/tenants/apps/samlservice/deploy-samlservice/samlservice/modules/logpeek/lib/File/reverseRead.php

https://github.com/hpgihan/cronus · PHP · 224 lines · 138 code · 41 blank · 45 comment · 20 complexity · 861eb003e284909c78e3da3e660eb8bd MD5 · raw file

  1. <?php
  2. /**
  3. * Functionatility for line by line reverse reading of a file. It is done by blockwise
  4. * fetching the file from the end and putting the lines into an array.
  5. *
  6. * @author Thomas Graff<thomas.graff@uninett.no>
  7. *
  8. */
  9. class sspmod_logpeek_File_reverseRead{
  10. // 8192 is max number of octets limited by fread.
  11. private $blockSize;
  12. private $blockStart;
  13. private $fileHandle;
  14. // fileSize may be changed after initial file size check
  15. private $fileSize;
  16. private $fileMtime;
  17. // Array containing file lines
  18. private $content;
  19. // Leftover before first complete line
  20. private $remainder;
  21. // Count read lines from the end
  22. private $readPointer;
  23. /**
  24. * File is checked and file handle to file is opend. But no data is read
  25. * from the file.
  26. *
  27. * @param string $fileUrl Path and filename to file to be read
  28. * @param int $blockSize File read block size in byte
  29. * @return bool Success
  30. */
  31. public function __construct($fileUrl, $blockSize = 8192){
  32. if(!is_readable($fileUrl)){
  33. return FALSE;
  34. }
  35. $this->blockSize = $blockSize;
  36. $this->content = array();
  37. $this->remainder = '';
  38. $this->readPointer = 0;
  39. $fileInfo = stat($fileUrl);
  40. $this->fileSize = $this->blockStart = $fileInfo['size'];
  41. $this->fileMtime = $fileInfo['mtime'];
  42. if($this->fileSize > 0){
  43. $this->fileHandle = fopen($fileUrl, 'rb');
  44. return TRUE;
  45. }else{
  46. return FALSE;
  47. }
  48. }
  49. public function __destruct(){
  50. if(is_resource($this->fileHandle)){
  51. fclose($this->fileHandle);
  52. }
  53. }
  54. /**
  55. * Fetch chunk of data from file.
  56. * Each time this function is called, will it fetch a chunk
  57. * of data from the file. It starts from the end of the file
  58. * and work towards the beginning of the file.
  59. *
  60. * @return string buffer with datablock.
  61. * Will return bool FALSE when there is no more data to get.
  62. */
  63. private function readChunk(){
  64. $splits = $this->blockSize;
  65. $this->blockStart -= $splits;
  66. if($this->blockStart < 0){
  67. $splits += $this->blockStart;
  68. $this->blockStart = 0;
  69. }
  70. // Return false if nothing more to read
  71. if($splits === 0){
  72. return FALSE;
  73. }
  74. fseek($this->fileHandle, $this->blockStart, SEEK_SET);
  75. $buff = fread($this->fileHandle, $splits);
  76. // $buff = stream_get_contents($this->fileHandle, $splits, $this->blockStart);
  77. return $buff;
  78. }
  79. /**
  80. * Get one line of data from the file, starting from the end of the file.
  81. *
  82. * @return string One line of data from the file.
  83. * Bool FALSE when there is no more data to get.
  84. */
  85. public function getPreviousLine(){
  86. if(count($this->content) === 0 || $this->readPointer < 1){
  87. do {
  88. $buff = $this->readChunk();
  89. if($buff !== FALSE){
  90. $eolPos = strpos($buff, "\n");
  91. }else{
  92. // Empty buffer, no more to read.
  93. if(strlen($this->remainder) > 0){
  94. $buff = $this->remainder;
  95. $this->remainder = '';
  96. // Exit from while-loop
  97. break;
  98. }else{
  99. // Remainder also empty.
  100. return FALSE;
  101. }
  102. }
  103. if($eolPos === FALSE){
  104. // No eol found. Make buffer head of remainder and empty buffer.
  105. $this->remainder = $buff . $this->remainder;
  106. $buff = '';
  107. }elseif($eolPos !== 0){
  108. // eol found.
  109. $buff .= $this->remainder;
  110. $this->remainder = substr($buff, 0, $eolPos);
  111. $buff = substr($buff, $eolPos+1);
  112. }elseif($eolPos === 0){
  113. $buff .= $this->remainder;
  114. $buff = substr($buff, 1);
  115. $this->remainder = '';
  116. }
  117. }while(($buff !== FALSE) && ($eolPos === FALSE));
  118. $this->content = explode("\n", $buff);
  119. $this->readPointer = count($this->content);
  120. }
  121. if(count($this->content) > 0){
  122. return $this->content[--$this->readPointer];
  123. }else{
  124. return FALSE;
  125. }
  126. }
  127. private function cutHead(&$haystack, $needle, $exit){
  128. $pos = 0;
  129. $cnt = 0;
  130. // Holder på inntill antall ønskede linjer eller vi ikke finner flere linjer
  131. while($cnt < $exit && ($pos = strpos($haystack, $needle, $pos)) !==false ){
  132. $pos++;
  133. $cnt++;
  134. }
  135. return $pos == false? false: substr($haystack, $pos, strlen($haystack));
  136. }
  137. // FIXME: This function hawe som error, do not use before auditing and testing
  138. public function getTail($lines = 10){
  139. $this->blockStart = $this->fileSize;
  140. $buff1 = Array();
  141. $lastLines = array();
  142. while($this->blockStart){
  143. $buff = $this->readChunk();
  144. if(!$buff)break;
  145. $lines -= substr_count($buff, "\n");
  146. if($lines <= 0)
  147. {
  148. $buff1[] = $this->cutHead($buff, "\n", abs($lines)+1);
  149. break;
  150. }
  151. $buff1[] = $buff;
  152. }
  153. for($i = count($buff1); $i >= 0; $i--){
  154. $lastLines = array_merge($lastLines, explode("\n", $buff1[$i]));
  155. }
  156. return $lastLines;
  157. // return str_replace("\r", '', implode('', array_reverse($buff1)));
  158. }
  159. private function getLineAtPost($pos){
  160. if($pos < 0 || $pos > $this->fileSize){
  161. return FALSE;
  162. }
  163. $seeker = $pos;
  164. fseek($this->fileHandle, $seeker, SEEK_SET);
  165. while($seeker > 0 && fgetc($this->fileHandle) !== "\n"){
  166. fseek($this->fileHandle, --$seeker, SEEK_SET);
  167. }
  168. return rtrim(fgets($this->fileHandle));
  169. }
  170. public function getFirstLine(){
  171. return $this->getLineAtPost(0);
  172. }
  173. public function getLastLine(){
  174. return $this->getLineAtPost($this->fileSize-2);
  175. }
  176. public function getFileSize(){
  177. return $this->fileSize;
  178. }
  179. public function getFileMtime(){
  180. return $this->fileMtime;
  181. }
  182. }
  183. ?>