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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: lisachenko dot it at gmail dot com
New email:
PHP Version: OS:

 

 [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

Pull Requests

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-2024 The PHP Group
All rights reserved.
Last updated: Tue Dec 03 17:01:29 2024 UTC