Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP: Read from certain point in file

Similar to: How to read only 5 last line of the text file in PHP?

I have a large log file and I want to be able to show 100 lines from position X in the file. I need to use fseek rather than file() because the log file is too large.

I have a similar function but it will only read from the end of the file. How can it be modified so that a start position can be specified as well? I would also need to start at the end of the file.

function read_line($filename, $lines, $revers = false)
{
    $offset = -1;
    $i = 0;
    $fp = @fopen($filename, "r");
    while( $lines && fseek($fp, $offset, SEEK_END) >= 0 ) {
        $c = fgetc($fp);
        if($c == "\n" || $c == "\r"){
            $lines--;
            if($revers){
                $read[$i] = strrev($read[$i]);
                $i++;
            }
        }
        if($revers) $read[$i] .= $c;
        else $read .= $c;
        $offset--;
    }
    fclose ($fp);
    if($revers){
        if($read[$i] == "\n" || $read[$i] == "\r")
            array_pop($read);
        else $read[$i] = strrev($read[$i]);
        return implode('',$read);
    }
    return strrev(rtrim($read,"\n\r"));
}

What I'm trying to do is create a web based log viewer that will start from the end of the file and display 100 lines, and when pressing the "Next" button, the next 100 lines preceding it will be shown.

like image 630
dukevin Avatar asked May 23 '12 00:05

dukevin


1 Answers

This uses fseek to read 100 lines of a file starting from a specified offset. If the offset is greater than the number of lines in the log, the first 100 lines are read.

In your application, you could pass the current offset through the query string for prev and next and base the next offset on that. You could also store and pass the current file position for more efficiency.

<?php

$GLOBALS["interval"] = 100;

read_log();

function read_log()
{
   $fp = fopen("log", "r");
   $offset = determine_offset();
   $interval = $GLOBALS["interval"];
   if (seek_to_offset($fp, $offset) != -1)
   {
      show_next_button($offset, $interval);
   }
   $lines = array();
   for ($ii = 0; $ii < $interval; $ii++)
   {
      $lines[] = trim(fgets($fp));
   }
   echo "<pre>";
   print_r(array_reverse($lines));
}

// Get the offset from the query string or default to the interval
function determine_offset()
{
   $interval = $GLOBALS["interval"];
   if (isset($_GET["offset"]))
   {
      return intval($_GET["offset"]) + $interval;
   }
   return $interval;
}

function show_next_button($offset, $interval)
{
   $next_offset = $offset + $interval;
   echo "<a href=\"?offset=" . $offset . "\">Next</a>";
}

// Seek to the end of the file, then seek backward $offset lines
function seek_to_offset($fp, $offset)
{
   fseek($fp, 0, SEEK_END);
   for ($ii = 0; $ii < $offset; $ii++)
   {
      if (seek_to_previous_line($fp) == -1)
      {
         rewind($fp);
         return -1;
      }
   }
}

// Seek backward by char until line break
function seek_to_previous_line($fp)
{
   fseek($fp, -2, SEEK_CUR);
   while (fgetc($fp) != "\n")
   {
      if (fseek($fp, -2, SEEK_CUR) == -1)
      {
         return -1;
      }
   }
}
like image 132
0eggxactly Avatar answered Sep 26 '22 14:09

0eggxactly