$fh = fopen('employees.txt','r') or die("can't open: $php_errormsg");
$linebreak = $beginning_of_file = 0;
$gap = 80;
$filesize = filesize('employees.txt');
fseek($fh,0,SEEK_END);
while (! ($linebreak || $beginning_of_file)) {
// save where we are in the file
$pos = ftell($fh);
/* move back $gap chars, use rewind() to go to the beginning if
* we're less than $gap characters into the file */
if ($pos < $gap) {
rewind($fh);
} else {
fseek($fh,-$gap,SEEK_CUR);
}
// read the $gap chars we just seeked back over
$s = fread($fh,$gap) or die($php_errormsg);
/* if we read to the end of the file, remove the last character
* since if it's a newline, we should ignore it */
if ($pos + $gap >= $filesize) {
$s = substr_replace($s,'',-1);
}
// move back to where we were before we read $gap chars into $s
if ($pos < $gap) {
rewind($fh);
} else {
fseek($fh,-$gap,SEEK_CUR);
}
// is there a linebreak in $s ?
if (is_integer($lb = strrpos($s,"\n"))) {
$linebreak = 1;
// the last line of the file begins right after the linebreak
$line_end = ftell($fh) + $lb + 1;
}
// break out of the loop if we're at the beginning of the file
if (ftell($fh) == 0) { $beginning_of_file = 1; }
}
if ($linebreak) {
rewind($fh);
$file_without_last_line = fread($fh,$line_end) or die($php_errormsg);
}
fclose($fh) or die("can't close: $php_errormsg");
This code starts at the end of the file and moves backwards in
$gap character chunks looking for a newline. If it
finds one, it knows the last line of the file starts right after that
newline. This position is saved in $line_end.
After the while loop, if
$linebreak is set, the contents of the file from
the beginning to $line_end are read into
$file_without_last_line.
The last character of the file is ignored because if
it's a newline, it doesn't indicate
the start of the last line of the file. Consider the 10-character
file whose contents are asparagus\n. It has only
one line, consisting of the word asparagus and a
newline character. This file without its last line is empty, which
the previous code correctly produces. If it starts scanning with the
last character, it sees the newline and exits its scanning loop,
incorrectly printing out asparagus without the
newline.