Проблема ImportExport с новым деструктором адаптера изображения Varien Gd2 в версии 1.9.2.0


Может кто-нибудь объяснить, для чего используется следующий код, введенный между 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), но расширение их в соответствии с родительской логикой не помогает.

Author: Fabian Schmengler, 2015-08-24

4 answers

Похоже, что они пытались уничтожить ресурс изображения, но вместо этого допустили утечку памяти. Честно говоря, я не могу придумать веской причины для этого кода, но я могу объяснить, что было изменено:

Первоначально imagedestroy() должен был быть вызван в дескрипторе __destruct()

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

Деструктор вызывается всякий раз, когда сборщик мусора PHP уничтожает неиспользуемые объекты (т. Е. объекты в памяти, на которые больше нет ссылок).

Теперь imagedestroy() вместо этого вызывается в функции выключения , и поскольку это обратный вызов метода объекта Varien_Image_Adapter_Gd2, он даже не может быть собран до самого конца. Таким образом, все ресурсы изображений остаются открытыми до завершения выполнения сценария.

 14
Author: Fabian Schmengler, 2015-08-24 08:40:21

У меня те же проблемы с моим 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 (или закомментировать)
  • измените имя функции уничтожить на __уничтожить

Я установил memory_limit обратно на 1G (ранее я увеличил его до 32 ГБ), и теперь он работает...

Этот проект реализует указанные процедура в дружественной для модмана манере. Просто установите его с помощью composer, и все готово.

 6
Author: dkr, 2018-08-14 12:18:16

Это было частью устранения проблем безопасности с помощью unserialize. Магические методы, такие как __destruct, имеют неотъемлемые проблемы с сериализацией.

Мы видели предложенные эксплойты, которые использовали сериализацию и __разрушение для создания файлов в файловой системе - и это изменение (вы увидите больше подобных изменений в других местах) было сделано, чтобы избежать этого.

Вызывает ли это утечку памяти или просто использует больше памяти, пока сценарий заканчивает?

Https://security.stackexchange.com/questions/77549/is-php-unserialize-exploitable-without-any-interesting-methods

 5
Author: Piotr Kaminski, 2017-03-17 13:14:44

Поэтому я действительно обнаружил ошибку в 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;
    }
}
 4
Author: David Manners, 2016-05-11 07:07:03