<?php
/**
- * @copyright Copyright (C) 2021, Friendica
+ * @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
namespace Friendica\Util;
-
/**
* An iterator which returns lines from file in reversed order
*
*/
class ReversedFileReader implements \Iterator
{
- const BUFFER_SIZE = 4096;
- const SEPARATOR = "\n";
+ const BUFFER_SIZE = 4096;
+ const SEPARATOR = "\n";
+
+ /** @var resource */
+ private $fh = null;
+
+ /** @var int */
+ private $filesize = -1;
+
+ /** @var int */
+ private $pos = -1;
+
+ /** @var array */
+ private $buffer = null;
+
+ /** @var int */
+ private $key = -1;
- public function __construct($filename)
- {
- $this->_fh = fopen($filename, 'r');
- if (!$this->_fh) {
+ /** @var string */
+ private $value = null;
+
+ /**
+ * Open $filename for read and reset iterator
+ *
+ * @param string $filename File to open
+ * @return $this
+ */
+ public function open(string $filename)
+ {
+ $this->fh = fopen($filename, 'r');
+ if (!$this->fh) {
// this should use a custom exception.
throw \Exception("Unable to open $filename");
}
- $this->_filesize = filesize($filename);
- $this->_pos = -1;
- $this->_buffer = null;
- $this->_key = -1;
- $this->_value = null;
- }
-
- public function _read($size)
- {
- $this->_pos -= $size;
- fseek($this->_fh, $this->_pos);
- return fread($this->_fh, $size);
- }
-
- public function _readline()
- {
- $buffer =& $this->_buffer;
- while (true) {
- if ($this->_pos == 0) {
- return array_pop($buffer);
- }
- if (count($buffer) > 1) {
- return array_pop($buffer);
- }
- $buffer = explode(self::SEPARATOR, $this->_read(self::BUFFER_SIZE) . $buffer[0]);
- }
- }
-
- public function next()
- {
- ++$this->_key;
- $this->_value = $this->_readline();
- }
-
- public function rewind()
- {
- if ($this->_filesize > 0) {
- $this->_pos = $this->_filesize;
- $this->_value = null;
- $this->_key = -1;
- $this->_buffer = explode(self::SEPARATOR, $this->_read($this->_filesize % self::BUFFER_SIZE ?: self::BUFFER_SIZE));
- $this->next();
- }
- }
-
- public function key()
+ $this->filesize = filesize($filename);
+ $this->pos = -1;
+ $this->buffer = null;
+ $this->key = -1;
+ $this->value = null;
+ return $this;
+ }
+
+ /**
+ * Read $size bytes behind last position
+ *
+ * @return string
+ */
+ private function _read($size)
+ {
+ $this->pos -= $size;
+ fseek($this->fh, $this->pos);
+ return fread($this->fh, $size);
+ }
+
+ /**
+ * Read next line from end of file
+ * Return null if no lines are left to read
+ *
+ * @return ?string
+ */
+ private function _readline()
+ {
+ $buffer = & $this->buffer;
+ while (true) {
+ if ($this->pos == 0) {
+ return array_pop($buffer);
+ }
+ if (is_null($buffer)) {
+ return null;
+ }
+ if (count($buffer) > 1) {
+ return array_pop($buffer);
+ }
+ $buffer = explode(self::SEPARATOR, $this->_read(self::BUFFER_SIZE) . $buffer[0]);
+ }
+ }
+
+ /**
+ * Fetch next line from end and set it as current iterator value.
+ *
+ * @see Iterator::next()
+ * @return void
+ */
+ public function next()
+ {
+ ++$this->key;
+ $this->value = $this->_readline();
+ }
+
+ /**
+ * Rewind iterator to the first line at the end of file
+ *
+ * @see Iterator::rewind()
+ * @return void
+ */
+ public function rewind()
+ {
+ if ($this->filesize > 0) {
+ $this->pos = $this->filesize;
+ $this->value = null;
+ $this->key = -1;
+ $this->buffer = explode(self::SEPARATOR, $this->_read($this->filesize % self::BUFFER_SIZE ?: self::BUFFER_SIZE));
+ $this->next();
+ }
+ }
+
+ /**
+ * Return current line number, starting from zero at the end of file
+ *
+ * @see Iterator::key()
+ * @return int
+ */
+ public function key()
{
- return $this->_key;
+ return $this->key;
}
- public function current()
+ /**
+ * Return current line
+ *
+ * @see Iterator::current()
+ * @return string
+ */
+ public function current()
{
- return $this->_value;
+ return $this->value;
}
- public function valid()
+ /**
+ * Checks if current iterator value is valid, that is, we readed all lines in files
+ *
+ * @see Iterator::valid()
+ * @return bool
+ */
+ public function valid()
{
- return ! is_null($this->_value);
+ return ! is_null($this->value);
}
}