ปัญหาการนำเข้าส่งออกด้วยตัวทำลายใหม่ของ Varien_Image_Adapter_Gd2 ใน 1.9.2.0


23

มีใครบ้างที่สามารถอธิบายได้ว่าใช้รหัสใดต่อไปนี้ระหว่าง Magento CE 1.9.1.0 และ 1.9.2.0

class Varien_Image_Adapter_Gd2:

public function __construct()
{
    // Initialize shutdown function
    register_shutdown_function(array($this, 'destruct'));
}

/**
 * Destroy object image on shutdown
 */
public function destruct()
{
    @imagedestroy($this->_imageHandler);
}

หลังจากเพิ่มฟังก์ชั่นทั้งสองนี้แล้วการนำเข้าภาพแกลเลอรีผลิตภัณฑ์ของเราที่มีส่วนต่อประสาน ImportExport หยุดทำงาน ข้อผิดพลาดเกิดจากการ จำกัด หน่วยความจำ (ซึ่งออกมาเป็นขีด จำกัด ขนาดไฟล์สูงสุดที่เปิด)

ความคิดของฉันคือไฟล์ที่เปิดโดยการนำเข้าจะไม่ถูกปิดอย่างถูกต้อง

ฉันยังเห็นด้วยว่ามีdestruct()ฟังก์ชั่นว่างเปล่าที่แนะนำ ( Mage_ImportExport_Model_Import_Adapter_Abstract) - แต่การขยายฟังก์ชันเหล่านั้นเพื่อให้ตรงกับตรรกะของผู้ปกครองก็ไม่ได้ช่วยอะไร

คำตอบ:


14

ดูเหมือนว่าพวกเขาพยายามที่จะทำลายทรัพยากรรูปภาพ แต่แนะนำหน่วยความจำรั่ว ฉันไม่สามารถคิดเหตุผลที่ถูกต้องสำหรับรหัสนี้เพื่อความซื่อสัตย์ แต่ฉันสามารถอธิบายสิ่งที่มีการเปลี่ยนแปลง:

ในขั้นต้นimagedestroy()จะได้รับการเรียกใน desctructor__destruct()

function __destruct()
{
    @imagedestroy($this->_imageHandler);
}

destructor ถูกเรียกเมื่อใดก็ตามที่ตัวรวบรวมขยะ PHP ทำลายวัตถุที่ไม่ได้ใช้ (เช่นวัตถุในหน่วยความจำที่ไม่ได้อ้างอิงอีกต่อไป)

ตอนนี้imagedestroy()ถูกเรียกแทนในฟังก์ชั่นปิดเครื่องและเนื่องจากนี่เป็นการเรียกกลับไปยังวิธีการของVarien_Image_Adapter_Gd2วัตถุจึงไม่สามารถแม้แต่จะเก็บขยะจนกว่าจะถึงจุดสิ้นสุด วิธีนี้แหล่งข้อมูลรูปภาพทั้งหมดจะยังคงเปิดอยู่จนกว่าสคริปต์จะเสร็จสิ้น


ขอบคุณสำหรับคำอธิบาย - นี่คือสิ่งที่ฉันคิด โดยรวมแล้วรหัสแนะนำนี้ทำให้การนำเข้าส่วนใหญ่ไร้ประโยชน์ใน 1.9.2 ในสายตาของฉัน. หวังว่าจะได้รับการแก้ไขในไม่ช้า มีคำแนะนำใดให้เปิดรายงานข้อผิดพลาด
Achim Rosenhagen

6

มีปัญหาเดียวกันกับ Magento 1.9.2.0 ของฉัน ...

ฉันได้รับสิ่งนี้ในการทำงานโดยการเปลี่ยนVarien_Image_Adapter_Gd2ใน/lib/Varien/Image/Adapter/Gd2.phpดังนี้

public function __construct()
{
    // Initialize shutdown function
    // register_shutdown_function(array($this, 'destruct'));
}

/**
 * Destroy object image on shutdown
 */
public function __destruct()
{
    @imagedestroy($this->_imageHandler);
}
  • ลบบรรทัดด้วยregister_shutdown_function (หรือใส่ความคิดเห็น)
  • เปลี่ยนชื่อฟังก์ชันdestructเป็น__destruct

ฉันได้ตั้งค่า memory_limit กลับเป็น 1G (ก่อนหน้านี้ฉันเพิ่มสูงถึง 32GB) และตอนนี้มันใช้งานได้ ...

โครงการนี้ใช้ขั้นตอนการพูดอย่างเป็นมิตรกับ modman เพียงติดตั้งกับผู้แต่งและคุณก็พร้อมที่จะไป


นี่ไม่ได้ตอบคำถามจริงๆ หากคุณมีคำถามที่แตกต่างที่คุณสามารถถามได้โดยคลิกที่ถามคำถาม นอกจากนี้คุณยังสามารถเพิ่มเงินรางวัลเพื่อดึงดูดความสนใจมากขึ้นกับคำถามนี้เมื่อคุณมีเพียงพอชื่อเสียง
Rajeev K Tomy

ใช่สิ่งนี้ไม่ได้ตอบคำถาม แต่จะช่วยให้ผู้ที่ต้องการทางออกชั่วคราวและไม่มีการสนทนา
dkr

แก้ไขปัญหาเกี่ยวกับการใช้หน่วยความจำในระหว่างการนำเข้า ที่น่าสนใจวีโอไอพีจะทดสอบสิ่งที่ปล่อยออกมาหรือไม่?
klipach

วิธีนี้ไม่เพียง แต่แก้ปัญหาการนำเข้าเท่านั้น วิธีนี้ช่วยแก้ปัญหาการกินหน่วยความจำขนาดใหญ่โดยกระบวนการที่สร้าง / สร้างแคชใหม่และปรับขนาดรุ่นสำหรับภาพผลิตภัณฑ์ทุกชิ้น หากฉันอัปโหลดภาพ png ในผลิตภัณฑ์ของฉันหากไม่มี "แฮ็ค" นี้ฉันไม่สามารถใช้งานได้และฉันได้รับข้อผิดพลาดหน่วยความจำจำนวนมาก
Simbus82

วันนี้ฉันพบข้อเสนอแนะนี้ ฉันนำไปใช้และการรั่วไหลของหน่วยความจำหายไป จากนั้นฉันก็สร้างgithub.com/borasocom-team/magento-gd2-memoryleakนี้เพื่อติดตั้งอย่างสะอาด
ดร. Gianluigi Zane Zanettini

5

มันเป็นส่วนหนึ่งของการแก้ไขปัญหาความปลอดภัยด้วย unserialize วิธีการที่มหัศจรรย์เช่น __ การทำลายโครงสร้างมีปัญหาโดยธรรมชาติเกี่ยวกับการทำให้เป็นอนุกรม

เราได้เห็นการหาประโยชน์ที่เสนอซึ่งใช้การทำให้เป็นอนุกรมและ __ การทำลายโครงสร้างเพื่อสร้างไฟล์ในระบบไฟล์ - และการเปลี่ยนแปลงนี้ (คุณจะเห็นการเปลี่ยนแปลงที่คล้ายกันมากขึ้นในที่อื่น ๆ ) ได้ทำเพื่อหลีกเลี่ยงปัญหานี้

มันทำให้หน่วยความจำรั่วหรือเพียงแค่ใช้หน่วยความจำเพิ่มเติมจนกว่าสคริปต์จะเสร็จสิ้น?

/security/77549/is-php-unserialize-exploitable-without-any-interesting-methods


ขอบคุณสำหรับบริบท มีการเปลี่ยนแปลงนี้เพื่อป้องกันการหาประโยชน์โดยเฉพาะหรือเพื่อให้แน่ใจหรือไม่?
เฟเบียน Schmengler

และไม่มันอาจทำให้สคริปต์ใช้หน่วยความจำมากขึ้นไม่ใช่การรั่วไหลของหน่วยความจำจริง
Fabian Schmengler

มันทำให้เกิดการรั่วไหลของหน่วยความจำขนาดใหญ่โดยเฉพาะอย่างยิ่งเมื่อนำเข้ารูปภาพเพราะมันจะเปิดไฟล์ภาพทั้งหมดจนกว่าจะสิ้นสุดกระบวนการนำเข้า วิธีนี้เราสามารถนำเข้าผลิตภัณฑ์ได้ประมาณ 50 รายการเท่านั้น (ก่อนที่เราจะสามารถนำเข้า> 2k ดูเหมือนจะไม่มีอะไร) ฉันทำการทดสอบบน VM ท้องถิ่นด้วย RAM 8G และไฟล์ต้นฉบับทั้งหมดประมาณ 300KB ก่อนที่จะเปลี่ยนหน่วยความจำที่ใช้โดย PHP rermains ที่ 1k ระหว่างการนำเข้าทั้งหมด
Achim Rosenhagen

fschmengler ถูกต้อง - มันอาจจะไม่ใช่ 'การรั่วไหลของหน่วยความจำ' แต่การบริโภคพุ่งขึ้นไปตามเนินเขา ;-)
Achim Rosenhagen

1
@ Alex ขอบคุณสำหรับคำแนะนำ ฉันย้อนกลับ patched มัน ตอนนี้การรั่วไหลของหน่วยความจำหายไป แต่ไม่มีวิธีแก้ปัญหาสำหรับอนาคต
Arne

4

ดังนั้นฉันจึงแจ้งข้อผิดพลาดกับ Magento รวมถึง "วิธีแก้ปัญหา" ที่ควรจัดการกับปัญหาการใช้หน่วยความจำในกระบวนการนำเข้าภาพ

วิธีการแก้ปัญหาสามารถพบได้ใน github ภายใต้https://github.com/sitewards/import_image_memory_leak_fixแต่แนวคิดพื้นฐานคือ

การแก้ไขMage_Catalog_Helper_Image::validateUploadFileเพื่อเรียกdestructวิธีการในโปรเซสเซอร์ภาพ น่าเศร้าที่ดูเหมือนว่าค่าเริ่มต้นVarien_Imageไม่ได้จัดการกับdestructดังนั้นเราจึงต้องเพิ่มชั้นเรียนของเราเองที่ทำ

<?php
/**
 * @category    Sitewards
 * @package     Sitewards_ImportImageMemoryLeakFix
 * @copyright   Copyright (c) Sitewards GmbH (http://www.sitewards.com/)
 */
class Sitewards_ImportImageMemoryLeakFix_Model_Destructable_Image extends Varien_Image
{
    /**
     * Constructor,
     * difference from original constructor - we register a destructor here.
     *
     * @param string $sFileName
     * @param Varien_Image_Adapter $oAdapter Default value is GD2
     */
    public function __construct($sFileName = null, $oAdapter = Varien_Image_Adapter::ADAPTER_GD2)
    {
        parent::__construct($sFileName, $oAdapter);

        // Initialize shutdown function
        register_shutdown_function(array($this, 'destruct'));
    }

    /**
     * Destroy object image on shutdown
     */
    public function destruct()
    {
        $oAdapter = $this->_getAdapter();
        if (method_exists($oAdapter, 'destruct')) {
            $oAdapter->destruct();
        } else {
            Mage::log('Image can not be destructed properly, adapter doesn\'t support the method.');
        }
    }
}

จากนั้นจะมีการเขียนใหม่ของผู้ช่วย

<?xml version="1.0"?>
<config>
    <modules>
        <Sitewards_ImportImageMemoryLeakFix>
            <version>0.1.0</version>
        </Sitewards_ImportImageMemoryLeakFix>
    </modules>
    <global>
        <models>
            <sitewards_importimagememoryleakfix>
                <class>Sitewards_ImportImageMemoryLeakFix_Model</class>
            </sitewards_importimagememoryleakfix>
        </models>
        <helpers>
            <catalog>
                <rewrite>
                    <image>Sitewards_ImportImageMemoryLeakFix_Helper_Catalog_Helper_Image</image>
                </rewrite>
            </catalog>
        </helpers>
    </global>
</config>

และฟังก์ชั่นใหม่เรียกคลาสอิมเมจที่ทำลายได้ใหม่

<?php
/**
 * @category    Sitewards
 * @package     Sitewards_ImportImageMemoryLeakFix
 * @copyright   Copyright (c) Sitewards GmbH (http://www.sitewards.com/)
 */
class Sitewards_ImportImageMemoryLeakFix_Helper_Catalog_Helper_Image extends Mage_Catalog_Helper_Image
{
    /**
     * Check - is this file an image
     *
     * Difference from original method - we destroy the image object here,
     * i.e. we are not wasting memory, without that fix product import with images
     * easily goes over 4Gb on memory with just couple hundreds of products.
     *
     * @param string $sFilePath
     *
     * @return bool
     * @throws Mage_Core_Exception
     */
    public function validateUploadFile($sFilePath) {
        if (!getimagesize($sFilePath)) {
            Mage::throwException($this->__('Disallowed file type.'));
        }

        /** @var Sitewards_ImportImageMemoryLeakFix_Model_Destructable_Image $oImageProcessor */
        $oImageProcessor = Mage::getModel('sitewards_importimagememoryleakfix/destructable_image', $sFilePath);
        $sMimeType       = $oImageProcessor->getMimeType();
        $oImageProcessor->destruct();

        return $sMimeType !== null;
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.