PageRenderTime 179ms CodeModel.GetById 45ms RepoModel.GetById 1ms app.codeStats 0ms

/tools/log-reader.php

https://bitbucket.org/kristovaher/wave-framework
PHP | 345 lines | 216 code | 57 blank | 72 comment | 56 complexity | b39b0fe5f49b7c6236b9afb67fa3da2f MD5 | raw file
Possible License(s): LGPL-3.0
  1. <?php
  2. /**
  3. * Wave Framework <http://www.waveframework.com>
  4. * Log Reader
  5. *
  6. * This is a simple script that is used to read log files stored by WWW_Logger class.
  7. * It loads a log file defined by specific timestamp formatted as Y-m-d-H. By default
  8. * it displays information about all the requests that have happened in the current
  9. * hour, but if GET variable 'log' is supplied in same timestamp format, then that
  10. * log file data is returned instead.
  11. *
  12. * @package Tools
  13. * @author Kristo Vaher <kristo@waher.net>
  14. * @copyright Copyright (c) 2012, Kristo Vaher
  15. * @license GNU Lesser General Public License Version 3
  16. * @tutorial /doc/pages/guide_tools.htm
  17. * @since 1.0.0
  18. * @version 3.6.0
  19. */
  20. // This initializes tools and authentication
  21. require('.'.DIRECTORY_SEPARATOR.'tools_autoload.php');
  22. // Log is printed out in plain text format
  23. header('Content-Type: text/html;charset=utf-8');
  24. // Checking if logger attempts to read internal log
  25. if(isset($_GET['internal'])){
  26. // Debugger actions are based on whether signature and error are set
  27. if(isset($_GET['signature'])){
  28. // Replacing potentially harmful characters
  29. $signature=preg_replace('[^a-zA-Z0-9]','',$_GET['signature']);
  30. // Actual log address
  31. $logAddress='..'.DIRECTORY_SEPARATOR.'filesystem'.DIRECTORY_SEPARATOR.'logs'.DIRECTORY_SEPARATOR.'internal_'.$signature.'_data.tmp';
  32. // If file is set for deletion
  33. if(isset($_GET['delete']) && file_exists($logAddress)){
  34. // Removing the data file
  35. unlink($logAddress);
  36. // Removing signature file
  37. $signatureAddress=str_replace('_data','_signature',$logAddress);
  38. if(file_exists($signatureAddress)){
  39. unlink($signatureAddress);
  40. }
  41. // Redirecting to link without delete flag set
  42. header('Location: log-reader.php?internal');
  43. die();
  44. }
  45. } else {
  46. // This array stores all the error developer signatures
  47. $signatures=array();
  48. // This is the list of all errors based on signatures
  49. $files=fileIndex('..'.DIRECTORY_SEPARATOR.'filesystem'.DIRECTORY_SEPARATOR.'logs'.DIRECTORY_SEPARATOR,'filenames',false);
  50. // Looping over each folder that includes errors
  51. foreach($files as $f){
  52. // Making sure that the file is that of an internal log entry
  53. $f=explode('_',$f);
  54. if(count($f)==3 && $f[0]=='internal' && $f[2]=='signature.tmp'){
  55. $signatures[$f[1]]=file_get_contents('..'.DIRECTORY_SEPARATOR.'filesystem'.DIRECTORY_SEPARATOR.'logs'.DIRECTORY_SEPARATOR.'internal_'.$f[1].'_signature.tmp');
  56. }
  57. }
  58. }
  59. } elseif(isset($_GET['api'])){
  60. // Actual log address
  61. $logAddress='..'.DIRECTORY_SEPARATOR.'filesystem'.DIRECTORY_SEPARATOR.'logs'.DIRECTORY_SEPARATOR.'api.tmp';
  62. // If file is set for deletion
  63. if(isset($_GET['delete']) && file_exists($logAddress)){
  64. unlink($logAddress);
  65. // Redirecting to link without delete flag set
  66. header('Location: log-reader.php?api');
  67. die();
  68. }
  69. } elseif(isset($_GET['http'])){
  70. // Log reader can access any log file created by the system
  71. if(isset($_GET['log'])){
  72. // User agent requested input URL is validated against hostile characters
  73. $logFileName=preg_replace('/[^A-Za-z\-\_0-9\/]/i','',$_GET['log']);
  74. } else {
  75. // By default the results are returned from current hour
  76. header('Location: log-reader.php?http&log='.date('Y-m-d-H'));
  77. die();
  78. }
  79. // This stores the array types to print out
  80. $types=array();
  81. // You can print out only some log information
  82. if(isset($_GET['types'])){
  83. $rawTypes=explode(',',$_GET['types']);
  84. foreach($rawTypes as $t){
  85. $bits=explode('[',$t);
  86. if(isset($bits[1])){
  87. $types[$t]=str_replace(']','',$bits[1]);
  88. } else {
  89. $types[$t]=true;
  90. }
  91. }
  92. } else {
  93. $types['all']=true;
  94. }
  95. // Every day the logs are stored under different log subfolder
  96. $logSubfolder=substr($logFileName,0,10);
  97. // Actual log address
  98. $logAddress='..'.DIRECTORY_SEPARATOR.'filesystem'.DIRECTORY_SEPARATOR.'logs'.DIRECTORY_SEPARATOR.$logSubfolder.DIRECTORY_SEPARATOR.$logFileName.'.tmp';
  99. // If file is set for deletion
  100. if(isset($_GET['delete']) && file_exists($logAddress)){
  101. unlink($logAddress);
  102. unset($_GET['delete']);
  103. // Redirecting to link without delete flag set
  104. if(!empty($_GET)){
  105. header('Location: log-reader.php?'.http_build_query($_GET));
  106. } else {
  107. header('Location: log-reader.php');
  108. }
  109. die();
  110. }
  111. }
  112. ?>
  113. <!DOCTYPE html>
  114. <html lang="en">
  115. <head>
  116. <title><?=(isset($_GET['internal']))?'Internal Log':((isset($_GET['api']))?'API Log':'Log Reader')?></title>
  117. <meta charset="utf-8">
  118. <meta name="viewport" content="width=device-width"/>
  119. <link type="text/css" href="style.css" rel="stylesheet" media="all"/>
  120. <link rel="icon" href="../favicon.ico" type="image/x-icon"/>
  121. <link rel="icon" href="../favicon.ico" type="image/vnd.microsoft.icon"/>
  122. <meta content="noindex,nocache,nofollow,noarchive,noimageindex,nosnippet" name="robots"/>
  123. <meta http-equiv="cache-control" content="no-cache"/>
  124. <meta http-equiv="pragma" content="no-cache"/>
  125. <meta http-equiv="expires" content="0"/>
  126. </head>
  127. <body>
  128. <?php
  129. // Pops up an alert about default password
  130. passwordNotification($config['http-authentication-password']);
  131. // Header
  132. if(isset($_GET['internal'])){
  133. echo '<h1>Internal Log</h1>';
  134. } elseif(isset($_GET['api'])){
  135. echo '<h1>API Log</h1>';
  136. } elseif(isset($_GET['http'])) {
  137. echo '<h1>HTTP Request Log</h1>';
  138. } else {
  139. echo '<h1>Log Entries</h1>';
  140. }
  141. echo '<h4 class="highlight">';
  142. foreach($softwareVersions as $software=>$version){
  143. // Adding version numbers
  144. echo '<b>'.$software.'</b> ('.$version.') ';
  145. }
  146. echo '</h4>';
  147. echo '<h2>Log</h2>';
  148. if(isset($_GET['internal']) && !isset($_GET['signature'])){
  149. echo '<h3>Available Signatures</h3>';
  150. echo '<h4>Signature is a pair of IP address and user agent string that generated the log entries. This helps you keep different log entries separate from one another based on client. Click on signature to see relevant log entries.</h4>';
  151. // If there are error signatures found
  152. if(!empty($signatures)){
  153. foreach($signatures as $folder=>$signature){
  154. if($signature==$_SERVER['REMOTE_ADDR'].' '.$_SERVER['HTTP_USER_AGENT']){
  155. echo '<a href="log-reader.php?internal&signature='.md5($signature).'">'.$signature.' <span class="orange">(this matches your signature)</span></a><br/>';
  156. } else {
  157. echo '<a href="log-reader.php?internal&signature='.md5($signature).'">'.$signature.'</a><br/>';
  158. }
  159. }
  160. } else {
  161. echo '<p class="bold">There are no logged messages</p>';
  162. }
  163. } elseif(file_exists($logAddress)){
  164. // File delete link
  165. echo '<h3 onclick="if(confirm(\'Are you sure?\')){ document.location.href=document.location.href+\'&delete\'; }" class="red bold" style="cursor:pointer;">Click to delete this log</h3>';
  166. // Getting error file size
  167. $filesize=filesize($logAddress);
  168. // Attempting to get memory limit
  169. $memory=ini_get('memory_limit');
  170. if($memory){
  171. $memory=iniSettingToBytes($memory);
  172. // Getting the amount of bytes currently allocated
  173. $memory=$memory-memory_get_usage();
  174. // available memory is 'about half' of the actual memory, just in case the array creation takes a lot of memory
  175. $memory=intval($memory/2);
  176. }
  177. // Output buffer allows to increase peformance due to multiple echo's
  178. ob_start();
  179. // This variable holds various summary statistics
  180. $summary=array();
  181. // Log is only shown if memory limit could not be gotten or is less than the file size
  182. if(!$memory || $filesize<$memory){
  183. // Log files are stored as JSON serialized arrays, separated with line-breaks
  184. $log=explode("\n",file_get_contents($logAddress));
  185. // Printing out every line from the log file
  186. foreach($log as $l){
  187. if(isset($_GET['api']) && $l!=''){
  188. $logDetails=explode("\t",$l);
  189. echo '<div class="block">';
  190. // Printing out log data
  191. echo '<b>'.date('d.m.Y H:i:s',$logDetails[0]).'</b> '.$logDetails[1].' -&gt; '.$logDetails[2].'<br/>';
  192. echo '</div>';
  193. if($logDetails[0]>=($_SERVER['REQUEST_TIME']-2592000)){
  194. $summary['30days'][$logDetails[1]][$logDetails[2]]++;
  195. }
  196. $summary['totals'][$logDetails[1]][$logDetails[2]]++;
  197. } else {
  198. // Log data is deencoded from JSON string
  199. $l=json_decode($l,true);
  200. // Log entry should be an array once decoded
  201. if(is_array($l)){
  202. $accepted=true;
  203. // Breaking out of the loop if the assigned key value is not the one that is required
  204. if(isset($types)){
  205. foreach($types as $key=>$t){
  206. if($key!='all' && $t!==true){
  207. if(!isset($l[str_replace('['.$t.']','',$key)]) || $l[str_replace('['.$t.']','',$key)]!=$t){
  208. $accepted=false;
  209. }
  210. }
  211. }
  212. }
  213. if($accepted){
  214. echo '<div class="border block">';
  215. // Printing out log data
  216. foreach($l as $key=>$entry){
  217. if(isset($_GET['internal']) || isset($types['all']) || isset($types[$key])){
  218. if(!is_array($entry)){
  219. echo '<b>'.$key.':</b> '.$entry.'<br/>';
  220. } else {
  221. echo '<b>'.$key.':</b>';
  222. echo '<pre class="small box disabled">';
  223. print_r($entry);
  224. echo '</pre>';
  225. }
  226. }
  227. }
  228. echo '</div>';
  229. }
  230. }
  231. }
  232. }
  233. } else {
  234. echo '<p class="bold">This log is too large for PHP to handle.</p>';
  235. }
  236. // Getting the content from output buffer
  237. $logContent=ob_get_clean();
  238. // Output buffer allows to increase peformance due to multiple echo's
  239. ob_start();
  240. // If summary data is set
  241. if(!empty($summary)){
  242. echo '<h2>Summary</h2>';
  243. if(isset($_GET['api'])){
  244. // Summary for 30 Days
  245. echo '<h3>Last 30 Days</h3>';
  246. foreach($summary['30days'] as $profile=>$data){
  247. echo '<h4><b>'.$profile.'</b></h4>';
  248. echo '<ul>';
  249. foreach($data as $command=>$d){
  250. echo '<li><b>'.$command.'</b> '.$d.' calls</li>';
  251. }
  252. echo '</ul>';
  253. }
  254. // Printing out summary for totals
  255. echo '<h3>Totals</h3>';
  256. foreach($summary['totals'] as $profile=>$data){
  257. echo '<h4><b>'.$profile.'</b></h4>';
  258. echo '<ul>';
  259. foreach($data as $command=>$d){
  260. echo '<li><b>'.$command.'</b> '.$d.' calls</li>';
  261. }
  262. echo '</ul>';
  263. }
  264. }
  265. echo '<h2>Entries</h2>';
  266. }
  267. // Getting the content from output buffer
  268. $summaryContent=ob_get_clean();
  269. // Printing out summary and log
  270. echo $summaryContent;
  271. echo $logContent;
  272. } else {
  273. if(isset($_GET['internal']) || isset($_GET['api']) || isset($_GET['http'])){
  274. // Log information not found
  275. echo '<p class="red bold">Cannot find log information</p>';
  276. } else {
  277. echo '<p class="bold">Please select log type</p>';
  278. }
  279. }
  280. echo '<h2>Modes</h2>';
  281. echo '<p><a href="log-reader.php?http">HTTP Request Log</a> - Log information about HTTP requests</p>';
  282. echo '<p><a href="log-reader.php?api">API Log</a> - API profile call log</p>';
  283. echo '<p><a href="log-reader.php?internal">Internal Log</a> - Internal log entries</p>';
  284. // Footer
  285. echo '<p class="footer small bold">Generated at '.date('d.m.Y h:i').' GMT '.date('P').' for '.$_SERVER['HTTP_HOST'].'</p>';
  286. ?>
  287. </body>
  288. </html>