Files
pathfinder/app/main/data/file/reversesplfileobject.php
Exodus4D a8edf39697 - new "logging" system for map/system/signature/connection changes, closed #271
- new map change log to Slack channel
- new "rally point" logging to Slack channel
- new "rally point" poke options (e.g. custom message), closed #295
- new log options for WebSocket installations
- added ship "mass" logging (backend only), #313
- added map logging to Slack, #326
- added "ESI error rate" limit detection
- added "Monolog" as new logging library (Composer dependency)
- added "Swiftmailer" as new eMail library (Composer dependency)
- added Support for Redis session hander (performance boost)
- improved character select panels (visible "online" status)
- improved "activity logging" (more DB columns added to check)
- improved eMail logging (HTML template support)
- improved "delete map" now become "inactive" for some days before delete
- improved character logout handling
- improved /setup page for DB bootstrap (new button for DB create if not exists)
- fixed broken ship tracking (ship name re-added)
- fixed broken ship tracking for multiple chars on different browser tabs
- fixed broken cursor coordinates, closed #518
- fixed null pointer "charactermodel.php->isActive():925" closed #529
- fixed broken "scroll offset", closed #533 closed #534
- Updated "validation" library JS v0.10.1 -> v0.11.9
- Updated ORM Mapper _Cortex_ v1.5.0-dev -> v1.5.0
- and many more....
2017-10-22 17:58:34 +02:00

219 lines
5.5 KiB
PHP

<?php
/**
* Created by PhpStorm.
* User: exodu
* Date: 06.08.2017
* Time: 18:42
*/
namespace data\file;
class ReverseSplFileObject extends \SplFileObject{
/**
* pointer position indicates file start
* @var int
*/
protected $begin = 0;
/**
* line offset from file end (1 => 'start with 2nd last line')
* @var int
*/
protected $offset = 0;
/**
* total lines found in file
* @var int
*/
protected $lineCount = 0;
/**
* empty lines found in file
* @var int
*/
protected $lineCountEmpty = 0;
/**
* current pointer position
* @var int
*/
protected $pointer = 0;
/**
* position increments when valid row data found
* @var
*/
protected $position;
/**
* control characters
* @var array
*/
protected $eol = ["\r", "\n"];
public function __construct($sourceFile, $offset = 0){
parent::__construct($sourceFile);
// set total line count of the file
$this->setLineCount();
//Seek to the first position of the file and record its position
//Should be 0
$this->fseek(0);
$this->begin = $this->ftell();
$this->offset = $offset;
//Seek to the last position from the end of the file
//This varies depending on the file
$this->fseek($this->pointer, SEEK_END);
}
/**
* reverse rewind file.
*/
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 character. "0" == false
$this->fseek(-1, SEEK_END);
$this->findLineBegin();
//... File pointer is now at the beginning of the last line that contains data
// add custom line offset
if($this->offset){
// calculate offset start line
$offsetLine = $this->lineCount - $this->lineCountEmpty - $this->offset;
if($offsetLine > 0){
// row is zero based
$offsetIndex = $offsetLine - 1;
parent::seek($offsetIndex);
// seek() sets pointer to next line... set it back to previous
$this->fseek(-2, SEEK_CUR);
$this->findLineBegin();
//... File pointer is now at the beginning of the last line that contains data from $offset
}else{
// negative offsetLine -> invalid!
$this->pointer = $this->begin -1;
}
}
}
/**
* Return the current line after the file pointer
* @return string
*/
public function current(){
return trim($this->fgets());
}
/**
* Return the current key of the line we're on
* These go in reverse order
* @return mixed
*/
public function key(){
return $this->position;
}
/**
* move one line up
*/
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);
$this->findLineBegin();
//File pointer is now on the next previous line
//Increment the line position
++$this->position;
}
/**
* Check the current file pointer to make sure we are not at the beginning of the file
* @return bool
*/
public function valid(){
return ($this->pointer >= $this->begin);
}
/**
* seek to previous lines
* @param int $lineCount
*/
public function seek($lineCount){
for($i = 0; $i < $lineCount; $i++){
$this->next();
}
}
/**
* move pointer to line begin
* -> skip line breaks
*/
private function findLineBegin(){
//Check the character over and over till we hit another new line
$c = $this->fgetc();
// skip empty lines
while(in_array($c, $this->eol)){
$this->fseek(-2, SEEK_CUR);
if(!$this->pointer = $this->ftell()){
break;
}
$c = $this->fgetc();
$this->lineCountEmpty++;
}
//Check the last character to make sure it is not a new line
while(!in_array($c, $this->eol)){
$this->fseek(-2, SEEK_CUR);
if(!$this->pointer = $this->ftell()){
break;
}
$c = $this->fgetc();
}
}
/**
* set total line count. No matter if there are empty lines in between
*/
private function setLineCount(){
// Store flags and position
$flags = $this->getFlags();
$currentPointer = $this->ftell();
// Prepare count by resetting flags as READ_CSV for example make the tricks very slow
$this->setFlags(null);
// Go to the larger INT we can as seek will not throw exception, errors, notice if we go beyond the bottom line
//$this->seek(PHP_INT_MAX);
parent::seek(PHP_INT_MAX);
// We store the key position
// As key starts at 0, we add 1
$this->lineCount = parent::key() + 1;
// We move to old position
// As seek method is longer with line number < to the max line number, it is better to count at the beginning of iteration
//parent::seek($currentPointer);
$this->fseek($currentPointer);
// Re set flags
$this->setFlags($flags);
}
}