php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #78406 Broken file includes with user-defined stream filters
Submitted: 2019-08-12 17:03 UTC Modified: 2019-08-13 08:16 UTC
From: lisachenko dot it at gmail dot com Assigned:
Status: Closed Package: Streams related
PHP Version: 7.4.0beta2 OS: Windows x64
Private report: No CVE-ID: None
 [2019-08-12 17:03 UTC] lisachenko dot it at gmail dot com
Description:
------------
Go! AOP framework heavily uses PHP file includes with applied stream filters like that:

include 'php://filter/read=sample.filter/resource=/some/path/to/php/file

In the latest version this inclusion with applied filter logic can result in a parse error like this:

Parse error: syntax error, unexpected end of file

Test script:
---------------
<?php

echo 'bug'; // Should be transformed by filter on second include

if (!class_exists(SampleFilter::class)) {
    class SampleFilter extends php_user_filter
    {
        private $data = '';

        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);

                $this->data = str_replace('bug', 'feature', $this->data);

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

                return PSFS_PASS_ON;
            }

            return PSFS_FEED_ME;
        }
    }
    stream_filter_register('sample.filter', SampleFilter::class);
    $uri = 'php://filter/read=sample.filter/resource='. __FILE__;

    $content = file_get_contents($uri);
    echo '<pre>', htmlentities($content), '</pre>'; // Looks good

    include $uri; // We expect one more "feature" output at line 3
}




Expected result:
----------------
bug

<?php

echo 'feature'; // Should be transformed by filter on second include

if (!class_exists(SampleFilter::class)) {
    class SampleFilter extends php_user_filter
    {
        private $data = '';

        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);

                $this->data = str_replace('feature', 'feature', $this->data);

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

                return PSFS_PASS_ON;
            }

            return PSFS_FEED_ME;
        }
    }
    stream_filter_register('sample.filter', SampleFilter::class);
    $uri = 'php://filter/read=sample.filter/resource='. __FILE__;

    $content = file_get_contents($uri);
    echo '<pre>', htmlentities($content), '</pre>'; // Looks good

    include $uri; // We expect one more "feature" output at line 3
}


feature

Actual result:
--------------
bug

<?php

echo 'feature'; // Should be transformed by filter on second include

if (!class_exists(SampleFilter::class)) {
    class SampleFilter extends php_user_filter
    {
        private $data = '';

        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);

                $this->data = str_replace('feature', 'feature', $this->data);

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

                return PSFS_PASS_ON;
            }

            return PSFS_FEED_ME;
        }
    }
    stream_filter_register('sample.filter', SampleFilter::class);
    $uri = 'php://filter/read=sample.filter/resource='. __FILE__;

    $content = file_get_contents($uri);
    echo '<pre>', htmlentities($content), '</pre>'; // Looks good

    include $uri; // We expect one more "feature" output at line 3
}



Parse error: syntax error, unexpected end of file in H:\Work\go\demos\stream.php on line 38

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-08-12 17:08 UTC] lisachenko dot it at gmail dot com
Reproduced example: https://3v4l.org/jEMEE
 [2019-08-13 08:16 UTC] cmb@php.net
-Status: Open +Status: Verified
 [2019-08-13 08:16 UTC] cmb@php.net
This behavioral change has been introduced with commit c2c5c9a[1].

[1] <http://git.php.net/?p=php-src.git;a=commit;h=c2c5c9a973559b7ba9f84337c5f8078e59e98a91>
 [2019-08-13 08:23 UTC] nikic@php.net
Automatic comment on behalf of nikita.ppv@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=b01824e596dd11d075d1f2c9af364d2fdabc4d17
Log: Fixed bug #78406
 [2019-08-13 08:23 UTC] nikic@php.net
-Status: Verified +Status: Closed
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Mon Dec 09 05:01:26 2019 UTC