diff --git a/www/resources/views/pages/testhistory.blade.php b/www/resources/views/pages/testhistory.blade.php index ea8c6957bb..77bf3920a9 100644 --- a/www/resources/views/pages/testhistory.blade.php +++ b/www/resources/views/pages/testhistory.blade.php @@ -24,7 +24,7 @@ - + @endif diff --git a/www/resources/views/pages/testhistoryadmin.blade.php b/www/resources/views/pages/testhistoryadmin.blade.php new file mode 100644 index 0000000000..0ad347e1e1 --- /dev/null +++ b/www/resources/views/pages/testhistoryadmin.blade.php @@ -0,0 +1,123 @@ +@extends('default') + +@section('content') + +
+

Test History{{$all}}

+
+
+ View test log for URLs containing + + +

+ @if ($adminish) +    + @endif + @if ($requestIP) + + @endif + @if ($local) + + @endif +    + + +
+
+
+
+ + + + + + + + @if ($includeip) + + @endif + @if ($admin) + + + @endif + + + + + @foreach ($history as + [ + 'guid' => $guid, + 'url' => $url, + 'video' => $video, + 'repeat' => $repeat, + 'private' => $private, + 'newDate' => $newDate, + 'location' => $location, + 'ip' => $ip, + 'testUID' => $testUID, + 'testUser' => $testUser, + 'email' => $email, + 'key' => $key, + 'count' => $count, + 'label' => $label, + 'shortURL' => $shortURL, + 'link' => $link, + 'labelTxt' => $labelTxt, + ]) + + + + + @if ($includeip) + + @endif + + @if ($admin) + @if (isset($testUID)) + + @elseif (isset($email)) + + @elseif (isset($key)) + + @else + + @endif + + @endif + + + + @endforeach +
Select to CompareDate/TimeFromRequested ByUserPage LoadsLabelURL
+ @if (isset($guid) && $video && !($url == "Bulk Test" || $url == "Multiple Locations test")) + + @if ($repeat) + + @endif + @endif + + @if ($private) + + @endif + {{ $newDate }} + @if ($private) + + @endif + {!! $location !!} + @if ($video) + (video) + @endif + {{ $ip }}{{ $testUser }} ({{ $testUID }}){{ $email }}{{ $key }}{{ $count }} + {{ $labelTxt }} + {{ $shortURL }}
+
+
+
+@endsection \ No newline at end of file diff --git a/www/testlog.php b/www/testlog.php index c637f69d20..5a934676f8 100644 --- a/www/testlog.php +++ b/www/testlog.php @@ -5,48 +5,70 @@ // found in the LICENSE.md file. require_once __DIR__ . '/common.inc'; +use WebPageTest\Exception\ForbiddenException; use WebPageTest\Util; -$host = Util::getSetting('host'); -$protocol = $request_context->getUrlProtocol(); +// why are you even here +if ($userIsBot || Util::getSetting('disableTestlog')) { + throw new ForbiddenException(); +} +// login status $is_logged_in = Util::getSetting('cp_auth') && (!is_null($request_context->getClient()) && $request_context->getClient()->isAuthenticated()); +// Redirect logged-in saml users to the hosted test history if one is configured +if (!$is_logged_in && (isset($USER_EMAIL) && Util::getSetting('history_url') && !isset($_REQUEST['local']))) { + header('Location: ' . Util::getSetting('history_url')); + exit; +} + if ($admin || $privateInstall || $is_logged_in) { set_time_limit(0); } else { set_time_limit(60); } -if ($userIsBot || Util::getSetting('disableTestlog')) { - header('HTTP/1.0 403 Forbidden'); - exit; -} +$csv = isset($_GET['f']) && !strcasecmp($_GET['f'], 'csv'); +$priority = (isset($_REQUEST['priority']) && is_numeric($_REQUEST['priority'])) ? intval($_REQUEST['priority']) : null; +$days = (int)($_GET['days'] ?? 7); -$test_history = []; -$default_days = 7; -$days = (int)($_GET["days"] ?? $default_days); +$GLOBALS['tab'] = 'Test History'; +$GLOBALS['page_description'] = 'History of website performance speed tests run on WebPageTest.'; -if ($is_logged_in) { - $test_history = $request_context->getClient()->getTestHistory($days); -} +// +// single user history +// +if (!$csv && ($is_logged_in || (!isset($user) && !isset($_COOKIE['google_email']) && Util::getSetting('localHistory')))) { + if ($is_logged_in) { + $test_history = $request_context->getClient()->getTestHistory($days); + } + $vars = [ + 'is_logged_in' => $is_logged_in, + 'protocol' => $request_context->getUrlProtocol(), + 'host' => Util::getSetting('host'), + 'days' => $days, + 'test_history' => $test_history, + 'priority' => $priority, + 'local' => isset($_REQUEST['local']) && $_REQUEST['local'], + 'body_class' => 'history', + 'page_title' => 'WebPageTest - Test History', -// Redirect logged-in saml users to the hosted test history if one is configured -if (!$is_logged_in && (isset($USER_EMAIL) && Util::getSetting('history_url') && !isset($_REQUEST['local']))) { - header('Location: ' . Util::getSetting('history_url')); - exit; -} + ]; -$page_keywords = array('Log', 'History', 'WebPageTest', 'Website Speed Test'); -$page_description = "History of website performance speed tests run on WebPageTest."; + echo view('pages.testhistory', $vars); + exit(); +} +// +// parse and display /logs/*.log +// in HTML (Blade) or CSV +// $supportsGrep = false; $out = exec('grep --version', $output, $result_code); if ($result_code == 0 && isset($output) && is_array($output) && count($output)) { $supportsGrep = true; } - $from = (isset($_GET["from"]) && strlen($_GET["from"])) ? $_GET["from"] : 'now'; $filter = $_GET["filter"]; $filterstr = $filter ? preg_replace('/[^a-zA-Z0-9 \@\/\:\.\(\))\-\+]/', '', strtolower($filter)) : null; @@ -54,12 +76,9 @@ $all = !empty($_REQUEST['all']); $repeat = !empty($_REQUEST['repeat']); $nolimit = !empty($_REQUEST['nolimit']); -$csv = isset($_GET["f"]) && !strcasecmp($_GET["f"], 'csv'); -$priority = (isset($_REQUEST['priority']) && is_numeric($_REQUEST['priority'])) ? intval($_REQUEST['priority']) : null; if (!$privateInstall && $all && $days > 7 && !strlen(trim($filterstr))) { - header('HTTP/1.0 403 Forbidden'); - exit; + throw new ForbiddenException(); } if (isset($USER_EMAIL) && !isset($user)) { @@ -77,303 +96,213 @@ $includePrivate = isset($_GET["private"]) && (int)$_GET["private"] == 1; } -function check_it($val) -{ - if ($val) { - echo ' checked '; - } -} - -// single user history -if (!$csv && ($is_logged_in || (!isset($user) && !isset($_COOKIE['google_email']) && Util::getSetting('localHistory')))) { - $GLOBALS['tab'] = 'Test History'; - $vars = [ - 'is_logged_in' => $is_logged_in, - 'protocol' => $protocol, - 'host' => $host, - 'days' => $days, - 'test_history' => $test_history, - 'priority' => $priority, - 'local' => isset($_REQUEST['local']) && $_REQUEST['local'], - 'body_class' => 'history', - 'page_title' => 'WebPageTest - Test History', - - ]; - - echo view('pages.testhistory', $vars); - exit(); -} +$history = getHistoryLog($from, $days, $supportsGrep, $all, $filterstr, $onlyVideo, $includePrivate, $repeat, $nolimit); +// CSV results if ($csv) { header("Content-type: text/csv"); echo '"Date/Time","Location","Test ID","URL","Label"' . "\r\n"; -} else { - ?> - - - - - WebPageTest - Test Log - - - - - -

Test History

-
-
- View test log for URLs containing - -
- -    - '; - } - if (isset($_REQUEST['local']) && $_REQUEST['local']) { - echo ''; - } - ?> -    - - - -
-
-
-
- - - - - - - - Requested By'; - } - if ($admin) { - echo ''; - echo ''; - } - ?> - - - - - format("Ymd") . '.log'); - if ($fileName !== false) { - // load the log file into an array of lines - if (isset($lines)) { - unset($lines); + // only track local tests + foreach ($history as + [ + 'guid' => $guid, + 'newDate' => $newDate, + 'location' => $location, + 'url' => $url, + 'label' => $label, + ]) { + if (strncasecmp($guid, 'http:', 5) && strncasecmp($guid, 'https:', 6)) { + echo '"' . $newDate . '","' . $location . '","' . $guid . '","' . str_replace('"', '""', $url) . '","' . $label . '"' . "\r\n"; } - if ($supportsGrep) { - $ok = false; - $patterns = array(); - if (isset($filterstr) && strlen($filterstr)) { - $patterns[] = $filterstr; - } elseif (!$all) { - if (isset($user)) { - $patterns[] = "\t$user\t"; - } - if (isset($owner) && strlen($owner)) { - $patterns[] = "\t$owner\t"; - } + } + exit(); +} + +// HTML results +$vars = [ + 'history' => $history, + 'is_logged_in' => $is_logged_in, + 'days' => $days, + 'priority' => $priority, + 'local' => !empty($_REQUEST['local']), + 'requestIP' => !empty($_REQUEST['ip']), + 'body_class' => 'history', + 'page_title' => 'WebPageTest - Test History', + 'admin' => $admin, + 'adminish' => ($admin || !Util::getSetting('forcePrivate')) && (isset($uid) || (isset($owner) && strlen($owner))), + 'includeip' => $includeip, + 'filter' => $filter, + // checkboxes + 'all' => $all, + 'onlyVideo' => $onlyVideo, + 'repeat' => $repeat, + 'nolimit' => $nolimit, +]; + +echo view('pages.testhistoryadmin', $vars); + +/** + * Retrieves log data from log files in `/logs/.log` + * + * @param string $from The starting date for the log data retrieval, in the format "Ymd." + * @param int $days The number of days of log data to retrieve. + * @param bool $supportsGrep Is `grep` supported by the system. + * @param bool $all Tests from all users + * @param string $filterstr Filter the log data by matching patterns. + * @param bool $onlyVideo Only tests with videos + * @param bool $includePrivate Private tests too + * @param bool $repeat Tests with repeats views. + * @param bool $nolimit Ignore the hard limit of 100 tests (slow) + * + * @return array An array of log data. + */ +function getHistoryLog($from, $days, $supportsGrep, $all, $filterstr, $onlyVideo, $includePrivate, $repeat, $nolimit) +{ + global $user; + global $owner; + global $tz_offset; + + $history = []; + $rowCount = 0; + $done = false; + $totalCount = 0; + $targetDate = new DateTime($from, new DateTimeZone('GMT')); + for ($offset = 0; $offset <= $days && !$done; $offset++) { + // figure out the name of the log file + $fileName = realpath('./logs/' . $targetDate->format("Ymd") . '.log'); + + if ($fileName !== false) { + // load the log file into an array of lines + if (isset($lines)) { + unset($lines); } - if (count($patterns)) { - $command = "grep -a -i -F"; - foreach ($patterns as $pattern) { - $pattern = str_replace('"', '\\"', $pattern); - $command .= " -e " . escapeshellarg($pattern); + if ($supportsGrep) { + $ok = false; + $patterns = array(); + if (isset($filterstr) && strlen($filterstr)) { + $patterns[] = $filterstr; + } elseif (!$all) { + if (isset($user)) { + $patterns[] = "\t$user\t"; + } + if (isset($owner) && strlen($owner)) { + $patterns[] = "\t$owner\t"; + } } - $command .= " '$fileName'"; - exec($command, $lines, $result_code); - if ($result_code === 0 && is_array($lines) && count($lines)) { + + if (count($patterns)) { + $command = "grep -a -i -F"; + foreach ($patterns as $pattern) { + $pattern = str_replace('"', '\\"', $pattern); + $command .= " -e " . escapeshellarg($pattern); + } + $command .= " '$fileName'"; + exec($command, $lines, $result_code); + if ($result_code === 0 && is_array($lines) && count($lines)) { + $ok = true; + } + } else { + $lines = file($fileName); $ok = true; } } else { - $lines = file($fileName); - $ok = true; - } - } else { - $ok = true; - $file = file_get_contents($fileName); - if ($filterstr) { - $ok = false; - if (stristr($file, $filterstr)) { - $ok = true; - } - } - $lines = explode("\n", $file); - unset($file); - } - if (count($lines) && $ok) { - // walk through them backwards - $records = array_reverse($lines); - unset($lines); - foreach ($records as $line) { $ok = true; - if ($filterstr && stristr($line, $filterstr) === false) { + $file = file_get_contents($fileName); + if ($filterstr) { $ok = false; + if (stristr($file, $filterstr)) { + $ok = true; + } } + $lines = explode("\n", $file); + unset($file); + } - if ($ok) { - // tokenize the line - $line_data = tokenizeLogLine($line); - - $date = @$line_data['date']; - $ip = @$line_data['ip']; - $guid = @$line_data['guid']; - $url = htmlentities(@$line_data['url']); - $location = @$line_data['location']; - $private = @$line_data['private']; - $testUID = @$line_data['testUID']; - $testUser = @$line_data['testUser']; - $video = @$line_data['video']; - $label = isset($line_data['label']) ? htmlentities($line_data['label']) : ''; - $o = isset($line_data['o']) ? $line_data['o'] : null; - $key = isset($line_data['key']) ? $line_data['key'] : null; - $count = @$line_data['count']; - $test_priority = @$line_data['priority']; - $email = @$line_data['email']; - - if (!$location) { - $location = ''; + if (count($lines) && $ok) { + // walk through them backwards + $records = array_reverse($lines); + unset($lines); + foreach ($records as $line) { + $ok = true; + if ($filterstr && stristr($line, $filterstr) === false) { + $ok = false; } - if (isset($date) && isset($location) && isset($url) && isset($guid)) { - // Automatically make any URLs with credentials private - if (!$private) { - $atPos = strpos($url, '@'); - if ($atPos !== false) { - $queryPos = strpos($url, '?'); - if ($queryPos === false || $queryPos > $atPos) { - $private = 1; + + if ($ok) { + // tokenize the line + $line_data = tokenizeLogLine($line); + + $date = @$line_data['date']; + $ip = @$line_data['ip']; + $guid = @$line_data['guid']; + $url = @$line_data['url']; + $location = @$line_data['location']; + $private = @$line_data['private']; + $testUID = @$line_data['testUID']; + $testUser = @$line_data['testUser']; + $video = @$line_data['video']; + $label = $line_data['label'] ?? ''; + $o = $line_data['o'] ?? null; + $key = $line_data['key'] ?? null; + $count = @$line_data['count']; + $test_priority = @$line_data['priority']; + $email = @$line_data['email']; + + if (!$location) { + $location = ''; + } + if (isset($date) && isset($location) && isset($url) && isset($guid)) { + // Automatically make any URLs with credentials private + if (!$private) { + $atPos = strpos($url, '@'); + if ($atPos !== false) { + $queryPos = strpos($url, '?'); + if ($queryPos === false || $queryPos > $atPos) { + $private = 1; + } } } - } - // see if it is supposed to be filtered out - if ($private) { - $ok = false; - if ($includePrivate) { - $ok = true; - } elseif ( - (isset($uid) && $uid == $testUID) || - (isset($user) && strlen($user) && !strcasecmp($user, $testUser)) - ) { - $ok = true; - } elseif (isset($owner) && strlen($owner) && $owner == $o) { - $ok = true; + // see if it is supposed to be filtered out + if ($private) { + $ok = false; + if ($includePrivate) { + $ok = true; + } elseif ( + (isset($uid) && $uid == $testUID) || + (isset($user) && strlen($user) && !strcasecmp($user, $testUser)) + ) { + $ok = true; + } elseif (isset($owner) && strlen($owner) && $owner == $o) { + $ok = true; + } } - } - - if ($onlyVideo and !$video) { - $ok = false; - } - if ($ok && isset($priority) && $priority != $test_priority) { - $ok = false; - } + if ($onlyVideo and !$video) { + $ok = false; + } - if ($ok && !$all) { - $ok = false; - if ( - (isset($uid) && $uid == $testUID) || - (isset($user) && strlen($user) && !strcasecmp($user, $testUser)) - ) { - $ok = true; - } elseif (isset($owner) && strlen($owner) && $owner == $o) { - $ok = true; + if ($ok && isset($priority) && $priority != $test_priority) { + $ok = false; } - } - if ($ok) { - $rowCount++; - $totalCount++; - $newDate = strftime('%x %X', $date + ($tz_offset * 60)); - - if ($csv) { - // only track local tests - if (strncasecmp($guid, 'http:', 5) && strncasecmp($guid, 'https:', 6)) { - echo '"' . $newDate . '","' . $location . '","' . $guid . '","' . str_replace('"', '""', $url) . '","' . $label . '"' . "\r\n"; - // flush every 30 rows of data - if ($rowCount % 30 == 0) { - flush(); - ob_flush(); - } - } - } else { - echo ''; - echo ''; - echo ''; - echo ''; - if ($includeip) { - echo ''; + if ($ok && !$all) { + $ok = false; + if ( + (isset($uid) && $uid == $testUID) || + (isset($user) && strlen($user) && !strcasecmp($user, $testUser)) + ) { + $ok = true; + } elseif (isset($owner) && strlen($owner) && $owner == $o) { + $ok = true; } + } + + if ($ok) { + $rowCount++; + $totalCount++; + $newDate = strftime('%x %X', $date + ($tz_offset * 60)); - if ($admin) { - if (isset($testUID)) { - echo ''; - } elseif (isset($email)) { - echo ''; - } elseif (isset($key)) { - echo ''; - } else { - echo ''; - } - echo ""; - } $link = "/results.php?test=$guid"; if (FRIENDLY_URLS) { $link = "/result/$guid/"; @@ -387,42 +316,39 @@ function check_it($val) $labelTxt = mb_substr($labelTxt, 0, 27) . '...'; } - echo ""; - - echo ''; - - // split the tables every 30 rows so the browser doesn't wait for ALL the results - if ($rowCount % 30 == 0) { - echo '
Select to CompareDate/TimeFromUserPage LoadsLabelURL
'; - if (isset($guid) && $video && !($url == "Bulk Test" || $url == "Multiple Locations test")) { - echo ""; - if ($repeat) { - echo ""; - } - } - echo ''; - if ($private) { - echo ''; - } - echo $newDate; - if ($private) { - echo ''; - } - echo '' . $location; - if ($video) { - echo ' (video)'; - } - echo '' . $ip . '' . "$testUser ($testUID)" . '' . htmlspecialchars($email) . '' . htmlspecialchars($key) . '$count"; - echo "$labelTxt "; - echo "' . fittext($url, 80) . '
'; - flush(); - ob_flush(); + $history[] = [ + 'guid' => $guid, + 'url' => $url, + 'video' => $video, + 'repeat' => $repeat, + 'private' => $private, + 'newDate' => $newDate, + 'location' => $location, + 'ip' => $ip, + 'testUID' => $testUID ?? null, + 'testUser' => $testUser ?? null, + 'email' => $email ?? null, + 'key' => $key ?? null, + 'count' => $count, + 'label' => $label, + 'shortURL' => fittext($url, 80), + 'link' => $link, + 'labelTxt' => $labelTxt, + ]; + + if (!$nolimit && $totalCount > 100) { + $done = true; + break; } } - - if (!$nolimit && $totalCount > 100) { - $done = true; - break; - } } } } } } - } - // on to the previous day - $targetDate->modify('-1 day'); + // on to the previous day + $targetDate->modify('-1 day'); + } + return $history; } -if (!$csv) { - ?> -
-
-
- - - - -