Reputation: 4834
So I am doing a small experiment for myself, a script to read the php errors' log file (with SplFileObject) and output it formatted on the browser.
I though it would be more logic to display it in reversed order (the latest errors on top).
To use the "normal" order I would just display each line and call $file->next(); to move the pointer, but as I'm doing it the other way around, and there's not a prev()
or previous()
method as far as I know, the only way I found was using seek()
:
for($i = $lines_total - $start_at; $i > $lines_total - $start_at - $lines_to_get; $i--){
$content->seek($i);
$data = $content->current();
if(empty($data)){
continue;
}
}
But this is incredibly slow (around 7 Secs for a 16mb file). If I do it in the normal order it's instant.
Do anyone knows any method? or what I'm trying to do is crazy? xD I'm just a designer forced to code, so I am not very familiarized with pointers and stuff like that.
Upvotes: 2
Views: 1949
Reputation: 21671
This is an old question but with SplFileObj the simplest way is to use the key and seek,
public function prev(){
$key = $this->_splFileObj->key();
if( $key ){
--$key;
}
$this->_splFileObj->seek($key);
}
Assuming this method is in a wrapper around SplFileObj with the property of _splFileObj
.
Upvotes: 0
Reputation: 4834
In case anybody encounters this problem in the future I came up with a quite simple solution:
//get to the last position of the file and get the pointer position.
$content->seek($content->getSize());
$lines_total = $content->key();
$byte = $content->ftell();
//all the line in the php error log starts like: [21-Feb-2013 22:34:53 UTC] so...
$pattern = '/^\[.*\]/';
for(...){
//get the current output to preg_match it
$data = $content->current();
//go backward each time it doesnt match a line's start
while ( preg_match( $pattern, $data ) === 0 ){
$byte--;
$content->fseek($byte);
$data = $content->current();
}
//go backward 1 more position to start the next loop
$byte--;
$content->fseek($byte);
}
Hope this helps someone someday xD
Upvotes: 2
Reputation: 95131
FROM PHP DOC
prev — Rewind the internal array pointer
prev() behaves just like next(), except it rewinds the internal array pointer one place instead of advancing it.
As you can see they only work with arrays not file pointer .... you can only use it like this
$file = new SplFileObject("log.txt", "r");
$file = iterator_to_array($file);
echo current($file), PHP_EOL;
echo next($file), PHP_EOL;
echo prev($file), PHP_EOL;
If you want to move to the next line you can try using SplFileObject::ftell
to get the previous position then use SplFileObject::fseek
to implement your reverse ...
Example
$file = new ReverseableSplFileObject("log.txt", "r");
foreach ( $file as $c ) {
echo $c, PHP_EOL;
}
echo $file->prev(), PHP_EOL;
echo $file->prev(), PHP_EOL;
echo $file->prev(), PHP_EOL;
Output
A
B
C
C
B
A
Modified class
class ReverseableSplFileObject extends SplFileObject {
private $pos = array();
function current() {
return trim(parent::current());
}
function next() {
$this->eof() or $this->pos[] = $this->ftell();
return parent::next();
}
function prev() {
if (empty($this->pos)) {
$this->fseek(0);
} else {
$this->fseek(array_pop($this->pos));
}
return $this->current();
}
}
Upvotes: 2