]> git.mxchange.org Git - friendica.git/blob - src/Util/ReversedFileReader.php
eeedc1a5ccba435fe6ecac8f6055677924eb9101
[friendica.git] / src / Util / ReversedFileReader.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2021, Friendica
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Util;
23
24
25 /**
26  * An iterator which returns lines from file in reversed order
27  *
28  * original code https://stackoverflow.com/a/10494801
29  */
30 class ReversedFileReader implements \Iterator
31 {
32     const BUFFER_SIZE = 4096;
33     const SEPARATOR = "\n";
34
35     /** @var int */
36     private $filesize;
37
38     /** @var int */
39     private $pos;
40
41     /** @var array */
42     private $buffer;
43
44     /** @var int */
45     private $key;
46
47     /** @var string */
48     private $value;
49
50     public function __construct($filename)
51     {
52         $this->_fh = fopen($filename, 'r');
53                 if (!$this->_fh) {
54                         // this should use a custom exception.
55                         throw \Exception("Unable to open $filename");
56                 }
57         $this->filesize = filesize($filename);
58         $this->pos = -1;
59         $this->buffer = null;
60         $this->key = -1;
61         $this->value = null;
62     }
63
64     public function _read($size)
65     {
66         $this->pos -= $size;
67         fseek($this->_fh, $this->pos);
68         return fread($this->_fh, $size);
69     }
70
71     public function _readline()
72     {
73         $buffer =& $this->buffer;
74         while (true) {
75             if ($this->pos == 0) {
76                 return array_pop($buffer);
77             }
78             if (count($buffer) > 1) {
79                 return array_pop($buffer);
80             }
81             $buffer = explode(self::SEPARATOR, $this->_read(self::BUFFER_SIZE) . $buffer[0]);
82         }
83     }
84
85     public function next()
86     {
87         ++$this->key;
88         $this->value = $this->_readline();
89     }
90
91     public function rewind()
92     {
93         if ($this->filesize > 0) {
94             $this->pos = $this->filesize;
95             $this->value = null;
96             $this->key = -1;
97             $this->buffer = explode(self::SEPARATOR, $this->_read($this->filesize % self::BUFFER_SIZE ?: self::BUFFER_SIZE));
98             $this->next();
99         }
100     }
101
102     public function key()
103         {
104                 return $this->key;
105         }
106
107     public function current()
108         {
109                 return $this->value;
110         }
111
112     public function valid()
113         {
114                 return ! is_null($this->value);
115         }
116 }