4

Magento WTF: memory limit check in Gd2 image adapter

 2 years ago
source link: http://mmenozzi.github.io/2015/07/30/magento-wtf-memory-limit-check-in-gd2-image-adapter/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Magento WTF: memory limit check in Gd2 image adapter

A few days ago I was coding on a catalog images import component in Magento. The import component is based on AvS_FastSimpleImport and invoked through a Magento’s shell script. As you may know, AvS_FastSimpleImport is a wrapper for Magento’s native Import/Export so using it will cause to use Magento core classes.

When the work was done I launched the import shell script with some test images in the media/import directory and I got the following error:

Uncaught exception 'Varien_Exception' with message 'Memory limit has been reached.'

My first thought was: “Uhm… That’s weird… My shell script sets memory_limit to -1 (which means no limit)”.

In fact, usually, my import shell script overrides the _applyPhpVariables method and forces memory_limit and max_execution_time to fit long/expensive execution needs:

// class MyShellScript extends Mage_Shell_Abstract

protected function _applyPhpVariables()
{
    parent::_applyPhpVariables();
    @ini_set('memory_limit', '-1');
    @ini_set('max_execution_time', '36000');
}

So, I searched for the exception and I found that during the image import Magento calls the following method for every image to import:

/**
 * Opens image file.
 *
 * @param string $filename
 * @throws Varien_Exception
 */
public function open($filename)
{
    $this->_fileName = $filename;
    $this->getMimeType();
    $this->_getFileAttributes();
    if ($this->_isMemoryLimitReached()) {
        throw new Varien_Exception('Memory limit has been reached.');
    }
    $this->_imageHandler = call_user_func($this->_getCallback('create'), $this->_fileName);
}

This code is in the class Varien_Image_Adapter_Gd2. Let’s look at the implementation of method _isMemoryLimitReached:

/**
 * Checks whether memory limit is reached.
 *
 * @return bool
 */
protected function _isMemoryLimitReached()
{
    $limit = $this->_convertToByte(ini_get('memory_limit'));
    $size = getimagesize($this->_fileName);
    $requiredMemory = $size[0] * $size[1] * 3;
    return (memory_get_usage(true) + $requiredMemory) > $limit;
}

What the F**k!?!?! Note that, as said above memory_limit is -1 so ini_get('memory_limit') converted to byte will be -1 so every memory usage value will always be greater than -1.

Conclusion: Magento’s image import will always fail if invoked with unlimited memory (which makes sense in a CLI shell script).

To solve the problem I replaced the @ini_set('memory_limit', '-1') with @ini_set('memory_limit', '512M'). It would have been enough to simply remove @ini_set('memory_limit', '-1') because the parent _applyPhpVariables applies the memory_limit found in the .htaccess file but I don’t want that memory limit of a PHP shell script is controlled by a configuration file for Apache.

Pay also attention that the suffix G can’t be used in memory_limit to indicate gigabytes. This is because the method _convertToByte of that class is implemented as follows:

/**
 * Converts memory value (e.g. 64M, 129KB) to bytes.
 * Case insensitive value might be used.
 *
 * @param string $memoryValue
 * @return int
 */
protected function _convertToByte($memoryValue)
{
    if (stripos($memoryValue, 'M') !== false) {
        return (int)$memoryValue * 1024 * 1024;
    } elseif (stripos($memoryValue, 'KB') !== false) {
        return (int)$memoryValue * 1024;
    }
    return (int)$memoryValue;
}

As you can see the G suffix it’s not taken into consideration.


Posted with : Magento, What The F..k Moment



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK