run('SELECT * FROM sites WHERE host=:host', [':host'=>$forHost])->fetch(); if (!$site) die('SITE NOT FOUND'); $path = $_GET['path']; $width = $_GET['width']; $isUnique = !empty($_GET['unique']) ? 1 : 0; $isBot = smart_ip_detect_crawler($ua) ? 1 : 0; $info = parse_user_agent($ua); $data[':site_id'] = $site['id']; $data[':ts'] = time(); $data[':path'] = $path; $data[':is_unique'] = $isUnique; $data[':is_bot'] = $isBot; $data[':platform'] = !empty($info['platform']) ? $info['platform'] : 'N/A'; $data[':browser'] = !empty($info['browser']) ? $info['browser'] : 'N/A'; $data[':version'] = !empty($info['version']) ? $info['version'] : 'N/A'; $data[':ref'] = !empty($_GET['ref']) ? $_GET['ref'] : ''; $data[':width'] = !empty($_GET['width']) ? $_GET['width'] : 'N/A'; $pdo->run('INSERT INTO visits (site_id, path, ts, is_unique, is_bot, platform, browser, version, ref, width) VALUES (:site_id, :path, :ts, :is_unique, :is_bot, :platform, :browser, :version, :ref, :width)', $data); if ($config['track_uas']) { $pdo->run('INSERT OR IGNORE INTO uas(ua) VALUES (:ua)', [':ua'=>$ua]); } echo 'OK'; } catch (Exception $exception) { if ($config['debug']) { echo $exception->getMessage(); } echo 'FAIL'; } class MyPDO extends PDO { public function __construct($dsn, $username = NULL, $password = NULL, $options = []) { $default_options = [ PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, ]; $options = array_replace($default_options, $options); parent::__construct($dsn, $username, $password, $options); } public function run($sql, $args = NULL) { if (!$args) { return $this->query($sql); } $stmt = $this->prepare($sql); $stmt->execute($args); return $stmt; } } /** * Parses a user agent string into its important parts * * @param string|null $u_agent User agent string to parse or null. Uses $_SERVER['HTTP_USER_AGENT'] on NULL * @return string[] an array with browser, version and platform keys * @throws \InvalidArgumentException on not having a proper user agent to parse. * * @author Jesse G. Donat * * @link https://donatstudios.com/PHP-Parser-HTTP_USER_AGENT * @link https://github.com/donatj/PhpUserAgent * * @license MIT */ function parse_user_agent( $u_agent = null ) { if( $u_agent === null && isset($_SERVER['HTTP_USER_AGENT']) ) { $u_agent = $_SERVER['HTTP_USER_AGENT']; } if( $u_agent === null ) { throw new \InvalidArgumentException('parse_user_agent requires a user agent'); } $platform = null; $browser = null; $version = null; $empty = array( 'platform' => $platform, 'browser' => $browser, 'version' => $version ); if( !$u_agent ) { return $empty; } if( preg_match('/\((.*?)\)/m', $u_agent, $parent_matches) ) { preg_match_all('/(?PBB\d+;|Android|CrOS|Tizen|iPhone|iPad|iPod|Linux|(Open|Net|Free)BSD|Macintosh|Windows(\ Phone)?|Silk|linux-gnu|BlackBerry|PlayBook|X11|(New\ )?Nintendo\ (WiiU?|3?DS|Switch)|Xbox(\ One)?) (?:\ [^;]*)? (?:;|$)/imx', $parent_matches[1], $result); $priority = array( 'Xbox One', 'Xbox', 'Windows Phone', 'Tizen', 'Android', 'FreeBSD', 'NetBSD', 'OpenBSD', 'CrOS', 'X11' ); $result['platform'] = array_unique($result['platform']); if( count($result['platform']) > 1 ) { if( $keys = array_intersect($priority, $result['platform']) ) { $platform = reset($keys); } else { $platform = $result['platform'][0]; } } elseif( isset($result['platform'][0]) ) { $platform = $result['platform'][0]; } } if( $platform == 'linux-gnu' || $platform == 'X11' ) { $platform = 'Linux'; } elseif( $platform == 'CrOS' ) { $platform = 'Chrome OS'; } preg_match_all('%(?PCamino|Kindle(\ Fire)?|Firefox|Iceweasel|IceCat|Safari|MSIE|Trident|AppleWebKit| TizenBrowser|(?:Headless)?Chrome|YaBrowser|Vivaldi|IEMobile|Opera|OPR|Silk|Midori|Edge|Edg|CriOS|UCBrowser|Puffin|OculusBrowser|SamsungBrowser| Baiduspider|Googlebot|YandexBot|bingbot|Lynx|Version|Wget|curl| Valve\ Steam\ Tenfoot| NintendoBrowser|PLAYSTATION\ (\d|Vita)+) (?:\)?;?) (?:(?:[:/ ])(?P[0-9A-Z.]+)|/(?:[A-Z]*))%ix', $u_agent, $result); // If nothing matched, return null (to avoid undefined index errors) if( !isset($result['browser'][0]) || !isset($result['version'][0]) ) { if( preg_match('%^(?!Mozilla)(?P[A-Z0-9\-]+)(/(?P[0-9A-Z.]+))?%ix', $u_agent, $result) ) { return array( 'platform' => $platform ?: null, 'browser' => $result['browser'], 'version' => isset($result['version']) ? $result['version'] ?: null : null ); } return $empty; } if( preg_match('/rv:(?P[0-9A-Z.]+)/i', $u_agent, $rv_result) ) { $rv_result = $rv_result['version']; } $browser = $result['browser'][0]; $version = $result['version'][0]; $lowerBrowser = array_map('strtolower', $result['browser']); $find = function ( $search, &$key, &$value = null ) use ( $lowerBrowser ) { $search = (array)$search; foreach( $search as $val ) { $xkey = array_search(strtolower($val), $lowerBrowser); if( $xkey !== false ) { $value = $val; $key = $xkey; return true; } } return false; }; $key = 0; $val = ''; if( $browser == 'Iceweasel' || strtolower($browser) == 'icecat' ) { $browser = 'Firefox'; } elseif( $find('Playstation Vita', $key) ) { $platform = 'PlayStation Vita'; $browser = 'Browser'; } elseif( $find(array( 'Kindle Fire', 'Silk' ), $key, $val) ) { $browser = $val == 'Silk' ? 'Silk' : 'Kindle'; $platform = 'Kindle Fire'; if( !($version = $result['version'][$key]) || !is_numeric($version[0]) ) { $version = $result['version'][array_search('Version', $result['browser'])]; } } elseif( $find('NintendoBrowser', $key) || $platform == 'Nintendo 3DS' ) { $browser = 'NintendoBrowser'; $version = $result['version'][$key]; } elseif( $find('Kindle', $key, $platform) ) { $browser = $result['browser'][$key]; $version = $result['version'][$key]; } elseif( $find('OPR', $key) ) { $browser = 'Opera Next'; $version = $result['version'][$key]; } elseif( $find('Opera', $key, $browser) ) { $find('Version', $key); $version = $result['version'][$key]; } elseif( $find('Puffin', $key, $browser) ) { $version = $result['version'][$key]; if( strlen($version) > 3 ) { $part = substr($version, -2); if( ctype_upper($part) ) { $version = substr($version, 0, -2); $flags = array( 'IP' => 'iPhone', 'IT' => 'iPad', 'AP' => 'Android', 'AT' => 'Android', 'WP' => 'Windows Phone', 'WT' => 'Windows' ); if( isset($flags[$part]) ) { $platform = $flags[$part]; } } } } elseif( $find('YaBrowser', $key, $browser) ) { $browser = 'Yandex'; $version = $result['version'][$key]; } elseif( $find(array( 'Edge', 'Edg' ), $key, $browser) ) { $browser = 'Edge'; $version = $result['version'][$key]; } elseif( $find(array( 'IEMobile', 'Midori', 'Vivaldi', 'OculusBrowser', 'SamsungBrowser', 'Valve Steam Tenfoot', 'Chrome', 'HeadlessChrome' ), $key, $browser) ) { $version = $result['version'][$key]; } elseif( $rv_result && $find('Trident', $key) ) { $browser = 'MSIE'; $version = $rv_result; } elseif( $find('UCBrowser', $key) ) { $browser = 'UC Browser'; $version = $result['version'][$key]; } elseif( $find('CriOS', $key) ) { $browser = 'Chrome'; $version = $result['version'][$key]; } elseif( $browser == 'AppleWebKit' ) { if( $platform == 'Android' ) { $browser = 'Android Browser'; } elseif( strpos($platform, 'BB') === 0 ) { $browser = 'BlackBerry Browser'; $platform = 'BlackBerry'; } elseif( $platform == 'BlackBerry' || $platform == 'PlayBook' ) { $browser = 'BlackBerry Browser'; } else { $find('Safari', $key, $browser) || $find('TizenBrowser', $key, $browser); } $find('Version', $key); $version = $result['version'][$key]; } elseif( $pKey = preg_grep('/playstation \d/i', $result['browser']) ) { $pKey = reset($pKey); $platform = 'PlayStation ' . preg_replace('/\D/', '', $pKey); $browser = 'NetFront'; } return array( 'platform' => $platform ?: null, 'browser' => $browser ?: null, 'version' => $version ?: null ); } /** * Check if the given user agent string is one of a crawler, spider, or bot. * * @param string $user_agent * A user agent string (e.g. Googlebot/2.1 (+http://www.google.com/bot.html)) * * @link https://gist.github.com/geerlingguy/a438b41a9a8f988ee106 * * @return bool * TRUE if the user agent is a bot, FALSE if not. */ function smart_ip_detect_crawler($user_agent) { // User lowercase string for comparison. $user_agent = strtolower($_SERVER['HTTP_USER_AGENT']); // A list of some common words used only for bots and crawlers. $bot_identifiers = array( 'bot', 'slurp', 'crawler', 'spider', 'curl', 'facebook', 'fetch', ); // See if one of the identifiers is in the UA string. foreach ($bot_identifiers as $identifier) { if (strpos($user_agent, $identifier) !== FALSE) { return TRUE; } } return FALSE; }