0

This seems like it should be a simple thing to do but I'm having a bit of trouble with fgetc() when returning the last line of a open file handle. what I'm trying to do is return the last line written to the handle, I have the following which works if the handle has only one line:

function getLastLineFromHandle($handle)
{

    $seeker = function($handle) use (&$seeker) {

        fseek($handle, -1, SEEK_CUR);

        return ftell($handle) ?
            $seeker($handle) :
            $handle;
    };

    return trim(fgets($seeker($handle)));
}

$handle = fopen('php://temp', 'w+');
fwrite($handle, 'Hello World'.PHP_EOL);

//prints Hello World
print getLastLineFromHandle($handle);

The problem is when I have multiple lines written to the handle, adding an fgetc() to the check condition doesn't seems to work for example:

function getLastLineFromHandle($handle)
{

    $seeker = function($handle) use (&$seeker) {

        fseek($handle, -1, SEEK_CUR);

        return ftell($handle) && fgetc($handle) != PHP_EOL ?
            $seeker($handle) :
            $handle;
    };

    return trim(fgets($seeker($handle)));
}

This returns blank if multiple lines are written to the handle and fgetc($handle) seems to return the same character each time?

I'm sure there is something very simple that I've missed, but any pointers would be great as this is driving me crazy!

Thanks.

tomo661
  • 88
  • 4
  • refer this link, http://stackoverflow.com/questions/1062716/php-returning-the-last-line-in-a-file – Ayyanar G Mar 20 '15 at 12:19
  • Would you be able to fseek to the end of the file and read the contents backwards until the line break?. If so, then you've just to strrev the results :). – The Marlboro Man Mar 20 '15 at 12:22
  • @AyyanarG thanks but this doesn't really sort it as I'm look to solve without an outside call, plus the handle is in memory & not written to the file system. – tomo661 Mar 20 '15 at 13:38
  • @TheMarlboroMan sounds interesting will give this a try and report back, thanks! – tomo661 Mar 20 '15 at 13:43

1 Answers1

0

Found what was missing from example above, turns out it was case of there being an unexpected end of line char at the pointer at start so moving one position in solves the issue, for example:

function getLastLineFromHandle($handle)
{
    $seeker = function($handle) use (&$seeker) {
        fseek($handle, -2, SEEK_CUR);

        return ftell($handle) && fgetc($handle) != PHP_EOL ?
            $seeker($handle) :
            $handle;
    };

    return trim(fgets($seeker($handle)));
}

While exploring this I also found another way of doing the same thing, thanks to @TheMarlboroMan's comment about seeking to the end which sparked this:

function getLastLineFromHandle($handle)
{
    $seeker = function($handle, $cur = -2, $line = '') use (&$seeker)
    {
        $char = '';
        if (fseek($handle, $cur, SEEK_END) != -1) {
            $char = fgetc($handle);
            $line = $char.$line;
        }

        return ftell($handle) > 0 && $char != PHP_EOL?
            $seeker($handle, $cur-1,$line) :
            $line;
    };

    return trim($seeker($handle));
}

This hasn't been through a refactor loop, however it passes the same tests as the other method above. This solution seems to be a bit messy to return the line string instead of the file handle as that is what you would expect back.

Setting this as solved but open for comments if anyone has a different way :)

tomo661
  • 88
  • 4