phpfgetsfseekftell

the output of ftell in php function


Here is my code:

<?php
    $url="http://www.sina.com.cn";
    $handle = @fopen($url, "r");
    $len=get_headers($url,true);
    print_r($len);
    echo $len['Content-Length']."\n";
    if ($handle) {
        while (($buffer = fgets($handle,1024)) !== false) {
            echo ftell($handle)."\n";
            fseek($handle,200000,SEEK_CUR);
            echo ftell($handle)."\n";
        }
        if (!feof($handle)) {
            echo "Error: unexpected fgets() fail\n";
        }
        fclose($handle);
    }
?>

The result is as below:

    Array
(
    [0] => HTTP/1.1 200 OK
    [Content-Type] => text/html
    [Vary] => Accept-Encoding
    [X-Powered-By] => shci_v1.03
    [Server] => nginx
    [Date] => Thu, 24 Dec 2015 04:03:39 GMT
    [Last-Modified] => Thu, 24 Dec 2015 04:01:28 GMT
    [Expires] => Thu, 24 Dec 2015 04:04:39 GMT
    [Cache-Control] => max-age=60
    [Age] => 32
    [Content-Length] => 518264
    [X-Cache] => HIT from xidan33-99.sina.com.cn
    [Connection] => close
)
518264
16
200016
200058
400058
400065
518264

The Content-Length maybe not the same as mine--518264,it will be changed dynamically when you execute the code,it does no matter for the discussion. Why the result is not the following?

518264
1024
201024
202048
402048
403072

please explain the action of file pointer on fgets and ftell and fseek function .


Solution

  • As per the PHP documentation for fgets(),

    Reading ends when length - 1 bytes have been read, or a newline (which is included in the return value), or an EOF (whichever comes first).

    Here length is the 2nd parameter you have used when calling fgets(), which is 1024. So your call to fgets() will end reading when any of the following happens :

    1. It has read 1023 bytes from the same line.
    2. It has reached the end of current line.
    3. It has reached the end of file.

    So, in your case, when fgets() reads the first line it reached the end of the first line after reading 16 bytes, and that will be the position of the file pointer when called by ftell() next to it. ftell() returns the current position of the file pointer in the file.

    When you are in the next line calling the fgets()again (iterated by the while loop), your starting position in the file is now 16 (notably not 1024) and you can read upto (16 + 1024) 1040 bytes (not upto 2048). Again if your next line has only 42 bytes, this fgets() will end reading at 58 bytes, which will be the position of the file pointer when called by ftell() again.

    And again you are going to start next fgets() from 58 bytes, to read up to (58 + 1024 =) 1082 bytes. It will continue this way.

    Effect of fseek()
    fseek() is used to move the file pointer to a specific position in the file as set by the $offset (2nd paramater). According to the PHP documentation for fseek(), the 3rd parameter values can be -

    SEEK_SET - Set position equal to offset bytes.
    SEEK_CUR - Set position to current location plus offset.
    SEEK_END - Set position to end-of-file plus offset.

    So, by fseek($handle,200000,SEEK_CUR); you are setting the file pointer to be at 200000 + the current position. For example, it will move to 200016 when it was in 16.