Проблема 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
), но расширение их в соответствии с родительской логикой не помогает.
4 answers
Похоже, что они пытались уничтожить ресурс изображения, но вместо этого допустили утечку памяти. Честно говоря, я не могу придумать веской причины для этого кода, но я могу объяснить, что было изменено:
Первоначально imagedestroy()
должен был быть вызван в дескрипторе __destruct()
function __destruct()
{
@imagedestroy($this->_imageHandler);
}
Деструктор вызывается всякий раз, когда сборщик мусора PHP уничтожает неиспользуемые объекты (т. Е. объекты в памяти, на которые больше нет ссылок).
Теперь imagedestroy()
вместо этого вызывается в функции выключения , и поскольку это обратный вызов метода объекта Varien_Image_Adapter_Gd2
, он даже не может быть собран до самого конца. Таким образом, все ресурсы изображений остаются открытыми до завершения выполнения сценария.
У меня те же проблемы с моим 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, и все готово.
Это было частью устранения проблем безопасности с помощью unserialize. Магические методы, такие как __destruct, имеют неотъемлемые проблемы с сериализацией.
Мы видели предложенные эксплойты, которые использовали сериализацию и __разрушение для создания файлов в файловой системе - и это изменение (вы увидите больше подобных изменений в других местах) было сделано, чтобы избежать этого.
Вызывает ли это утечку памяти или просто использует больше памяти, пока сценарий заканчивает?
Поэтому я действительно обнаружил ошибку в 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;
}
}