pronto.ee

Tomorrow will be cancelled due to lack of interest

Magento: SUPEE-10752 v1 breaks Zend_Filter_PregReplace

There’s a chance that after installing SUPEE-10752v1 you might run into following error message:

Warning: substr() expects parameter 1 to be string, array given in /magento_root/app/code/core/Zend/Filter/PregReplace.php on line 173


This file was introduced as a part of SUPEE-10752v1 patch and it adds some deprecation modifier checks:

    /**
     * Perform regexp replacement as filter
     *
     * @param  string $value
     * @return string
     */
    public function filter($value)
    {
        if ($this->_matchPattern == null) {
            #require_once 'Zend/Filter/Exception.php';
            throw new Zend_Filter_Exception(get_class($this) . ' does not have a valid MatchPattern set.');
        }
        $firstDilimeter = substr($this->_matchPattern, 0, 1);
        $partsOfRegex = explode($firstDilimeter, $this->_matchPattern);
        $modifiers = array_pop($partsOfRegex);
        if ($modifiers != str_replace('e', '', $modifiers)) {
            throw new Zend_Filter_Exception(get_class($this) . ' uses deprecated modifier "/e".');
        }

        return preg_replace($this->_matchPattern, $this->_replacement, $value);
    }

It’s an override of lib/Zend/Filter/PregReplace.php and the original looks like this:

    /**
     * Perform regexp replacement as filter
     *
     * @param  string $value
     * @return string
     */
    public function filter($value)
    {
        if ($this->_matchPattern == null) {
            #require_once 'Zend/Filter/Exception.php';
            throw new Zend_Filter_Exception(get_class($this) . ' does not have a valid MatchPattern set.');
        }

        return preg_replace($this->_matchPattern, $this->_replacement, $value);
    }

As you can see, original method is indeed able to handle arrays while override is not. Objects such as lib/Zend/Filter/Word/CamelCaseToSeparator.php and lib/Zend/Filter/Word/SeparatorToCamelCase.php indeed use arrays for match patterns:

    public function filter($value)
    {
        if (self::isUnicodeSupportEnabled()) {
            parent::setMatchPattern(array('#(?<=(?:\p{Lu}))(\p{Lu}\p{Ll})#','#(?<=(?:\p{Ll}|\p{Nd}))(\p{Lu})#'));
            parent::setReplacement(array($this->_separator . '\1', $this->_separator . '\1'));
        } else {
            parent::setMatchPattern(array('#(?<=(?:[A-Z]))([A-Z]+)([A-Z][A-z])#', '#(?<=(?:[a-z0-9]))([A-Z])#'));
            parent::setReplacement(array('\1' . $this->_separator . '\2', $this->_separator . '\1'));
        }

        return parent::filter($value);
    }

While Magento itself does not use the things above some of the third party extension do, such as Ebizmarts_SagePaySuite (Zend_Filter_Word_CamelCaseToUnderscore extends Zend_Filter_Word_CamelCaseToSeparator), do. Here a sample code from app/code/local/Ebizmarts/SagePaySuite/Helper/Data.php:

    public function cameltounder($str)
    {
        $a = new Zend_Filter_Word_CamelCaseToUnderscore;

        return strtolower($a->filter($str));
    }

Solution:

Easiest way to solve this issue is to copy the file mentioned above (app/code/core/Zend/Filter/PregReplace.php) to app/code/local/Zend/Filter/PregReplace.php and replace the filter method with following:

    /**
     * Perform regexp replacement as filter
     *
     * @param string $value
     * @return string
     */
    public function filter($value)
    {
        if ($this->_matchPattern == null) {
            #require_once 'Zend/Filter/Exception.php';
            throw new Zend_Filter_Exception(get_class($this) . ' does not have a valid MatchPattern set.');
        }
        $patterns = array();
        if (is_array($this->_matchPattern)) {
            $patterns = $this->_matchPattern;
        } else {
            $patterns[] = $this->_matchPattern;
        }
        foreach($patterns as $pattern) {
            $firstDilimeter = substr($pattern, 0, 1);
            $partsOfRegex = explode($firstDilimeter, $pattern);
            $modifiers = array_pop($partsOfRegex);
            if ($modifiers != str_replace('e', '', $modifiers)) {
                throw new Zend_Filter_Exception(get_class($this) . ' uses deprecated modifier "/e".');
            }
        }
        return preg_replace($this->_matchPattern, $this->_replacement, $value);
}

I guess eventually there will be SUPEE-10752v2 which hopefully fixes this problem. Make sure to check/remove the local override when you install it.

PS. Everything above applies to Magento OS v1.9.3.9 as well.

Post a comment