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: 2020-08-17 13:01 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: cmb (profile)
Status: Not a bug Package: Streams related
PHP Version: 5.6.5 OS: Linux
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: 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

Pull Requests

Pull requests:

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.
 [2020-08-17 13:01 UTC] cmb@php.net
-Status: Open +Status: Not a bug -Assigned To: +Assigned To: cmb
 [2020-08-17 13:01 UTC] cmb@php.net
I think we can close this ticket as not-a-bug *now*, since it was
mostly about the BC break, and this is moot now.  Other than that,
php://temp behaves like php://memory now[1].

[1] <https://3v4l.org/E2JL2>
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 23:01:29 2024 UTC