} ?> ><?php echo $lang['settings']; ?> </a></li> <li><a href="logout.php"><?php echo $lang['logout']; ?> </a></li> </ul> <div id="ip"> <?php showip(); # on the RACHEL-Plus we also show a battery meter if (is_rachelplus()) { echo ' <script> refreshRate = 1000 * 60 * 1; // one minute on admin page, be conservative function getBatteryInfo() { $.ajax({ url: "background.php?getBatteryInfo=1", success: function(results) { //console.log(results); var vert = 0; // shows full charge (each icon down 12px) if (results.level < 20) { vert = -48; } else if (results.level < 40) { vert = -36; } else if (results.level < 60) { vert = -24; } else if (results.level < 80) { vert = -12; } var horz = 0; // shows not plugged (40px right to show plugged) if (results.status > -20 ) { horz = 40 }
function draw_stats() { global $maxlines, $alog, $elog; # start timer $starttime = microtime(true); $out = ""; # read query string (and display) if ($_GET && $_GET['module']) { $module = $_GET['module']; $out .= "<p>Usage Stats\n"; $dispmod = preg_replace("/\\/modules\\//", "", $module); } else { # i don't understand why i wrote this bit: if (file_exists("../modules")) { $module = "/modules"; } else { $module = "/"; } $out .= "<p>Usage Stats\n"; $dispmod = ""; } $modmatch = preg_quote($module, "/"); # our log file is overrun with stuff like battery check # requests -- we filter that here and create a temporary # log file instead... $tmpfile = "/media/RACHEL/filteredlog"; $lagtime = 60; # seconds to refresh the filtered log if (!file_exists($tmpfile) || filemtime($tmpfile) < time() - $lagtime) { exec("grep -v 'GET /admin' {$alog} > {$tmpfile}"); } # read in the log file $content = tail($tmpfile, $maxlines); # and process $nestcount = 0; $not_counted = 0; $total_pages = 0; while (1) { ++$nestcount; $count = 0; $errors = 0; # array(); $stats = array(); $start = ""; foreach (preg_split("/((\r?\n)|(\r\n?))/", $content) as $line) { # line count and limiting # XXX is this needed if we're using tail()? if ($maxlines && $count >= $maxlines) { break; } ++$count; # we display the date range - [29/Mar/2015:06:25:15 -0700] preg_match("/\\[(.+?) .+?\\]/", $line, $date); if ($date) { if (!$start) { $start = $date[1]; } $end = $date[1]; } # count errors preg_match("/\"GET.+?\" (\\d\\d\\d) /", $line, $matches); if ($matches && $matches[1] >= 400) { ++$errors; #inc($errors, $matches[1]); } # count pages only (not images and support files) preg_match("/GET (.+?(\\/|\\.html?|\\.pdf|\\.php)) /", $line, $matches); if ($matches) { $url = $matches[1]; # cout the subpages preg_match("/{$modmatch}\\/([^\\/]+)/", $url, $sub); if ($sub) { inc($stats, $sub[1]); ++$total_pages; } else { if (preg_match("/{$modmatch}\\/\$/", $url)) { # if there was a hit with this directory as the # trailing component, there was probably a page there # so we count that too inc($stats, "./"); ++$total_pages; } else { ++$not_counted; } } } else { ++$not_counted; } } # auto-descend into directories if there's only one item # XXX basically we redo the above over, one dir deeper each time, # until we reach a break condition (multiple choices, single page, or too deep, # which is pretty darn inefficient if (sizeof($stats) == 1) { # PHP 5.3 compat - can't index off a function, need a temp var $keys = array_keys($stats); # but not if the one thing is an html file if (preg_match("/(\\/|\\.html?|\\.pdf|\\.php)\$/", $keys[0])) { break; } # and not if it's too deep if ($nestcount > 5) { $out .= "<h1>ERROR descending nested directories</h1>\n"; break; } $module .= "/" . $keys[0]; $modmatch = preg_quote($module, "/"); $dispmod = preg_replace("/\\/modules\\//", "", $module); $dispmod = preg_replace("/\\/+/", "/", $dispmod); } else { break; } } # date & time formatting (we used to show time, but now we don't) $start = preg_replace("/\\:.+/", " ", $start, 1); $end = preg_replace("/\\:.+/", " ", $end, 1); #$start = preg_replace("/\:/", " ", $start, 1); #$end = preg_replace("/\:/", " ", $end, 1); #$start = preg_replace("/\:\d\d$/", "", $start, 1); #$end = preg_replace("/\:\d\d$/", "", $end, 1); $start = preg_replace("/\\//", " ", $start); $end = preg_replace("/\\//", " ", $end); $out .= "<b>{$start}</b> through <b>{$end}</b></p>\n"; # tell the user the path they're in if ($dispmod) { $out .= "<h3 style='margin-bottom: 0;'>Looking In: {$dispmod}</h3>\n"; $out .= "<a href='stats.php' style='font-size: small;'>← back to all modules</a>"; } else { $out .= "<h3 style='margin-bottom: 0;'>Looking At: all modules</h3>\n"; } # stats display arsort($stats); $out .= "<table class=\"stats\">\n"; $out .= "<tr><th>Hits</th><th>Content</th></tr>\n"; foreach ($stats as $mod => $hits) { # html pages are links to the content if (preg_match("/(\\/|\\.html?|\\.pdf|\\.php)\$/", $mod)) { $url = "{$module}/{$mod}"; $out .= "<tr><td>{$hits}</td><td>{$mod} "; $out .= "<small>(<a href=\"{$url}\" target=\"_blank\">view</a>)</small></td></tr>\n"; # directories link to a drill-down } else { $url = "stats.php?module=" . urlencode("{$module}/{$mod}"); $out .= "<tr><td>{$hits}</td>"; $out .= "<td><a href=\"{$url}\">{$mod}</a></td></tr>\n"; } } $out .= "</table>\n"; # timer readout $time = microtime(true) - $starttime; $out .= sprintf("<p><b>{$count} lines analyzed in %.2f seconds.</b><br>\n", $time); $out .= "\n <span style='font-size: small;'>\n {$total_pages} content pages seen<br>\n {$not_counted} items not counted (images, css, js, admin, etc)<br>\n <!-- {$errors} errors -->\n Stats are updated each minute, and do not include ka-lite or wiki items.\n </span></p>\n "; # download log links $out .= ' <ul> <li><a href="stats.php?dl_alog=1">Download Raw Access Log</a> <li><a href="stats.php?dl_elog=1">Download Raw Error Log</a> </ul> '; # allow clearing logs on the plus if (is_rachelplus()) { $out .= ' <script> function clearLogs() { if (!confirm("Are you sure you want to clear the logs?")) { return false; } $.ajax({ url: "background.php?clearLogs=1", success: function() { $("#clearbut").css("color", "green"); $("#clearbut").html("✔ Logs Cleared"); }, error: function() { $("#clearbut").css("color", "#c00"); $("#clearbut").html("X Internal Error"); } }); } </script> <button type="button" id="clearbut" onclick="clearLogs();">Clear Logs</button> '; } return $out; }
function clearLogs() { if (is_rachelplus()) { exec("rm /var/log/httpd/access_log /var/log/httpd/error_log /media/RACHEL/filteredlog", $out, $rv); $rv = 0; if ($rv == 0) { # make sure they are there (even if empty) in case someone looks) exec("touch /var/log/httpd/access_log /var/log/httpd/error_log", $out, $rv); # now we need to restart the server after clearing the logs # but we need to do that after sending out our response and closing # (found on stackoverflow) ob_end_clean(); header("HTTP/1.1 200 OK"); header("Connection: close"); ignore_user_abort(true); // just to be safe ob_start(); echo "{ \"status\" : \"OK\" }\n"; $size = ob_get_length(); header("Content-Length: {$size}"); ob_end_flush(); // Strange behaviour, will not work flush(); // Unless both are called ! // Do post-processing here //echo "{ \"status\" : \"NOTOK\" }\n"; # client should be closed now exec("killall lighttpd"); # shouldn't ever get here but... exit; } } header("HTTP/1.1 500 Internal Server Error"); exit; }
function kiwix_restart() { if (is_rachelpi()) { exec("sudo service kiwix restart"); } else { if (is_rachelplus()) { exec("bash /root/rachel-scripts/rachelKiwixStart.sh"); } } }