how to read the last 10 lines on a file using php.

Sample Entry:

Samp1
Samp2
Samp3
Samp4
Samp5
Samp6
Samp7
Samp8
Samp9
Samp10
Samp11
Samp12
Samp13
Samp14
Samp15

Output:
Samp11
Samp12
Samp13
Samp14
Samp15

Recommended Answers

All 10 Replies

without seeing what you have attempted...... (this is just a second guess)

$array = array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19);

sort($array);
$i = 1;
while ($i < 11){
foreach ($array as $key => $val) {
    echo "array[" . $key . "] = " . $val . "\n";
      }
       $i ++
}
?>

hi whiteyoh,

I have a content on a text file which is 20 lines.

here's the sample:
line1
line2
line3
line4
line5
line6
line7
line8
line9
line10
line11
line12
line13
line14
line15
line16
line17
line18
line19
line20

I want to have the following sample output:

line20
line19
line18
line17
line16
line15
line14
line13
line12
line11

How to limit that into 10, I want to show the last 10 lines in a reverse order. Right now it shows all content in a reverse order but don't know how to limit the last 10 only.

Thank you for your response friend :)

Is the file of a variable length, where you do not know the total number of lines, or will the file always have a fixed number of lines?

you could use my example, but before using the array you can sort (for ascending) or rsort (for descending).

then just iterate through the array however many times you want to by using while

hi whiteyoh,

I have here the following code here from a friend and it shows all the content in a reverse order. thank you so much for your quick reply.

<?php
         $file = array_reverse( file( 'cLogs/'.$sid.'.txt' ) );
         foreach ( $file as $line ){
                 $parts = explode('||', $line);
                 echo $parts[0]."<div style='border-bottom: 1px dotted #333333; height: 2px;'></div>";
                }
?>

Is the file of a variable length, where you do not know the total number of lines, or will the file always have a fixed number of lines?

Hi mschroeder,

the content on a file is dynamic, it added new line once there an action made on the page.

thank you so much for your reply.

- alfred

If you use the file() function to load the file like that, it will load the entire file into memory. For files with only a few hundred lines this won't be an issue, for files with hundreds of thousands of lines, this will become very intensive.

For example, I have a dictionary file that has 135K lines. Only a single word per line. When I load it with file() memory usage goes from 379288 bytes to 15289096 bytes. The original file is only 1.29MB in size.

You cannot read files backwards, but you can use fread() and fseek() to read chunks from the end of the file, and see if you have 10 lines in it.

This examples keeps reading a chunk from the end, moving towards the beginning of the file, until it finds 10 lines.

$path = '/path/to/file.txt';

$num_lines = 10; // number of lines from end of file to read

$tail = ''; // content at end of file 

if ($fp = fopen($path, 'r')) {
 $buf_size = 1024;
 $start_read = $filesize = filesize($path); // where to start reading (end of file)
 $i = 0;
 while($start_read > 0 && count(explode("\n", $tail)) < $num_lines+1) {
   
   $start_read -= $buf_size; // read from last point minus the size we want to read
   if ($start_read < 0) {
     $read_size = $buf_size + $start_read;
     $start_read = 0;
   } else {
     $read_size = $buf_size;   
   }
   fseek($fp, $start_read);
   $tail = fread($fp, $read_size) . $tail;
   
   $i++;
 }
 fclose($fp);
}

$lines = array_slice(explode("\n", $tail), -$num_lines, $num_lines);

echo implode("\n", array_reverse($lines));

This has been driving me up the wall all day so I put some code down and have something I like.

This is a class which extends the SplFileObject class and overloads its iterator methods. It also implements the seek method. I did play with this, but there may be some oversights take it for what it is.

- ReverseSplFileObject.php -

<?php
class ReverseSplFileObject extends SplFileObject {
	
	protected $_line = 0;
	protected $_pointer = 0;
	protected $_begin;
	protected $_eol = "\n";
	protected $_trim = TRUE;

    public function __construct($filename, $trim = true) {
		//Setup the SplFileObkect
		parent::__construct($filename);
		
		//Should we trim the output?
		$this->_trim = $trim;
		
		//Set our line position from the end at 0
		//Numbers increment positively but lines go in reverse order
		$this->_line = 0;
		
		//Seek to the first position of the file and record its position
		//Should be 0
		$this->fseek(0);
		$this->_begin = $this->ftell();
		
		//Seek to the last position from the end of the file
		//This varies depending on the file
		$this->fseek($this->_pointer, SEEK_END);
    }

    public function rewind() {		
		//Set the line position to 0 - First Line
		$this->_position = 0;
		
		//Reset the file pointer to the end of the file minus 1 charachter
		$this->fseek(-1, SEEK_END);
		$this->_pointer = $this->ftell();
		
		//Check the last charachter to make sure it is not a new line
		$c = $this->fgetc();
		while($c != $this->_eol){
			--$this->_pointer;
			$this->fseek($this->_pointer);
			if( $this->ftell() < 0 ){
				break;
			}
			$c = $this->fgetc();
		}
		//File pointer is now at the beginning of the last line
    }

    public function current() {
		//Return the current line after the file pointer
		if( TRUE === $this->_trim ){
			return trim($this->fgets());
		} 
		
		return $this->fgets();
    }

    public function key() {
		//Return the current key of the line we're on
		//These go in reverse order
		return $this->_position;
    }

    public function next() {
		//Step the file pointer back one step to the last letter of the previous line
		--$this->_pointer;
		if( $this->_pointer < $this->_begin ){
			return;
		}
		
		$this->fseek($this->_pointer);
		//Check the charachter over and over till we hit another new line
		$c = $this->fgetc();
		while($c != $this->_eol){
			--$this->_pointer;
			$this->fseek($this->_pointer);
			if( $this->ftell() <= 0 ){
				break;
			}
			$c = $this->fgetc();
		}
		//File pointer is now on the next previous line
		//Increment the line position
		++$this->_position;
    }

    public function valid() {
		//Check the current file pointer to make sure we  are not at the beginning of the file
		if( ($this->_pointer >= $this->_begin) ){
			return true;
		}
		return false;
	}
	
	public function seek( $position ){
		for($i=0; $i<$position; $i++){
			$this->next();
		}
	}
}

Use it like this:

<?php
include( 'ReverseSplFileObject.php' );

echo memory_get_usage(), PHP_EOL;

$file = new ReverseSplFileObject('dictionary.txt');
foreach(new LimitIterator($file, 0, 10) as $key=>$val){
	var_dump($key, $val);
}
echo memory_get_usage(), PHP_EOL;

In my testing dictionary.txt has over 135K lines, by wrapping the ReverseSplFileObject instance ($file) in a LimitIterator we can limit the output to ten lines as well as setting an offset from the bottom of the file. This functions by placing the file pointer at the end of the file then going backwards by character until it finds an EOL character (\n in this case).

$data = array_slice(file('file.txt'), -5);

foreach ($data as $line) {
    echo $line;
}


echo $line;
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.