1

I am experimenting with some php file / stream functionality. And i am having troubles with fread.

This data is send to a php script:

    baz=bomb&foo=bar&baz=bomb&foo=bar&foo=bar&baz=bomb

And that script runs this code:

    <php
    $fp = fopen("php://input", "rb");
    fseek($fp, 3, SEEK_SET);
    echo "<br>ftell: ".ftell($fp)."<br>";
    echo "<br>fread(resource, 4): ".fread($fp, 4)."<br>";
    fclose($fp);

The output shows:

    ftell: 3
    fread(resource, 4): baz=

What i am expecting that it shows is:

    =bom

Why does it seem like fread sets the pointer to the beginning of the stream first and then reads? What is the point of seeking trough a stream and not being able to read from a certain position?

The php version i am using is: 7.0.8 on a windows machine.

ITGuy1990
  • 93
  • 1
  • 9
  • Just wondering why not `$_POST` or `parse_str()`? – AbraCadaver Sep 22 '16 at 21:00
  • I am preparing to implement php-fig psr-7 streaminterface myself. That as a part of learning to build modern php framework. – ITGuy1990 Sep 22 '16 at 21:04
  • Are you sure whatever is streaming the data to php isn't adding data to the beginning? What happens when you use a different offset to `fseek()`? – Starson Hochschild Sep 22 '16 at 21:13
  • I am sure nothing is adding to the beginning. When i change the offset of fseek to 5 for example, the same "baz=" output appears. While ftell says 5. The post data is send by creating an streamcontext (http) and using that on a readfile function which calls the code above – ITGuy1990 Sep 22 '16 at 21:26
  • This explains it: http://stackoverflow.com/questions/3107624/why-can-php-input-be-read-more-than-once-despite-the-documentation-saying-othe `the underlying stream does not implement the seek handler` – Starson Hochschild Sep 22 '16 at 21:31
  • Apparently you can read it into the `php://memory` stream as this post suggests: http://stackoverflow.com/questions/35361763/php-input-can-only-be-read-once-in-php-5-6-16 – Starson Hochschild Sep 22 '16 at 21:33
  • Hmm ok. We could assume that that's true about the not implemented seek handler. But all that's being said there is for version 5.2.10. I am using 7. What would be the nicest way to read very big data from for example post or put requests without hogging the computers memory? The php://memory stream will put it in RAM memory and then it make's no sense anymore to give yourself a headache using streams inset of using $_POST? – ITGuy1990 Sep 22 '16 at 21:45
  • I assume the behavior has been carried over to 7 if you're seeing the same thing. Good question on large data. Other than writing to a `temp file` instead of `php://memory` and streaming that in, I don't have anything else off the top of my head and I need to go AFK. – Starson Hochschild Sep 22 '16 at 21:56
  • Thank you Starson Hochschild for your time. Appreciate it. Just tried the php://temp stream. It reads the first 2 MB (by default) into the RAM of your pc and the rest into a temporary file. Which is sufficient i guess. – ITGuy1990 Sep 22 '16 at 22:07

1 Answers1

1

This is the answer to the problem and i hope many will profit from this:

When using fseek, ftell seems to tell you where the pointer is in the stream. But it isn't. The pointer in the stream isn't moveable by the fseek function strange enough. This is, as Starson Hochschild pointed out because the underlying stream does not implement the seek handler.

So an alternative could be reading $_POST. But what about large content?

There is a stream called php://temp. The first two MB you put in it will go into the ram of your pc. More data will go into a temporary file on your pc.

So you could use that something like this:

    $tempStream = fopen("php://input", "rb");
    $stream = fopen("php://temp", "w+b");
    $size = 0;
    while (!feof($in)) $size += fwrite($stream,fread($tempStream,8192)); //Copy the php://input stream to the seekable php://temp stream. $size will contain the size in bytes of the $stream resource.
    fclose($tempStream);

    //Do your next fread's, fseek's, ftell's etc here on the $stream resource.

    fclose($stream);
ITGuy1990
  • 93
  • 1
  • 9