Search code examples
phpgoaopphp-7.4

What happened to include / stream filters in PHP 7.4


Go! AOP framework was using stream filters with include statement in order to perform proxies generation. It worked well in PHP 7.3, but now after PHP 7.4 beta 2 release it looks like something has changed.

Unfortunately stream filters have poor documentation, so I could not check what is going one. Maybe someone more experienced would know.

Check following sample code:

// index.php

include __DIR__ . '/SampleFilter.php';
SampleFilter::register();

$uri = 'php://filter/read=sample.filter/resource='. __DIR__ . '/Sample.php';

$content = file_get_contents($uri);

include $uri;
Sample::printIt();
// SampleFilter.php

class SampleFilter extends php_user_filter
{
    public const PHP_FILTER_READ = 'php://filter/read=';
    public const FILTER_IDENTIFIER = 'sample.filter';

    protected $data = '';
    protected static $filterId;

    public static function register(string $filterId = self::FILTER_IDENTIFIER) : void
    {
        if (!empty(self::$filterId)) 
        {
            throw new RuntimeException('Stream filter already registered');
        }

        $result = stream_filter_register($filterId, __CLASS__);
        if ($result === false)
        {
            throw new Exception('Stream filter was not registered');
        }

        self::$filterId = $filterId;
    }

    public static function getId() : string
    {
        if (empty(self::$filterId))
        {
            throw new Exception('Stream filter was not registered');
        }

        return self::$filterId;
    }

    public function filter($in, $out, &$consumed, $closing)
    {
        while ($bucket = stream_bucket_make_writeable($in))
        {
            $this->data .= $bucket->data;
        }

        if ($closing || feof($this->stream))
        {
            $consumed = strlen($this->data);

            echo '<h2>Before</h2><pre>'. htmlentities($this->data) .'</pre>';
            $this->data = str_replace('text', 'text!!!!!!!!', $this->data);
            echo '<h2>After</h2><pre>'. htmlentities($this->data) .'</pre>';

            $bucket = stream_bucket_new($this->stream, $this->data);
            stream_bucket_append($out, $bucket);

            return PSFS_PASS_ON;
        }

        return PSFS_FEED_ME;
    }

}
// Sample.php

class Sample
{

    public static function printIt()
    {
        echo 'text';
    }

}

As you can see $content has properly modified code (full). But while include'ing that file it looks like code is striped to original file length. PHP prints error: Parse error: syntax error, unexpected end of file in /(...)/Sample.php on line 9

Line 9 is where it exceeds original file size.


Solution

  • This was a bug, introduced in the PHP7.4. It have been already fixed in the latest version.