'admin/logs/browscap', 'title' => t('Browscap'), 'description' => t('Browser-specific site statistics.'), 'callback' => 'browscap_top_useragents', 'callback arguments' => array('all'), 'access' => $access, 'weight' => 5); $items[] = array('path' => 'admin/logs/browscap/useragents', 'title' => t('All user agents'), 'access' => $access, 'weight' => 1, 'type' => MENU_DEFAULT_LOCAL_TASK); $items[] = array('path' => 'admin/logs/browscap/browsers', 'callback' => 'browscap_top_useragents', 'callback arguments' => array('browsers'), 'title' => t('Browsers'), 'access' => $access, 'weight' => 2, 'type' => MENU_LOCAL_TASK); $items[] = array('path' => 'admin/logs/browscap/crawlers', 'callback' => 'browscap_top_useragents', 'callback arguments' => array('crawlers'), 'title' => t('Crawlers'), 'access' => $access, 'weight' => 3, 'type' => MENU_LOCAL_TASK); // SETTINGS PAGE $items[] = array( 'path' => 'admin/settings/browscap', 'title' => t('Browscap'), 'description' => t('Enable browscap site statistics.'), 'callback' => 'drupal_get_form', 'callback arguments' => array('browscap_settings'), 'access' => user_access('administer site configuration'), ); $items[] = array( 'path' => 'admin/settings/browscap/refresh', 'title' => t('Browscap Refresh'), 'callback' => 'browscap_refresh', 'access' => user_access('administer site configuration'), 'type' => MENU_CALLBACK ); } else { if (arg(0) == 'admin' && arg(1) == 'logs' && arg(2) == 'browscap' && arg(3) == 'useragent' && arg(4)) { // INFORMATION ABOUT A USERAGENT $items[] = array( 'path' => 'admin/logs/browscap/useragent', 'callback' => 'browscap_useragent_properties', 'title' => 'Useragent details', 'access' => $access, 'weight' => 5, 'type' => MENU_LOCAL_TASK ); } } return $items; } /** * Implementation of hook_exit(). * * Keep tabs on browsers that visit */ function browscap_exit() { // If monitoring is enabled, record the browser if (variable_get('browscap_monitor', FALSE)) { $browser = browscap_get_browser(); $browserstring = substr(trim($browser['parent']), 0, 255); if ($browserstring == '' or $browserstring == 'Default Browser') { $browserstring = trim($_SERVER['HTTP_USER_AGENT']); } db_query("UPDATE {browscap_statistics} SET counter = counter + 1, is_crawler=%d ". "WHERE parent='%s'", $browser['crawler'], $browserstring); // If we affected 0 rows, this is the first time we've seen this browser if (!db_affected_rows()) { // We must create a new row to store counters for the new browser. db_query('INSERT INTO {browscap_statistics} (parent,counter,is_crawler) '. "VALUES('%s', 1, %d)", $browserstring, $browser['crawler']); } } } /** * Implementation of hook_cron(). */ function browscap_cron() { // Has it been a week since the last (attempt to) import? $last_imported = variable_get('browscap_imported', 0); if (($last_imported + 60*60*24*7) < time()) { _browscap_import(); variable_set('browscap_imported', time()); } } /** * ******************** Menu Callbacks ************************ */ /** * Callback for settings form * Turn monitoring on or off * * @return array */ function browscap_settings() { $form['browscap_monitor'] = array( '#type' => 'checkbox', '#prefix' => t('

Browscap data current as of %fileversion. [Refresh now]

', array( '%fileversion' => variable_get('browscap_version', t('Never fetched')), '!refresh' => url('admin/settings/browscap/refresh'), )), '#title' => t('Monitor browsers'), '#default_value' => variable_get('browscap_monitor', FALSE), '#description' => t('Monitor all user agents visiting the site.') ); return system_settings_form($form); } function browscap_refresh() { _browscap_import(FALSE); drupal_goto('admin/settings/browscap'); } /** * Menu callback; presents the user agents monitoring page. * * @param $view * - "browsers": Only display "real" browsers * - "crawlers": Only display search engine crawlers * - "all": Display all user agents. */ function browscap_top_useragents($view = 'all') { if ($view == 'all') { $result = db_query('SELECT SUM(counter) FROM {browscap_statistics}'); $total = db_result($result); if (!$total) $total = 1; $query = "SELECT parent,counter,(100*counter)/$total as percent,is_crawler FROM {browscap_statistics}"; $query_cnt = 'SELECT COUNT(parent) FROM {browscap_statistics}'; $title = t('Top user agents'); $header = array( array('data' => t('User agent'), 'field' => 'parent'), array('data' => t('Count'), 'field' => 'counter', 'sort' => 'desc'), array('data' => t('Percent'), 'field' => 'percent'), array('data' => t('Crawler?'), 'field' => 'is_crawler') ); } elseif ($view == 'browsers') { $result = db_query('SELECT SUM(counter) FROM {browscap_statistics} WHERE is_crawler=0'); $total = db_result($result); if (!$total) $total = 1; $query = "SELECT parent,counter,(100*counter)/$total as percent FROM {browscap_statistics} WHERE is_crawler=0"; $query_cnt = 'SELECT COUNT(parent) FROM {browscap_statistics} WHERE is_crawler=0'; $title = t('Top browsers'); $header = array( array('data' => t('Browser'), 'field' => 'parent'), array('data' => t('Count'), 'field' => 'counter', 'sort' => 'desc'), array('data' => t('Percent'), 'field' => 'percent') ); } else { $result = db_query('SELECT SUM(counter) FROM {browscap_statistics} WHERE is_crawler=1'); $total = db_result($result); if (!$total) $total = 1; $query = "SELECT parent,counter,(100*counter)/$total as percent FROM {browscap_statistics} WHERE is_crawler=1"; $query_cnt = 'SELECT COUNT(parent) FROM {browscap_statistics} WHERE is_crawler=1'; $title = t('Top crawlers'); $header = array( array('data' => t('Crawler'), 'field' => 'parent'), array('data' => t('Count'), 'field' => 'counter', 'sort' => 'desc'), array('data' => t('Percent'), 'field' => 'percent') ); } drupal_set_title($title); $query .= tablesort_sql($header); $result = pager_query($query, 50, 0, $query_cnt); while ($useragent = db_fetch_object($result)) { if (db_result(db_query_range('SELECT useragent FROM {browscap} WHERE useragent = "%s"', $useragent->parent, 0, 1))) { $parent = l($useragent->parent, 'admin/logs/browscap/useragent/'. urlencode($useragent->parent)); } else { $parent = check_plain($useragent->parent); } if ($view == 'all') { if ($useragent->is_crawler) { $is_crawler = t('Yes'); } else { $is_crawler = t('No'); } $rows[] = array($parent, $useragent->counter, $useragent->percent, $is_crawler); } else { $rows[] = array($parent, $useragent->counter, $useragent->percent); } } if ($pager = theme('pager', NULL, 50, 0)) { $rows[] = array(array('data' => $pager, 'colspan' => 2)); } $output .= theme('table', $header, $rows); print theme('page', $output, $title); } function browscap_get_browser($useragent = NULL) { if (!$useragent) { $useragent = $_SERVER['HTTP_USER_AGENT']; } // Cache the results $cacheid = $useragent; $cache = cache_get($cacheid, 'cache_browscap'); if ((!empty($cache)) and ($cache->created > time() - 60*60*24)) { // Found a fresh entry in the cache $browserinfo = unserialize($cache->data); } else { // Note the 'backwards' use of LIKE - the useragent column contains // the wildcarded pattern to match against our full-length string // The ORDER BY chooses the most-specific matching pattern $browserinfo = db_fetch_object(db_query_range( "SELECT * from {browscap} WHERE '%s' LIKE useragent ORDER BY LENGTH(useragent) DESC", $useragent, 0, 1)); // A couple of fieldnames not in our database, provided for // compatibility with PHP's get_browser() //$browserinfo->tables = $browserinfo->htmltables; cache_set($cacheid, 'cache_browscap', serialize($browserinfo)); } $info = unserialize($browserinfo->data); $info['useragent'] = $useragent; $info['browser_name_pattern'] = strtr($browserinfo->useragent, '%_', '*?'); return $info; } // A numeric interpretation of browscap.csv's TRUE/FALSE/default fields function _browscap_boolean($value) { switch ($value) { case 'TRUE': case 'true': return 1; case 'FALSE': case 'false': case 'default': default: return 0; } } /** * If there's a new version of browscap.csv, fetch it and update the * database. */ function _browscap_import($cron = TRUE) { // Politely check the version for updates before fetching the file $versionpage = drupal_http_request('http://browsers.garykeith.com/versions/version-number.asp'); if ($versionpage->error) { watchdog('browscap', t("Couldn't check version: "). $versionpage->error); if (!$cron) { drupal_set_message(t("Couldn't check version: ") .$versionpage->error, 'error'); } return; } $browscapversion = trim($versionpage->data); $oldversion = variable_get('browscap_version', 'Never fetched'); if ($browscapversion == $oldversion) { // No update, nothing to do here watchdog('browscap', t('No new version of browscap to import')); if (!$cron) { drupal_set_message(t('No new version of browscap to import')); } return; } // Fetch the new version, and dump it in the temp directory $server = $_SERVER['SERVER_NAME']; $path = variable_get('file_directory_temp', '/tmp'); $browscapfile = "$path/browscap_$server.ini"; $browscap = drupal_http_request('http://browsers.garykeith.com/stream.asp?PHP_BrowsCapINI'); if ($browscap->error or !trim($browscap->data)) { watchdog('browscap', t("Couldn't retrieve updated browscap: ") . $browscap->error); if (!$cron) { drupal_set_message(t("Couldn't retrieve updated browscap: ") . $browscap->error); } return; } $browscapfp = fopen($browscapfile, "w"); fwrite($browscapfp, $browscap->data); fclose($browscapfp); $a = parse_ini_file($browscapfile, TRUE); if ($a) { // the first entry in the array is the version info $version = array_shift($a); foreach ($a as $key => $vals) { $e = $vals; // some recursive magic! $last_parent = array(); while ($vals['Parent'] && $vals['Parent'] !== $last_parent) { $vals = $a[$vals['Parent']]; $e = array_merge((array)$vals, (array)$e); $last_parent = $vals; } $useragent = strtr($key, '*?', '%_'); $e = array_change_key_case($e); db_query("REPLACE INTO {browscap} (useragent, data) VALUES('%s','%s')", $useragent, serialize($e)); } cache_clear_all('*', 'cache_browscap', TRUE); variable_set('browscap_version', $browscapversion); watchdog('browscap', t("New version of browscap imported: "). $browscapversion); if (!$cron) { drupal_set_message(t("New version of browscap imported: "). $browscapversion); } } } /* * Undo a recorded browser visit by request * * This function serves the statistics_filter module, enabling it * to ignore visits from specified roles. */ function browscap_unmonitor() { // No point if statistics aren't enabled if (!module_exists('statistics')) { return; } // If monitoring is enabled, unrecord the browser if (variable_get('browscap_monitor', FALSE)) { $browser = browscap_get_browser(); $browserstring = trim($browser->parent); if ($browserstring == '' or $browserstring == 'Default Browser') { $browserstring = trim($_SERVER['HTTP_USER_AGENT']); } db_query("UPDATE {browscap_statistics} SET counter = counter - 1, is_crawler=%d ". "WHERE parent='%s'", $browser->crawler, $browserstring); } } /** * Page callback to show details about known useragents. * * @param string $useragent a useragent, taken from the url. * @return string an HTMl blob representing the data about this useragent. */ function browscap_useragent_properties($useragent = NULL) { drupal_set_title(check_plain(arg(4))); if ($useragent == NULL) { drupal_not_found(); return; } $row = db_fetch_object(db_query('SELECT * FROM {browscap} WHERE useragent = "%s"', $useragent)); if (!$row) { drupal_not_found(); return; } $data = unserialize($row->data); $headers = array(t('property'), t('value')); foreach($data as $key => $val) { $rows[] = array(check_plain($key), check_plain($val)); } $output = theme('table', $headers, $rows); return $output; }