Edit report at https://bugs.php.net/bug.php?id=65581&edit=1
ID: 65581
Comment by: ivan dot enderlin at hoa-project dot net
Reported by: ivan dot enderlin at hoa-project dot net
Summary: stream_get_contents does not seek with a stream
wrapper
Status: Closed
Type: Bug
Package: *General Issues
PHP Version: master-Git-2013-08-29 (Git)
Assigned To: jpauli
Block user comment: N
Private report: N
New Comment:
Oh yes, I forgot that tell() returns 0 on success⦠That's solved my issue.
Thanks!
Previous Comments:
------------------------------------------------------------------------
[2013-08-29 13:31:55] [email protected]
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php
This is because your stream_seek() function does not return the right value.
stream_seek() should return TRUE if the seek has successed, you return the
value
of fseek(), which is 0 on success.
Additionally, you have to implement stream_tell() so that the underlying layer
can ask for it and know where the stream position is.
stream_tell() is called just after stream_seek() has successed, thus it is
needed, even if you never call ftell() on your own stream, the underlying layer
does.
Correct code is :
<?php
class StreamWrapper {
protected $_stream = null;
public function stream_open ( $path, $mode, $options, &$openedPath ) {
$this->_stream = fopen(__FILE__, $mode);
return true;
}
public function stream_seek ( $offset, $whence = SEEK_SET ) {
var_dump('seek to ' . $offset);
if (fseek($this->_stream, $offset, $whence) == 0) {
return true;
}
return false;
}
public function stream_tell()
{
return ftell($this->_stream);
}
public function stream_read ( $count ) {
return fread($this->_stream, $count);
}
public function stream_stat ( ) {
return fstat($this->_stream);
}
public function stream_eof ( ) {
return feof($this->_stream);
}
}
stream_wrapper_register('foo', 'StreamWrapper');
$a = fopen('foo://bar', 'rb');
var_dump(stream_get_contents($a, 30, 4));
------------------------------------------------------------------------
[2013-08-29 08:40:49] ivan dot enderlin at hoa-project dot net
Oh also the bug disappears with:
fseek($a, 4);
stream_get_contents($a, 30);
------------------------------------------------------------------------
[2013-08-29 08:28:08] ivan dot enderlin at hoa-project dot net
Description:
------------
When calling stream_get_contents() with $offset >= ftell() *through a stream
wrapper*, the internal pointer of the stream is moved but stream_get_contents()
throws an error: "Failed to seek to position $offset in the stream".
While monitoring the source code (ext/standard/streamsfuncs.c, at line 404, no
kidding ;-)), it appears that it is a normal behaviour since seek_res is set to
-1 at line 426 (with the code bellow). I did not understand why (I looked at
php_stream_seek implementation but I was not able to understand).
Change fopen('foo://bar', 'rb') for fopen(__FILE__, 'rb') and the issue
disappears. That's why I think it is related to stream wrapper, but I cannot
ensure that.
Test script:
---------------
<?php
class StreamWrapper {
protected $_stream = null;
public function stream_open ( $path, $mode, $options, &$openedPath ) {
$this->_stream = fopen(__FILE__, $mode);
return true;
}
public function stream_seek ( $offset, $whence = SEEK_SET ) {
var_dump('seek to ' . $offset);
return fseek($this->_stream, $offset, $whence);
}
public function stream_read ( $count ) {
return fread($this->_stream, $count);
}
public function stream_stat ( ) {
return fstat($this->_stream);
}
public function stream_eof ( ) {
return feof($this->_stream);
}
}
stream_wrapper_register('foo', 'StreamWrapper');
$a = fopen('foo://bar', 'rb');
var_dump(stream_get_contents($a, 30, 4));
Expected result:
----------------
no error
Actual result:
--------------
error
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=65581&edit=1