Question

I'm guessing it's fgets, but I can't find the specific syntax. I'm trying to read out (in a string I'm thinking is easier) the last line added to a log file.

Was it helpful?

Solution

The simplest naive solution is simply:

$file = "/path/to/file";
$data = file($file);
$line = $data[count($data)-1];

Though, this WILL load the whole file into memory. Possibly a problem (or not). A better solution is this:

$file = escapeshellarg($file); // for the security concious (should be everyone!)
$line = `tail -n 1 $file`;

OTHER TIPS

This looks like it is what you are looking for:

tekkie.flashbit.net: Tail functionality in PHP

It implements a function that uses fseek() with a negative index to roll up the file from the end. You can define how many lines you want to be returned.

The code also is available as a Gist on GitHub:

// full path to text file
define("TEXT_FILE", "/home/www/default-error.log");
// number of lines to read from the end of file
define("LINES_COUNT", 10);


function read_file($file, $lines) {
    //global $fsize;
    $handle = fopen($file, "r");
    $linecounter = $lines;
    $pos = -2;
    $beginning = false;
    $text = array();
    while ($linecounter > 0) {
        $t = " ";
        while ($t != "\n") {
            if(fseek($handle, $pos, SEEK_END) == -1) {
                $beginning = true; 
                break; 
            }
            $t = fgetc($handle);
            $pos --;
        }
        $linecounter --;
        if ($beginning) {
            rewind($handle);
        }
        $text[$lines-$linecounter-1] = fgets($handle);
        if ($beginning) break;
    }
    fclose ($handle);
    return array_reverse($text);
}

$fsize = round(filesize(TEXT_FILE)/1024/1024,2);

echo "<strong>".TEXT_FILE."</strong>\n\n";
echo "File size is {$fsize} megabytes\n\n";
echo "Last ".LINES_COUNT." lines of the file:\n\n";

$lines = read_file(TEXT_FILE, LINES_COUNT);
foreach ($lines as $line) {
    echo $line;
}
define('YOUR_EOL', "\n");
$fp = fopen('yourfile.txt', 'r');

$pos = -1; $line = ''; $c = '';
do {
    $line = $c . $line;
    fseek($fp, $pos--, SEEK_END);
    $c = fgetc($fp);
} while ($c != YOUR_EOL);

echo $line;

fclose($fp);

This is better, since it does not load the complete file into memory...

Set YOUR_EOL to your correct line endings, if you use the same line endings as the default line endings of the OS where your script resides, you could use the constant PHP_EOL.

function seekLastLine($f) {
    $pos = -2;
    do {
        fseek($f, $pos--, SEEK_END);
        $ch = fgetc($f);
    } while ($ch != "\n");
}

-2 because last char can be \n

You either have to read the file in line by line and save the last read line to get it.

Or if on unix/linux you might consider using the shell command tail

tail -n 1 filename

This one wont break for a 1 or 0 line file.

function readlastline($fileName)
{

       $fp = @fopen($fileName, "r");
       $begining = fseek($fp, 0);      
       $pos = -1;
       $t = " ";
       while ($t != "\n") {
             fseek($fp, $pos, SEEK_END);
             if(ftell($fp) == $begining){
              break;
             }
             $t = fgetc($fp);
             $pos = $pos - 1;
       }
       $t = fgets($fp);
       fclose($fp);
       return $t;
}

...Why just read the last line?

function readLines($fp, $num) {

    $line_count = 0; $line = ''; $pos = -1; $lines = array(); $c = '';

    while($line_count < $num) {
        $line = $c . $line; 
        fseek($fp, $pos--, SEEK_END);
        $c = fgetc($fp);
        if($c == "\n") { $line_count++; $lines[] = $line; $line = ''; $c = ''; }
    }   
    return $lines;
}

$filename = "content.txt";
$fp = @fopen($filename, "r");

print_r(readLines($fp, 2));

fclose($fp);

If you want to read a file line by line the file function reads the contents of a file, line by line and returns each line as an element of an array.

So you could do something simple like:

$lines    = file('log.txt');
$lastLine = array_pop($lines);

@unique_stephen, your answer is flawed. PHP fseek returns 0 for success and -1 for failure. Storing the result in $begining (sic) and then later using it in a filter for ftell() isn't correct. If my reputation were higher I would have voted you down and left a comment. Here is a modified version of unique_stephen's function.

function readlastline($fileName)
{
    $fp = @fopen($fileName, "r");
    if (fseek($fp, 0) == -1)
        exit('Cannot seek to beginning of the file'); 
    $pos = -1;
    $t = " ";
    while ($t != "\n") {
        if (fseek($fp, $pos, SEEK_END) == -1)
            exit('Cannot seek to the end of the file');
        if (ftell($fp) == 0) {
            break;
        }
        $t = fgetc($fp);
        $pos = $pos - 1;
    }
    $t = fgets($fp);
    fclose($fp);
    return $t;
}

NOTE: PHP's fseek cannot manage to seek to the end of files larger than PHP_MAX_INT which is 32bit signed even on 64bit binaries.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top