$value) { if (strpos($key, '\\') !== false) { unset($a[$key]); continue; } if (is_string($value)) { $a[$key] = stripslashes($value); } else if (is_array($value)) { self::DeSlashArray($a[$key]); } #$key2 = stripslashes($key); #if ($key2 !== $key) #{ # unset($a[$key]); #} #$a[$key2] = $value; } } // Filters all NUL bytes out of input parameters. // // Some PHP functions have shown vulnerabilities to strings with NUL bytes and since this kind // of data is not expected to be passed as external parameter anyway, all of those are filtered // out. // public static function SetupNull() { // Remove NUL characters from any user input for security reasons self::DeNulArray($_GET); self::DeNulArray($_POST); self::DeNulArray($_REQUEST); self::DeNulArray($_COOKIE); self::DeNulArray($_FILES); } // Removes NUL characters from each array key and value, recursing into sub-arrays. // // This also removes \r characters as part of line breaks on the Windows platform. // // In the past, some of PHP's functions have shown vulnerabilities against NUL values in // strings passed to them. To generally eliminate any attack using this method, all of those // characters are removed from user input data. They are entirely useless for normal operation // anyway. The array passed to this function is modified in-place, so there is no return // value and little data gets copied around. // // in/out a = (array) Array to be processed // private static function DeNulArray(&$a) { foreach ($a as $key => $value) { if (strpos($key, "\x00") !== false) { unset($a[$key]); continue; } if (is_string($value)) { $a[$key] = str_replace(array("\x00", "\r"), array('', ''), $value); } else if (is_array($value)) { self::DeNulArray($a[$key]); } #$key2 = str_replace("\x00", '', $key); #if ($key2 !== $key) #{ # unset($a[$key]); #} #$a[$key2] = $value; } } // Configures PHP register globals setting. // // Since this setting cannot be simply switched off, its effects are actually undone instead. // public static function SetupRegisterGlobals() { // Unregister_globals :) for more security if (ini_get('register_globals')) { if (sizeof($_SESSION)) foreach (array_keys($_SESSION) as $key) unset($GLOBALS[$key]); if (sizeof($_GET)) foreach (array_keys($_GET) as $key) unset($GLOBALS[$key]); if (sizeof($_POST)) foreach (array_keys($_POST) as $key) unset($GLOBALS[$key]); if (sizeof($_COOKIE)) foreach (array_keys($_COOKIE) as $key) unset($GLOBALS[$key]); if (sizeof($_SERVER)) foreach (array_keys($_SERVER) as $key) unset($GLOBALS[$key]); if (is_array($_GET['GLOBALS'])) foreach (array_keys($_GET['GLOBALS']) as $key) unset($GLOBALS[$key]); if (is_array($_POST['GLOBALS'])) foreach (array_keys($_POST['GLOBALS']) as $key) unset($GLOBALS[$key]); } } // Enables HTTP output compression. // public static function EnableHttpCompression() { // Activate page compression if it's not active yet if (!ini_get('zlib.output_compression')) { if (ob_get_level() == 1 && ini_get('output_buffering')) { // The output_buffering PHP configuration has already started an ob level. // This prevents ob_gzhandler to function properly, so just discard that buffer. ob_end_clean(); } ob_start('ob_gzhandler'); } // Ensure that output buffering is turned on if (!ob_get_level()) { ob_start(); } } // Automatically finds related directories around. // private static function FindProjectRoot() { // Find common root of this library and the web page file // This is the absolute project root path $libfile = str_replace('\\', '/', __FILE__); $pagefile = str_replace('\\', '/', $_SERVER['DOCUMENT_ROOT'] . $_SERVER['PHP_SELF']); $projectRoot = substr($libfile, 0, self::strdifferindex($libfile, $pagefile)); if (substr($projectRoot, -1) == '/') $projectRoot = substr($projectRoot, 0, -1); // Cut off trailing slash else $projectRoot = dirname($projectRoot); // Cut off the last part: partially equal dirname // Find project root path level relative to DOCUMENT_ROOT $dir = substr($projectRoot, strlen($_SERVER['DOCUMENT_ROOT'])); if ($dir == '/') $dir = ''; $projectPathDepth = strlen(preg_replace('_[^/]_', '', $dir)); // Find back reference path from current page to project root $dir = dirname($_SERVER['PHP_SELF']); $dir = str_replace('\\', '/', $dir); if ($dir == '/') $dir = ''; $depth = strlen(preg_replace('_[^/]_', '', $dir)); $depth -= $projectPathDepth; self::$backpath = str_repeat('../', $depth); // Different level for the URL if (isset($_SERVER['VIRTUAL_PATH'])) { $dir = ltrim($_SERVER['VIRTUAL_PATH'], '/'); $dir = str_replace('\\', '/', $dir); if ($dir == '/') $dir = ''; $depth = strlen(preg_replace('_[^/]_', '', $dir)); } else { $depth += substr_count($_GET['PATH_INFO'], '/'); #if (basename($_SERVER['PHP_SELF']) == 'index.php' && substr($_SERVER['REQUEST_URI'], -1) != '/') #{ # // Requested directory without trailing /, adapt URL depth to that # $depth--; #} } self::$backurl = str_repeat('../', $depth); // Find path to library files relative to project root self::$libpath = substr(dirname($libfile), strlen($projectRoot) + 1) . '/'; // + 1 to skip the leading slash self::$backlibpath = self::$backpath . self::$libpath; self::$backliburl = self::$backurl . self::$libpath; // Find project root relative to DOCUMENT_ROOT (to which PHP_SELF is relative) // Used for me() function self::$projectRootToDocRoot = substr($projectRoot, strlen($_SERVER['DOCUMENT_ROOT'])); if (isset($_SERVER['VIRTUAL_PATH'])) { $name = $_SERVER['VIRTUAL_PATH']; } else { $name = substr($_SERVER['PHP_SELF'], strlen(self::$projectRootToDocRoot)); } $n = strpos($name, '/'); if ($n !== false) { $name = substr($name, $n + 1); } // Extract the selected language from the first path level, if present if (self::$firstPathLanguage && preg_match('_^([a-z]{2}(-[A-Z]{2})?)(/|$)_', $name, $m)) { self::$pageLanguage = $m[1]; } else if (self::$firstPathLanguage && preg_match('_^(lang)/_', $name, $m)) { // Only the language path level is virtual, // read the selected language from the rewritten LANG parameter self::$pageLanguage = $_GET['LANG']; } // Cut off leading language specification, if it is one if (self::$firstPathLanguage) { if ($n = strpos($name, '/')) { $name = substr($name, $n + 1); } else if (self::$pageLanguage) { // Probably just "en" without the trailing / $name = 'index'; } } // Cut off .php file name extension, if present if (substr($name, -4) == '.php') { $name = substr($name, 0, -4); } self::$pageBaseName = $name; } // Find at what character index both strings differ first. // // Used in FindProjectRoot(). // // Returns (int) zero-based index of the first different character, or -1 if both strings are equal. // private static function strdifferindex($a, $b) { for ($i = 0; $i < min(strlen($a), strlen($b)); $i++) { if ($a{$i} != $b{$i}) return $i; } if (strlen($a) == strlen($b)) return -1; return $i; } // Gets the path to the project root, relative to the currently requested web page. // // Example: "../../" // public static function BackPath() { return self::$backpath; } // Gets the URL to the project root, relative to the currently requested web page. // // Example: "../../" // public static function BackUrl() { return self::$backurl; } // Gets the path to the language pages root, relative to the currently requested web page. // // Example: "../../en/" // public static function BackLangPath() { if (self::$firstPathLanguage) return self::$backpath . self::$pageLanguage . '/'; else return self::$backpath; } // Gets the URL to the language pages root, relative to the currently requested web page. // // Example: "../../en/" // public static function BackLangUrl() { if (self::$firstPathLanguage) return self::$backurl . self::$pageLanguage . '/'; else return self::$backurl; } // Gets the path to the library files, relative to the project root. // // Example: "unb_lib/" // public static function LibPath() { return self::$libpath; } // Gets the path to the library files, relative to the currently requested web page. // // Example: "../../unb_lib/" // public static function BackLibPath() { return self::$backlibpath; } // Gets the URL to the library files, relative to the currently requested web page. // // Example: "../../unb_lib/" // public static function BackLibUrl() { return self::$backliburl; } // Gets the path to the project root, relative to the web server's DOCUMENT_ROOT. // // Example: "project/" // public static function ProjectRootToDocRoot() { return self::$projectRootToDocRoot; } // Gets the full path and file base name of the currently requested web page relative to the // project root and without the .php extension. // // noIndex = (bool) true to replace the page base name "index" with "./" // public static function PageBaseName($noIndex = false) { $name = self::$pageBaseName; if ($noIndex && $name == 'index') $name = './'; else if ($noIndex && substr($name, -6) == '/index') $name = substr($name, 0, -5); return $name; } // Gets the language code of the currently requested web page. // // This will return the first path level relative to the project root. It is only supported // if firstPathLanguage has been set. // public static function PageLanguage() { return self::$pageLanguage; } // Gets the referer URL for this request. // public static function GetReferrer() { return isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''; } // Gets a value indicating whether the referer URL is on the same domain as this page. // // Returns (bool) // public static function IsRefererMyDomain() { $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''; if (preg_match('_^https?://(.*?)/_i', $referer, $m)) { $referer = $m[1]; // find domain from referer $me = $_SERVER['SERVER_NAME']; // find our own server name if (!strcasecmp(substr($me, 0, 4), 'www.')) $me = substr($me, 4); // remove www. prefix if (!strcasecmp(substr($referer, 0, 4), 'www.')) $referer = substr($referer, 4); return !strcasecmp($me, $referer); // compare both domains } return false; } // Gets the client IP address // public static function GetClientAddress() { $addr = $_SERVER['HTTP_X_FORWARDED_FOR']; // HTTP proxy if (!isset($addr) || !preg_match('_^(([0-9]{1,3}\.){3}[0-9]{1,3}|[0-9a-f]+:[0-9a-f:]*)$_i', $addr) || preg_match('_^(0\.|10\.|127\.|169\.254\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.|255\.255\.255\.255|f[cd][0-9a-f]{2}:)_i', $addr)) { // Don't accept invalid or local IP addresses, use real remote address instead $addr = $_SERVER['REMOTE_ADDR']; } return $addr; } // Gets the client's language preferences. // // Returns an array of all language codes, sorted by descending priority. The most preferred // language code is in the first item, the least preferred is in the last item. All language // codes are normalised to the form "aa" or "aa-AA". // public static function GetClientLanguages() { $languageCodes = array(); $priorities = array(); $acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE']; while (preg_match('/^\s*([a-z]{2})(?:[-_]([a-z]{2}))?(?:;\s*q\s*=\s*(\d+(?:\.\d+)?))?(?:\s*,\s*(.*))?$/i', $acceptLanguage, $m)) { $acceptLanguage = $m[4]; $languageCodes[] = strtolower($m[1]) . ($m[2] ? '-' . strtoupper($m[2]) : ''); $priorities[] = $m[3] ? intval(floatval($m[3]) * 100) : 100; } array_multisort($priorities, SORT_DESC, SORT_NUMERIC, $languageCodes); return $languageCodes; } // Gets the client's platform identifier containing the client application (browser) and operating // system as known. // // String format is "@". // Each component is a hierarchical string separated by a slash (/). // Browser format is usually "//". // OS format is usually "//". // For a full reference see the $names and $osmap arrays in the function implementation. // public static function GetClientPlatform() { if (isset(self::$clientPlatform)) return self::$clientPlatform; $raw_ua = $_SERVER['HTTP_USER_AGENT']; // References: // http://www.zytrax.com/tech/web/browser_ids.htm // http://www.zytrax.com/tech/web/mobile_ids.html // (and my own log files) // Determine browser and version $names = array( 'Slurp' => 'search', 'ZyBorg' => 'search', 'Ask Jeeves' => 'search/askjeeves', 'Googlebot' => 'search/google', 'Google Web Preview' => 'search/google', 'Mediapartners-Google' => 'search/google', 'Opera Mini' => 'opera/mini', 'Opera Mobi' => 'opera/mobile', 'Opera' => 'opera/opera', 'iCab' => 'icab', 'OmniWeb' => 'webkit/omniweb', 'Avant Browser' => 'ie/avant', 'Maxthon' => 'ie/maxthon', 'MSIEMobile' => 'ie/mobile', 'IEMobile' => 'ie/mobile', 'MSIE' => 'ie/ie', 'Galeon' => 'galeon', 'Firebird' => 'gecko/ff', 'Firefox' => 'gecko/ff', 'Minefield' => 'gecko/ff', 'Iceweasel' => 'gecko/ff', 'Thunderbird' => 'gecko/ff', 'Fennec' => 'gecko/fennec', 'chromeframe' => 'webkit/chrome/frame', 'Chromium' => 'webkit/chrome/chromium', 'Chrome' => 'webkit/chrome', 'Mobile Safari' => 'webkit/mobile', 'Safari' => 'webkit/safari', 'AppleWebKit' => 'webkit', 'Konqueror' => 'webkit/konq', 'Chimera' => 'gecko/camino', 'Camino' => 'gecko/camino', 'K-Meleon' => 'gecko/kmeleon', 'UCBrowser' => 'ucbrowser', 'UC Browser' => 'ucbrowser', 'Kindle' => 'kindle', 'Lynx' => 'text/lynx', 'ELinks' => 'text/elinks', 'Links' => 'text/links', 'w3m' => 'text/w3m', 'msnbot' => 'search/ms', 'bingbot' => 'search/ms', 'ConveraMultiMediaCrawler' => 'search', 'Spider' => 'search', 'Scooter' => 'search', 'WebCrawler' => 'search', 'crawler' => 'search', 'WiseCrawler' => 'search', 'LinkWalker' => 'search', 'Nutch' => 'search', 'Powermarks' => 'app', 'findlinks' => 'bot', // http://wortschatz.uni-leipzig.de/findlinks/ 'Indy Library' => 'bot', 'Jetbot' => 'bot', 'ia_archiver' => 'bot/archive', 'Python-urllib' => 'bot', 'Gigabot' => 'bot', 'Firefly' => 'bot', 'ichiro' => 'bot', 'lwp-trivial' => 'bot', 'LWP::Simple' => 'bot/perl', 'RI Checker' => 'bot', 'Spinn3r' => 'bot', 'Wget' => 'app/download', 'DA 4' => 'app/download', 'NetAnts' => 'app/download', 'Mass Downloader' => 'app/download', 'GetRight' => 'app/download', 'PHP' => 'bot/php', 'APT-HTTP' => 'app/download/apt', 'robot' => 'bot', 'psbot' => 'bot', 'bot' => 'bot', 'Seznam screenshot-generator' => 'bot', 'Gecko' => 'gecko', 'Netscape' => 'gecko/nn', 'Mozilla' => 'gecko/nn', ); $platform = 'unknown'; foreach ($names as $ua => $name) { if (stristr($raw_ua, $ua)) { // UA signature matched $platform = $name; // Determine version if ($ua == 'Gecko') $ua = 'rv:'; else if ($ua == 'Netscape') $ua .= '[0-9]?[ /]'; else if (($ua == 'Opera' || $ua == 'Opera Mini' || $ua == 'Opera Mobi') && stristr($raw_ua, 'Version/')) $ua = 'Version/'; // Fix for Opera 10+ stuck versions at 9.80 else if ($ua == 'Safari' && stristr($raw_ua, 'Version/')) $ua = 'Version/'; // Fix for Safari weird versions else if ($ua == 'Avant Browser' || $ua == 'Maxthon') $ua = 'MSIE'; // Actually IE with another UI else if ($ua == 'UCBrowser' || $ua == 'UC Browser') $ua .= ''; // No separator to version number else $ua .= '[ /]'; if (preg_match('~' . $ua . '([0-9.]+)~', $raw_ua, $m)) { if (preg_match('~^webkit/chrome~', $platform)) { // Shorten version number to 2 segments (x.y) $parts = explode('.', $m[1]); while (count($parts) > 2) array_pop($parts); $m[1] = join('.', $parts); } $platform .= '/' . $m[1]; } break; } } if (preg_match('_^ie/ie/([0-9.]+)_', $platform, $m)) { $ieVer = $m[1]; // Check for inconsistent data from compatibility mode if (preg_match('_Trident/([0-9.]+)_', $raw_ua, $m)) { $tridentVer = $m[1]; if (substr($tridentVer, 0, 2) == '4.' && substr($ieVer, 0, 2) != '8.') { $realIEVer = 8; } if (substr($tridentVer, 0, 2) == '5.' && substr($ieVer, 0, 2) != '9.') { $realIEVer = 9; } if (substr($tridentVer, 0, 2) == '6.' && substr($ieVer, 0, 3) != '10.') { $realIEVer = 10; } if ($realIEVer) { $platform = 'ie/ie/' . $realIEVer . '/compat/' . $ieVer; } } } // Determine operating system $osmap = array( 'PalmOS' => 'palm', 'PalmSource' => 'palm', 'webOS' => 'webos', 'Windows Mobile 6\.1' => 'win/mobile/6.1', 'Windows Mobile' => 'win/mobile', 'Windows Phone 6\.5' => 'win/phone/6.5', 'Windows Phone OS 7\.0' => 'win/phone/7', 'Windows Phone OS 7\.5' => 'win/phone/7.5', 'Windows Phone OS 8\.0' => 'win/phone/8.0', 'Windows Phone' => 'win/phone', 'Windows CE' => 'win/ce', 'Windows 95' => 'win/95', 'Win95' => 'win/95', 'Windows 98' => 'win/98', 'Win98' => 'win/98', 'Windows ME' => 'win/me', 'Windows NT 4' => 'win/nt/4', 'Windows NT 5\.0' => 'win/nt/2000', 'Windows NT 5\.1' => 'win/nt/xp', 'Windows NT 5\.2' => 'win/nt/2003', 'Windows NT 6\.0' => 'win/nt/vista', 'Windows NT 6\.1' => 'win/nt/7', 'Windows NT 6\.2' => 'win/nt/8', 'WinNT' => 'win/nt', 'Windows-NT' => 'win/nt', 'Windows NT' => 'win/nt', 'CYGWIN-NT' => 'win/nt', 'Android 4\.1' => 'unix/linux/android/4.1', 'Android 4\.0' => 'unix/linux/android/4.0', 'Android 4' => 'unix/linux/android/4', 'Android 3' => 'unix/linux/android/3', 'Android 2\.3' => 'unix/linux/android/2.3', 'Android 2\.2' => 'unix/linux/android/2.2', 'Android 2\.1' => 'unix/linux/android/2.1', 'Android 2\.0' => 'unix/linux/android/2.0', 'Android 1\.6' => 'unix/linux/android/1.6', 'Android 1\.5' => 'unix/linux/android/1.5', 'Android' => 'unix/linux/android', 'Linux' => 'unix/linux', 'Embedix' => 'unix/linux/mobile', 'FreeBSD' => 'unix/freebsd', 'Unix' => 'unix', 'iPad;.*(iPhone|CPU) OS 6_0' => 'mac/ipad/6.0', 'iPad;.*(iPhone|CPU) OS 6' => 'mac/ipad/6', 'iPad;.*(iPhone|CPU) OS 5_1' => 'mac/ipad/5.1', 'iPad;.*(iPhone|CPU) OS 5_0' => 'mac/ipad/5.0', 'iPad;.*(iPhone|CPU) OS 5' => 'mac/ipad/5', 'iPad;.*(iPhone|CPU) OS 4_3' => 'mac/ipad/4.3', 'iPad;.*(iPhone|CPU) OS 4_2' => 'mac/ipad/4.2', 'iPad;.*(iPhone|CPU) OS 4' => 'mac/ipad/4', 'iPad;.*(iPhone|CPU) OS 3_2' => 'mac/ipad/3.2', 'iPad;.*(iPhone|CPU) OS 3' => 'mac/ipad/3', 'iPad;.*(iPhone|CPU) OS' => 'mac/ipad', 'iPhone OS 6_0' => 'mac/iphone/6.0', 'iPhone OS 6' => 'mac/iphone/6', 'iPhone OS 5_1' => 'mac/iphone/5.1', 'iPhone OS 5_0' => 'mac/iphone/5.0', 'iPhone OS 5' => 'mac/iphone/5', 'iPhone OS 4_3' => 'mac/iphone/4.3', 'iPhone OS 4_2' => 'mac/iphone/4.2', 'iPhone OS 4_1' => 'mac/iphone/4.1', 'iPhone OS 4_0' => 'mac/iphone/4.0', 'iPhone OS 4' => 'mac/iphone/4', 'iPhone OS 3_1' => 'mac/iphone/3.1', 'iPhone OS 3_0' => 'mac/iphone/3.0', 'iPhone OS 3' => 'mac/iphone/3', 'iPhone OS 2_2' => 'mac/iphone/2.2', 'iPhone OS 2_1' => 'mac/iphone/2.1', 'iPhone OS 2_0' => 'mac/iphone/2.0', 'iPhone OS 2' => 'mac/iphone/2', 'iPhone OS 1' => 'mac/iphone/1', 'iPhone' => 'mac/iphone', 'Mac OS X 10[._]9' => 'mac/x/10.9', 'Mac OS X 10[._]8' => 'mac/x/10.8', 'Mac OS X 10[._]7' => 'mac/x/10.7', 'Mac OS X 10[._]6' => 'mac/x/10.6', 'Mac OS X 10[._]5' => 'mac/x/10.5', 'Mac OS X 10[._]4' => 'mac/x/10.4', 'Mac OS X 10[._]3' => 'mac/x/10.3', 'Mac OS X 10[._]2' => 'mac/x/10.2', 'Mac OS X 10[._]1' => 'mac/x/10.1', 'Mac OS X' => 'mac/x', 'Mac' => 'mac', 'Darwin' => 'mac', 'BlackBerry' => 'blackberry', 'RIM Tablet OS' => 'blackberry', 'Symbian' => 'symbian', 'SunOS' => 'unix/sun', 'NokiaN8' => 'symbian/3', 'NokiaN70' => 'symbian/s60', 'OS/2' => 'os2', 'Win' => 'win', 'MIDP' => 'java/me/midp', 'J2ME' => 'java/me', 'Java' => 'java', ); $os = ''; foreach ($osmap as $name => $v) { if (preg_match('~' . $name . '~i', $raw_ua)) { $os = $v; break; } } // Append CPU architecture if (stristr($raw_ua, 'PPC Mac OS X')) $os .= '/ppc'; else if (stristr($raw_ua, 'Intel Mac OS X')) $os .= '/intel'; else if (stristr($raw_ua, 'Mac_PowerPC')) $os .= '/ppc'; else if (preg_match('_win/_', $os) && stristr($raw_ua, 'Trident/') && stristr($raw_ua, 'ARM;')) // IE on Win RT $os .= '/arm'; if ($os != '') $platform .= '@' . $os; self::$clientPlatform = $platform; return $platform; } // Gets the version of the client's browser application. // // Returns the full version identifier string spanning digits and dots (.) or 0 if the version // cannot be determined. // public static function GetClientVersion() { if (isset(self::$clientVersion)) return self::$clientVersion; self::$clientVersion = 0; $platform = self::GetClientPlatform(); list($name, $os) = explode('@', $platform); if (preg_match('~/([0-9.]+)/compat~', $name, $m)) // IE compatibility mode self::$clientVersion = $m[1]; else if (preg_match('~/([0-9.]+)[^/]*$~', $name, $m)) self::$clientVersion = $m[1]; return self::$clientVersion; } // Determines whether the client platform matches the specified selector. // // The selector is matched for browser and OS separately. Only the specified parts are regarded. // Each component is matched from the beginning of the client's browser/OS. Only complete string // parts are matched, ie "web" does not match "webkit/chrome/5.0" but "webkit" and "*/chrome" do. // All matching is done case-insensitive. To match the OS only, leave out the browser and start // the selector with the @ character. // public static function IsClientPlatform($selector) { // Get and prepare all data $platform = self::GetClientPlatform(); list($name, $os) = explode('@', $platform); list($sel_name, $sel_os) = explode('@', $selector); // Make selector regex-safe and convert * wildcard $sel_name = preg_replace('[~\\^$.\\[\\]|()?+{}]', '\\$1', $sel_name); $sel_name = str_replace('*', '[^/]*', $sel_name); $sel_os = preg_replace('[~\\^$.\\[\\]|()?+{}]', '\\$1', $sel_os); $sel_os = str_replace('*', '[^/]*', $sel_os); // Match selectors against data if ($sel_name != '' && !preg_match('~^' . $sel_name . '(/|$)~i', $name)) return false; if ($sel_os != '' && !preg_match('~^' . $sel_os . '(/|$)~i', $os)) return false; return true; } // Determines whether it is likely that the client is using a real browser with a human sitting in // front of it, rather than an automated bot or other application. // public static function IsBrowser() { if (isset(self::$clientIsBrowser)) return self::$clientIsBrowser; // Compare against a list of user-agent classifications $bots = array( 'search', 'bot', 'app', ); self::$clientIsBrowser = true; foreach ($bots as $bot) { if (self::IsClientPlatform($bot)) { self::$clientIsBrowser = false; } } // If we still think it's a browser, take a look at the hostname if (self::$clientIsBrowser) { $hostName = gethostbyaddr(self::GetClientAddress()); if (preg_match('_^crawl.*\.archive\.org$_i', $hostName) || preg_match('_^crawl-.*\.googlebot\.com$_i', $hostName) || preg_match('_crawl\.yahoo\.net$_i', $hostName) || preg_match('_^msnbot.*\.search\.msn\.com$_i', $hostName) || preg_match('_^crawler.*\.ask\.com$_i', $hostName)) { self::$clientIsBrowser = false; } } return self::$clientIsBrowser; } // Determines whether the client is on a mobile platform like a smartphone or PDA. // public static function IsMobile() { if (isset(self::$clientIsMobile)) return self::$clientIsMobile; $selectors = array( 'gecko/fennec', 'webkit/mobile', 'opera/mini', 'opera/mobile', 'ie/mobile', 'kindle', '@win/ce', '@unix/linux/android', '@mac/iphone', '@unix/linux/mobile', '@java/me', '@blackberry', '@symbian', ); self::$clientIsMobile = false; foreach ($selectors as $sel) if (self::IsClientPlatform($sel)) self::$clientIsMobile = true; return self::$clientIsMobile; } // Gets the client's best supported XHTML MIME type. // public static function BestXHtml() { // Determine browser XHTML capabilities with HTTP Accept header $accept = explode(',', $_SERVER['HTTP_ACCEPT']); foreach ($accept as $h => $v) { $e = explode(';', $v); $accept[$h] = $e[0]; } if (in_array('application/xhtml+xml', $accept)) return 'application/xhtml+xml'; else if (in_array('text/xml', $accept)) return 'text/xml'; else if (in_array('text/html', $accept)) return 'text/html'; return 'text/html'; } // Gets a value indicating whether the client's best supported XHTML MIME type is XML-based. // // Returns (bool) // public static function IsXml() { return strstr(self::BestXHtml(), 'xml') != false; } // Gets the client's DNT (do not track) preference. // // Returns (bool) true if DNT=1 is set, false if DNT=0 is set or null if DNT is unset. // public static function DoNotTrack() { $dnt = $_SERVER['HTTP_DNT']; if (isset($dnt)) return $_SERVER['HTTP_DNT'] != '0' ? true : false; return null; } // Gets the search terms found in the referer, e.g. if clicked on a search engine link. // // referrer = (string) Different referrer than the automatically detected, like from a JavaScript call. // // Returns (string) Search terms complete string, or null if not a recognised search engine referrer. // public static function GetSearchTerms($referrer = null) { if (!isset(self::$searchTerms) || isset($referrer)) { if (!isset($referrer)) $referrer = self::GetReferrer(); self::$searchTerms = null; self::$searchEngine = null; self::$searchImageUrl = null; self::$searchPageNumber = null; $url = parse_url($referrer); $q = ''; parse_str($url['query'], $arr); if (preg_match('_google\.[a-z]{2,3}(?:\.[a-z]{2,3})?$_i', $url['host'])) { // Referer is Google search if ($url['path'] == '/url' || $url['path'] == '/search') { switch ($arr['source']) { case 'videos': self::$searchEngine = 'Google Videos'; break; case 'newssearch': self::$searchEngine = 'Google News'; break; default: // mostly 'web' self::$searchEngine = 'Google'; break; } $q = $arr['q']; self::$searchPageNumber = intval(intval($arr['cd']) / 10) + 1; } if ($url['path'] == '/m' || $url['path'] == '/m/search') { self::$searchEngine = 'Google Mobile'; $q = $arr['q']; self::$searchPageNumber = intval(intval($arr['cd']) / 10) + 1; // TODO: is it set? "start" } if ($url['path'] == '/cse') { self::$searchEngine = 'Google Custom Search'; $q = $arr['q']; self::$searchPageNumber = intval(intval($arr['cd']) / 10) + 1; // TODO: is it set? } else if ($url['path'] == '/imgres') { // Google image search self::$searchEngine = 'Google Images'; $q = $arr['q']; self::$searchImageUrl = urldecode($arr['imgurl']); // NOTE: The imgurl parameter seems to be double-encoded by Google. PHP decodes // it the first time in parse_str, and we do it the second by using // urldecode. self::$searchPageNumber = intval(intval($arr['start']) / 25) + 1; if (!strlen($q)) { // Look deeper... $url = parse_url($arr['prev']); parse_str($url['query'], $arr); $q = $arr['q']; } } } // TODO: Google mobile search (images?): http://www.google.de/m/search?site=images&source=mog&q=... else if (preg_match('_search\.yahoo\.com$_i', $url['host'])) { // Referer is Yahoo search if (substr($url['path'], 0, 7) == '/search') { self::$searchEngine = 'Yahoo'; } else if (substr($url['path'], 0, 7) == '/mobile/s') { self::$searchEngine = 'Yahoo Mobile'; } else if (substr($url['path'], 0, 7) == '/images') { self::$searchEngine = 'Yahoo Images'; } $q = $arr['p']; self::$searchPageNumber = intval(intval($arr['b']) / 10) + 1; } else if (preg_match('_bing\.com$_i', $url['host'])) { // Referer is Microsoft Bing search if ($url['path'] == '/search' || $url['path'] == '/url') { self::$searchEngine = 'Bing'; self::$searchPageNumber = intval(intval($arr['first']) / 10) + 1; } else if ($url['path'] == '/images/search') { self::$searchEngine = 'Bing Images'; // ImageUrl is not available self::$searchPageNumber = intval(intval($arr['first']) / 30) + 1; } $q = $arr['q']; } else if (preg_match('_suche\.web\.de$_i', $url['host']) && $url['path'] == '/search/web/') { // Referer is Web.de search [DE] self::$searchEngine = 'Web.de'; $q = $arr['su']; self::$searchPageNumber = $arr['pageIndex'] ? intval($arr['pageIndex']) : 1; } else if (preg_match('_suche\.gmx\.net$_i', $url['host']) && $url['path'] == '/web') { // Referer is GMX.net search [DE] self::$searchEngine = 'GMX'; $q = $arr['su']; self::$searchPageNumber = $arr['pageIndex'] ? intval($arr['pageIndex']) : 1; } else if (preg_match('_ask\.com$_i', $url['host']) && $url['path'] == '/web') { // Referer is Ask.com search self::$searchEngine = 'Ask.com'; $q = $arr['q']; self::$searchPageNumber = $arr['page'] ? intval($arr['page']) : 1; } else if (preg_match('_yandex\.ru$_i', $url['host']) && $url['path'] == '/yandsearch') { // Referer is Yandex search [RU] self::$searchEngine = 'Yandex.ru'; $q = $arr['text']; self::$searchPageNumber = intval($arr['p']) + 1; } else if (preg_match('_baidu\.com$_i', $url['host']) && $url['path'] == '/s') { // Referer is Baidu search [CN] self::$searchEngine = 'Baidu'; $q = $arr['wd']; self::$searchPageNumber = intval(intval($arr['pn']) / 10) + 1; } else if (preg_match('_scroogle\.org$_i', $url['host']) && $url['path'] == '/cgi-bin/nbbw.cgi') { // Referer is Scroogle search self::$searchEngine = 'Scroogle'; // No additional information available from this site by design } self::$searchTermsArray = array(); if (strlen($q)) { // Undo PHP's data scrambling if necessary if (get_magic_quotes_gpc()) $q = stripslashes($q); // Safety measure, sometimes PHP functions are not binary safe $q = str_replace("\x00", '', $q); // Do some guessing about whether this is the correct format, // maybe we need to urldecode the string once more. if (strpos($q, ' ') === false && // No space substr($q, 0, 1) != '+' && // No + at beginning substr($q, -1) != '+' && // No + at end strpos($q, '++') === false && // No ++ in sequence !preg_match('_%(2[de]|3[0-9]|[46][1-9a-f]|[57][0-9a]|5f)_i', $q) && // No untypical urlencode %## sequence (strpos($q, '+') !== false || preg_match('_%[0-9a-f]{2}_i', $q))) // At least one of + or %## { $q = urldecode($q); } // Allowed urlencode %## hex values are: 00-ff except // 2d (-), 2e (.), 30-39 (0-9), 41-5a (A-Z), 5f (_) and 61-7a (a-z) self::$searchTerms = $q; // Split into array with quotes support if (function_exists('str_getcsv')) $st = str_getcsv($q, ' '); // Supported since PHP 5.3 else $st = explode(' ', $q); foreach ($st as $a) { $a = trim($a); if ($a != '') self::$searchTermsArray[] = $a; } } } return self::$searchTerms; } // Gets the search terms found in the referer, e.g. if clicked on a search engine link. // // Returns (array(string)) Search terms array // // This method only returns a value if the method GetSearchTerms has been called before. // public static function GetSearchTermsArray() { return self::$searchTermsArray; } // Gets the search engine found in the referer, e.g. if clicked on a search engine link. // // Returns (string) Search engine name // // This method only returns a value if the method GetSearchTerms has been called before. // public static function GetSearchEngine() { return self::$searchEngine; } // Gets the URL of the image that was clicked on in an image search. // // Returns (string) Image URL // // This method only returns a value if the method GetSearchTerms has been called before. // public static function GetSearchImageUrl() { return self::$searchImageUrl; } // Gets the page number of the search result in the referer, e.g. if clicked on a search engine link. // // Returns (int) Search result page number, first page is 1 // // This method only returns a value if the method GetSearchTerms has been called before. // public static function GetSearchPageNumber() { return self::$searchPageNumber; } // Gets the local server's operating system class. // public static function GetServerPlatform() { if (substr(strtoupper(PHP_OS), 0, 3) == 'WIN') return 'win'; if (substr(strtoupper(PHP_OS), 0, 5) == 'LINUX') return 'linux'; return ''; } } // class UnbEnvironment ?>