|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #72561 5.2.2 regressed with incorrect seeking in stream wrappers
Submitted: 2016-07-08 01:33 UTC Modified: 2020-09-08 11:34 UTC
Avg. Score:3.0 ± 0.0
Reproduced:0 of 0 (0.0%)
From: nazar at mokrynskyi dot com Assigned:
Status: Verified Package: Streams related
PHP Version: 7.1.0alpha1 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 this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Bug Type:
From: nazar at mokrynskyi dot com
New email:
PHP Version: OS:


 [2016-07-08 01:33 UTC] nazar at mokrynskyi dot com
When doing reading/seeking on stream wrapper, PHP does interesting magic under the hood (for instance, reading 3 bytes results in 8192 bytes actually tried to be read in ::stream_read()).
This is all fine until it works as expected.

Here is demo:

PHP 5.1.4 - 5.2.1 have expected correct output.

hhvm-3.9.1 - 3.12.0 seems to also have optimizations under the hood, but result is correct anyway.

PHP 5.2.2+ (including latest 7.1.0-alpha2) regressed and does incorrect seeking which results in wrong position eventually.

I believe this should be fixed and backported to stable versions, since I do not see any good workaround here, input in ::stream_seek() is already incorrect.


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2016-07-08 08:16 UTC]
-Status: Open +Status: Verified -Package: Filesystem function related +Package: Streams related
 [2016-07-08 08:16 UTC]
There's some weird magic going on, alright.

1. stream_read gets called with the full 8192, implying PHP is automatically buffering the stream. This could be intentional (probably is) and may simply be an issue of documentation, but as a developer I would prefer PHP didn't do that for me. And I'll bet that 99% of stream wrapper code out there expects the method to be called with the specific length instead of the maximum length.

2. stream_tell is not being called. At all. The docs say it should be called when using fseek(), and one would expect it to be called with ftell() but apparently that's not the case, however it looks like PHP is managing the pointer position all by itself.

3. read 3 seek -1 results in ftell()=3 when it should be =2. Then later the read 2 results in ftell()=5 (should be =4). Seems that the relative seek isn't updating the internal pointer?

> I believe this should be fixed and backported to stable versions,
So we're clear, that would be 5.6.x, 7.0.y, and 7.1.z. Because 5.5 is dead and there's no way any changes would get into versions earlier than that.
 [2020-09-08 11:34 UTC]
I agree that this behavior is confusing at best, but it is
documented.  Stream reads are buffered by default, and fseek()
does not call ::stream_seek() if the target position is already
contained in the read buffer[1].

However, that behavior renders our streamwrapper example[2] moot,
since it relies on an internal position property like the supplied
reproduce scripts in this ticket.

[1] <>
[2] <>
PHP Copyright © 2001-2023 The PHP Group
All rights reserved.
Last updated: Wed May 31 16:03:37 2023 UTC