php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #65581 stream_get_contents does not seek with a stream wrapper
Submitted: 2013-08-29 08:28 UTC Modified: 2013-08-29 13:41 UTC
From: ivan dot enderlin at hoa-project dot net Assigned: jpauli (profile)
Status: Not a bug Package: *General Issues
PHP Version: master-Git-2013-08-29 (Git) OS:
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: ivan dot enderlin at hoa-project dot net
New email:
PHP Version: OS:

 

 [2013-08-29 08:28 UTC] 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

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-08-29 08:40 UTC] 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 13:31 UTC] jpauli@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: jpauli
 [2013-08-29 13:31 UTC] jpauli@php.net
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 13:36 UTC] ivan dot enderlin at hoa-project dot net
Oh yes, I forgot that tell() returns 0 on success… That's solved my issue. Thanks!
 [2013-08-29 13:41 UTC] rasmus@php.net
-Status: Closed +Status: Not a bug
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Thu Jan 02 12:01:29 2025 UTC