php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #68948 feof() on temporary streams broken
Submitted: 2015-01-29 17:42 UTC Modified: 2015-02-09 19:53 UTC
Votes:17
Avg. Score:4.7 ± 0.6
Reproduced:15 of 15 (100.0%)
Same Version:12 (80.0%)
Same OS:12 (80.0%)
From: yunosh@php.net Assigned:
Status: Open Package: Streams related
PHP Version: 5.6.5 OS: Linux
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: yunosh@php.net
New email:
PHP Version: OS:

 

 [2015-01-29 17:42 UTC] yunosh@php.net
Description:
------------
feof() doesn't work properly on temporary streams.

Test script:
---------------
$stream = fopen("php://temp", "r+");
fwrite($stream, "0123456789");
rewind($stream);
var_dump(fread($stream, 10), ftell($stream), feof($stream));

Expected result:
----------------
string(10) "0123456789"
int(10)
bool(true)


Actual result:
--------------
string(10) "0123456789"
int(10)
bool(false)


Patches

Add a Patch

Pull Requests

Pull requests:

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-01-29 19:15 UTC] php at mcq8 dot be
This is due to https://github.com/php/php-src/pull/936
You only get an EOF when you tried to read more than there is data.
This is the same behaviour as reading from a file.
 [2015-01-29 20:02 UTC] yunosh@php.net
It still happens if reading 11 bytes. And even with 10 bytes, this would be BC break against PHP 5.
 [2015-02-07 13:08 UTC] sjaillet at gmail dot com
It's definitely a bug introduced recently.

Indeed with:

$stream = fopen("php://temp", "r+");
fwrite($stream, "0123456789");
rewind($stream);
var_dump(fread($stream, 1024), ftell($stream), feof($stream));

The output for 5.5.20, 5.6.4, php7@20141201, HHVM 3.5.0 is:

string(10) "0123456789"
int(10)
bool(true)

And now with 5.5.21, 5.6.5, php7@20150101 the output was:

string(10) "0123456789"
int(10)
bool(false)
 [2015-02-09 19:53 UTC] yunosh@php.net
-PHP Version: master-Git-2015-01-29 (Git) +PHP Version: 5.6.5
 [2015-02-09 19:53 UTC] yunosh@php.net
Changing version because this is a major regression in the latest stable 5.5 and 5.6 releases too.
 [2015-02-09 20:35 UTC] slusarz at horde dot org
The previous way of handling EOFs in memory streams was entirely compatible with the fread() documentation -- http://php.net/manual/en/function.fread.php -- which clearly states (emphasis mine):

"When reading from **anything that is not a regular local file** ... reading will stop after a packet is available. This means that you should collect the data together in chunks.... (Example loops through fread() to build a string; it doesn't rely on feof() to return true immediately when the end of string is reached.)"

In other words, this can be stated as: "When reading from a memory stream, which is NOT a regular local file, it cannot be guaranteed that at the end of any fread() operation that EOF has been reached."

Any code that requires feof() to return true in a in-memory stream immediately after a non-empty fread() return is broken, since this is non-guaranteed behavior.  Thus, this fix must be reverted as it is a backward incompatible change.  the base64 filter (or filter code in general) is the problematic code and is what needs to be fixed.
 [2015-02-11 14:40 UTC] adorman at ironicdesign dot com
Just to comment on how critical this bug is, it prevents horde/imp webmail from working and our users can not access their email.
 [2015-03-06 03:18 UTC] slusarz at horde dot org
Proof that this is backward breaking for 5.5 and 5.6 (not to mention, HHVM). See:

http://3v4l.org/YJRWQ

This is a **CRITICAL** regression from a poorly implemented patch.  This is preventing PHP upgrades on enterprise-level clients.  As explained in a previous ticket, the old behavior was NOT broken per the PHP documentation itself, so this behavior simply cannot change in the middle of point releases.

To try to speed up reverting this, I guess I will implement a patch and submit to github.
 [2015-03-09 03:32 UTC] slusarz at horde dot org
Realize that my previous comment re: documentation was not very clear at all (in fact, it reads both ways).

So to clarify, this is what I meant:

In other words, this can be stated as: "When reading from something NOT a regular local file, it cannot be guaranteed that at the end of any fread() operation that EOF has been reached.  However, when reading from a regular local file, EOF will be returned once the end of the data is reached."

Thus, feof() behaves differently depending on what the underlying stream is; there is no correct behavior for all streams - it is stream-dependent.

In memory streams are more analogous to a file than a network stream, because at any given point in time the in-memory stream has a physical length that is determinative.  Therefore, feof() should act on in-memory streams as it acts on files - returning true once all data has been read from the stream.
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Sun Sep 22 10:01:26 2019 UTC