private function upgrade() { $v = isset($this->options['db_version']) ? $this->options['db_version'] : 0; $visits_table = $this->tables['visits']; if ($v && $v < 2) { // upgrade from db version 1 to 2 - platform and browser columns have changed to integer values $ua = new SimpleStatsUA(); foreach ($ua->get_all_browser_names() as $id => $name) { $this->query("UPDATE `{$visits_table}` SET `browser` = '{$id}' WHERE `browser` = '{$name}'"); } $this->query("UPDATE `{$visits_table}` SET `browser` = '1' WHERE `browser` = 'Crawler'"); $this->query("UPDATE `{$visits_table}` SET `browser` = CEIL(`browser`)"); // fixes any we missed $this->query("ALTER TABLE `{$visits_table}` MODIFY `browser` TINYINT UNSIGNED NOT NULL DEFAULT '0'"); foreach ($ua->get_all_platform_names() as $id => $name) { $this->query("UPDATE `{$visits_table}` SET `platform` = '{$id}' WHERE `platform` = '{$name}'"); } $this->query("UPDATE `{$visits_table}` SET `platform` = CEIL(`platform`)"); $this->query("ALTER TABLE `{$visits_table}` MODIFY `platform` TINYINT UNSIGNED NOT NULL DEFAULT '0'"); $this->query("ALTER TABLE `{$visits_table}` ADD KEY `ua`(`browser`, `platform`)"); $this->query("ALTER TABLE `{$visits_table}` ADD KEY `country`(`country`)"); } if ($v && $v < 3) { // save password as hash if (!empty($this->options['password'])) { $this->update_option('password', $this->hash(trim($this->options['password']))); } } if ($v && $v < 4) { // bump referrer field size $this->query("ALTER TABLE `{$visits_table}` MODIFY `referrer` VARCHAR(512) NOT NULL DEFAULT ''"); } if ($v && $v < 5) { // bump ip field size to allow ipv6 addresses $this->query("ALTER TABLE `{$visits_table}` MODIFY `remote_ip` VARCHAR(39) NOT NULL DEFAULT ''"); } if ($v && $v < 6) { // change structure of last_aggregated - used to be yyyymm?, now array with keys yr and mo $parts = $this->options['last_aggregated'] ? str_split($this->options['last_aggregated'], 4) : array(0, 0); $this->update_option('last_aggregated', array('yr' => intval($parts[0]), 'mo' => intval($parts[1]))); } }
function render_page() { global $ss; scripts_i18n(); page_head(); echo '<div id="main">'; echo '<h2>' . __('Latest visitors') . '</h2>'; $page_size = 20; $offset = isset($_GET['offset']) ? abs(intval($_GET['offset'])) : 0; $query = "SELECT * FROM `{$ss->tables['visits']}` ORDER BY `date` DESC, `start_time` DESC LIMIT {$offset},{$page_size}"; $visits = array(); if ($result = $ss->query($query)) { while ($assoc = @mysql_fetch_assoc($result)) { $visits[] = $assoc; } } $ua = new SimpleStatsUA(); echo '<table id="paths" class="center wide" data-offset="' . $offset . '" data-page_size="' . $page_size . '"><thead>'; echo '<tr><th colspan="2" class="left">' . __('IP Address') . '/' . __('Pages'); echo '<th>' . __('Time'); echo '<th>' . __('Browser'); echo '<th>' . __('Operating system'); echo '<th>' . __('Country'); echo '<tbody>'; foreach ($visits as $visit) { $start_ts = strtotime($visit['date'] . ' ' . $visit['start_time']); $hits = explode("\n", $visit['resource']); $dy_label = strftime('%d %b', $start_ts); $start_ts = date('H:i', $start_ts); $full_ua = $ss->options['log_user_agents'] && !empty($visit['user_agent']) ? $visit['user_agent'] : ''; if ($visit['browser'] == 0) { $browser_name = ''; } elseif ($visit['browser'] == 1) { $browser_name = __('(Robot)'); } else { $browser_name = $ua->browser_name_from_id($visit['browser']); } $robot_class = $visit['browser'] == 1 ? ' bot' : ''; $title = $full_ua ? ' title="' . htmlspecialchars($full_ua) . '"' : ''; echo "<tr class='visit-header{$robot_class}'>"; echo '<td colspan="2" class="left">' . htmlspecialchars($visit['remote_ip']); echo '<td>' . $dy_label . '</td>'; echo "<td class='ua'{$title}>" . htmlspecialchars($browser_name) . ' ' . htmlspecialchars($visit['version']); echo '<td>' . htmlspecialchars($ua->platform_name_from_id($visit['platform'])); echo '<td>' . htmlspecialchars(country_name($visit['country'])) . '</tr>'; $row = 0; foreach ($hits as $hit) { if (empty($hit)) { continue; } @(list($time, $resource) = explode(' ', $hit, 2)); // dump the seconds part of the time $time = substr($time, 0, 5); $r = htmlspecialchars($resource); echo '<tr class="hit">'; echo '<td colspan="2" class="left"><a href="' . $r . '" class="goto">→</a> ' . filter_link(array('resource' => $resource), $resource) . "<td>{$time}"; if ($row == 0 && !empty($visit['referrer'])) { echo '<td colspan="3" class="right">'; if (!empty($visit['search_terms'])) { echo filter_link(array('search_terms' => $visit['search_terms']), $visit['search_terms']); } else { echo filter_link(array('domain' => $visit['domain']), $visit['domain']); } echo ' <a href="' . htmlspecialchars($visit['referrer']) . '" rel="external noreferrer" class="goto ext">→</a>'; } else { echo '<td colspan="3"> '; } echo '</tr>'; $row++; } } echo '</table>'; echo '<nav class="center wide hide-if-no-js"><a class="ajax" style="display:block; padding: 5px" id="load-more">— ' . __('more') . ' —</a></nav>'; echo '</div>'; page_foot(); }
function __construct() { $ss = new SimpleStats(); if (!$ss->is_installed() || !$ss->options['stats_enabled'] || isset($_COOKIE['simple_stats']) && $_COOKIE['simple_stats'] == $ss->hash($ss->options['username'] . $ss->options['password'])) { return; } $data = array(); $data['remote_ip'] = substr($this->determine_remote_ip(), 0, 39); // check whether to ignore this hit if (in_array($data['remote_ip'], $ss->options['ignored_ips'])) { return; } $data['resource'] = substr($ss->utf8_encode($this->determine_resource()), 0, 255); $ua = new SimpleStatsUA(); $browser = $ua->parse_user_agent($_SERVER['HTTP_USER_AGENT']); $data['platform'] = $browser['platform']; $data['browser'] = $browser['browser']; $data['version'] = substr($this->parse_version($browser['version']), 0, 15); // check whether to ignore this hit if ($data['browser'] == 1 && $ss->options['log_bots'] == false) { return; } // use DateTime instead of messing with the default timezone which could affect the calling application $tz = new DateTimeZone($ss->options['tz']); $datetime = new DateTime('now', $tz); $date = $data['date'] = $datetime->format('Y-m-d'); $time = $datetime->format('H:i:s'); // attempt to update table $table = $ss->tables['visits']; if ($ss->options['log_user_agents']) { $data['user_agent'] = $ss->esc(substr($_SERVER['HTTP_USER_AGENT'], 0, 255)); } $resource = $ss->esc($time . ' ' . $data['resource']); $ip = $ss->esc($data['remote_ip']); $query = "UPDATE `{$table}` SET hits = hits + 1, resource = CONCAT( resource, '{$resource}', '\\n' ), `end_time` = '{$time}' WHERE `date` = '{$date}' AND remote_ip = '{$ip}'"; if ($ss->options['log_user_agents']) { $query .= " AND user_agent = '{$data['user_agent']}'"; } else { foreach (array('browser', 'version', 'platform') as $key) { $v = $ss->esc($data[$key]); $query .= " AND {$key} = '{$v}'"; } } $query .= " AND TIMEDIFF( '{$time}', start_time ) < '00:30:00' LIMIT 1"; $rows = $ss->query($query); if ($rows == 0) { // this information is only needed for new visitors $data['country'] = $this->determine_country($data['remote_ip']); // always 2 chars, no need to truncate $data['language'] = substr($this->determine_language(), 0, 255); $data['referrer'] = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''; $url = parse_url($data['referrer']); $data['referrer'] = substr($ss->utf8_encode($data['referrer']), 0, 511); $data['domain'] = isset($url['host']) ? substr(preg_replace('/^www\\./', '', $url['host']), 0, 255) : ''; $data['search_terms'] = substr($ss->utf8_encode($this->determine_search_terms($url)), 0, 255); // this isn't actually used at present, but storing local timestamps without a GMT reference is asking for trouble $data['offset'] = $datetime->getOffset() / 60; // store in minutes $query = "INSERT INTO `{$table}` ( "; foreach (array_keys($data) as $key) { if ($key == 'resource') { continue; } $query .= "{$key}, "; } $query .= 'hits, resource, start_time, end_time ) VALUES ( '; foreach ($data as $key => $value) { $value = $ss->esc($value); if ($key == 'resource') { continue; } $query .= "'{$value}', "; } $query .= "'1', CONCAT( '{$resource}', '\\n' ), '{$time}', '{$time}' )"; $ss->query($query); } $ss->close(); }