tubalmartin / YUI-CSS-compressor-PHP-port

A PHP port of the YUI CSS compressor.
231 stars 34 forks source link

xception: Deprecated Functionality: preg_replace(): Passing null to parameter #3 ($subject) of type array|string #66

Open magento360 opened 11 months ago

magento360 commented 11 months ago

Magento ver. 2.4.4-p6 PHP 8.1.14 Bitbucket : wardenenv/php-fpm:8.1

When we run deploy command : php8.1 bin/magento setup:static-content:deploy

We are getting error :

`Compilation from source app/design/frontend/Vendor/demo/web/css/styles.css failed Exception: Deprecated Functionality: preg_replace(): Passing null to parameter #3 ($subject) of type array|string is deprecated in vendor/tubalmartin/cssmin/src/Minifier.php on line 330 in vendor/magento/framework/App/ErrorHandler.php:61 Stack trace:

0 [internal function]: Magento\Framework\App\ErrorHandler->handler()

1 vendor/tubalmartin/cssmin/src/Minifier.php(330): preg_replace()

2 vendor/tubalmartin/cssmin/src/Minifier.php(102): tubalmartin\CssMin\Minifier->minify()

3 vendor/magento/framework/Code/Minifier/Adapter/Css/CSSmin.php(58): tubalmartin\CssMin\Minifier->run()

4 vendor/magento/framework/View/Asset/PreProcessor/Minify.php(60): Magento\Framework\Code\Minifier\Adapter\Css\CSSmin->minify()

5 vendor/magento/framework/Interception/Interceptor.php(58): Magento\Framework\View\Asset\PreProcessor\Minify->process()

6 vendor/magento/framework/Interception/Interceptor.php(138): Magento\Framework\View\Asset\PreProcessor\Minify\Interceptor->___callParent()

7 vendor/magento/framework/Interception/Interceptor.php(153): Magento\Framework\View\Asset\PreProcessor\Minify\Interceptor->Magento\Framework\Interception{closure}()

8 generated/code/Magento/Framework/View/Asset/PreProcessor/Minify/Interceptor.php(23): Magento\Framework\View\Asset\PreProcessor\Minify\Interceptor->___callPlugins()

9 vendor/magento/framework/View/Asset/PreProcessor/Pool.php(77): Magento\Framework\View\Asset\PreProcessor\Minify\Interceptor->process()

10 vendor/magento/framework/View/Asset/Source.php(152): Magento\Framework\View\Asset\PreProcessor\Pool->process()

11 vendor/magento/framework/View/Asset/Source.php(105): Magento\Framework\View\Asset\Source->preProcess()

12 vendor/magento/framework/View/Asset/File.php(158): Magento\Framework\View\Asset\Source->getFile()

13 vendor/magento/framework/App/View/Asset/Publisher.php(74): Magento\Framework\View\Asset\File->getSourceFile()

14 vendor/magento/framework/App/View/Asset/Publisher.php(62): Magento\Framework\App\View\Asset\Publisher->publishAsset()

15 vendor/magento/framework/Interception/Interceptor.php(58): Magento\Framework\App\View\Asset\Publisher->publish()

16 vendor/magento/framework/Interception/Interceptor.php(138): Magento\Framework\App\View\Asset\Publisher\Interceptor->___callParent()

17 vendor/magento/framework/Interception/Interceptor.php(153): Magento\Framework\App\View\Asset\Publisher\Interceptor->Magento\Framework\Interception{closure}()

`

Same things are working fine with PHP 8.1.15 .

please review the issue and let me know how we can fix it.

tedsalmon commented 9 months ago

@magento360

In my case, I was hitting PREG_JIT_STACK_LIMIT_ERROR. Add a call to preg_last_error() after the method call on line 330 to check if you have the same problem.

nahall commented 9 months ago

68 fixes this

tedsalmon commented 9 months ago

68 fixes this

I appreciate your willingness to fix this, but $css shouldn't be null to begin with. It's only null because of the aforementioned PREG stack limit error.

nahall commented 9 months ago

Where were you hitting it? I checked for an error after line 330 and in my case there was no PREG stack limit error there.

tedsalmon commented 9 months ago

Where were you hitting it? I checked for an error after line 330 and in my case there was no PREG stack limit error there.

On line 328.

Weird; preg_last_error() shouldn't be null if $css is null as it indicates a regex evaluation failure. preg_replace_callback() should return the altered input string, never null.

nahall commented 9 months ago

You are right. Mine is hitting here:

    $css = preg_replace_callback(
        '/(?:"(?:[^\\\\"]|\\\\.|\\\\)*")|'."(?:'(?:[^\\\\']|\\\\.|\\\\)*')/S",
        array($this, 'processStringsCallback'),
        $css
    );

It seems like this regexp may need to be rewritten as it can quickly exhaust the backtrack limit depending on the input string. But looking at the outstanding bugs and pull requests I'm not sure if this project has been abandoned or not?

tedsalmon commented 9 months ago

You are right. Mine is hitting here:

    $css = preg_replace_callback(
        '/(?:"(?:[^\\\\"]|\\\\.|\\\\)*")|'."(?:'(?:[^\\\\']|\\\\.|\\\\)*')/S",
        array($this, 'processStringsCallback'),
        $css
    );

It seems like this regexp may need to be rewritten as it can quickly exhaust the backtrack limit depending on the input string. But looking at the outstanding bugs and pull requests I'm not sure if this project has been abandoned or not?

That's the same conclusion I came to. Even breaking the regex apart into two parts doesn't resolve the fact that it's exhausting the stack frame limit.

I did alter the regex to get it working, but it no longer worked as expected. I ended up switching to matthiasmullie/minify.

nahall commented 9 months ago

In my case this package is a dependency of Magento so I'll open a bug with them as they will need to decide whether to address it in this package or switch to a different library. Thanks for the heads up.

tedsalmon commented 9 months ago

In my case this package is a dependency of Magento so I'll open a bug with them as they will need to decide whether to address it in this package or switch to a different library. Thanks for the heads up.

My use case was also Magento. Here's how I replaced this library:

composer require matthiasmullie/minify

app/code/Custom/Package/etc/di.xml:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="cssMinificationAdapter" type="Custom\Package\Code\Minifier\Adapter\Css\CSSmin" />
</config>

app/code/Custom/Package/Code/Minifier/Adapter/Css/CSSmin.php:

<?php
namespace Custom\Package\Code\Minifier\Adapter\Css;

use MatthiasMullie\Minify\CSS as CssMinLibrary;
use Magento\Framework\Code\Minifier\AdapterInterface;

/**
 * Adapter for CSSmin library
 */
class CSSmin implements AdapterInterface
{
    /**
     * 'pcre.recursion_limit' value for CSSMin minification
     */
    const PCRE_RECURSION_LIMIT = 1000;

    /**
     * Minify css file content
     *
     * @param string $content
     * @return string
     */
    public function minify($content)
    {
        $pcreRecursionLimit = ini_get('pcre.recursion_limit');
        ini_set('pcre.recursion_limit', self::PCRE_RECURSION_LIMIT);
        $cssMinifier = new CssMinLibrary();
        $result = $cssMinifier->add($content)->minify();
        ini_set('pcre.recursion_limit', $pcreRecursionLimit);
        return $result;
    }
}

-Ted