\n"; } else { require_once(dirname(__FILE__).'/init.php'); $res = fs_add_hit__($site_id); if ($close_connection) { $fsdb = &fs_get_db_conn(); $fsdb->disconnect(); fs_get_db_conn(false,true); // clear connection object. } if ($res !== true) { echo "FireStats error : $res"; } } } function fs_add_hit__($site_id, $time = null) { return fs_add_hit_with_with_strategy(FS_COMMIT_STRATEGY, $site_id, $time); } function fs_add_hit_with_with_strategy($commit_strategy, $site_id, $time = null, $is_rss = false) { if ($commit_strategy == FS_COMMIT_BY_OPTION) { $commit_strategy = fs_get_system_option('commit_strategy',FS_COMMIT_IMMEDIATE); } if ($commit_strategy == FS_COMMIT_IMMEDIATE) { if (!$is_rss) { return fs_add_hit_immediate__($site_id, $time); } else { return fs_add_rss_immediate__($site_id, $time); } } else if ($commit_strategy == FS_COMMIT_MANUAL) { return fs_add_hit_delayed__($site_id, $time, $is_rss); } else if ($commit_strategy == FS_COMMIT_AUTOMATIC) { return fs_add_hit_automatic__($site_id, $time, $is_rss); } else { return "FireStats: Unknown commit strategy"; } } function fs_get_hit_data($fsdb,$site_id) { $d = new stdClass(); $remoteaddr = $useragent = $url = $referer = "''"; $site_id = $fsdb->escape(empty($site_id) ? 1 : $site_id); $real_ip = fs_get_ip_address(); $remoteaddr = $fsdb->escape(fs_limited_htmlentities($real_ip)); if (isset($_SERVER['HTTP_USER_AGENT'])) $useragent = $fsdb->escape(fs_limited_htmlentities($_SERVER['HTTP_USER_AGENT'])); // turns out wp likes to add slashes to useragents, which messes things up if (isset($_SERVER['REQUEST_URI'])) $url = $fsdb->escape(fs_limited_htmlentities(fs_get_absolute_url($_SERVER['REQUEST_URI']))); $unescaped_referrer = null; if (isset($_SERVER['HTTP_REFERER'])) { // if referrer is relative, convert it to absolute using the requested URI (see RFC 2616 section 14.36 : http://www.ietf.org/rfc/rfc2616.txt) $unescaped_referrer = fs_get_absolute_url($_SERVER['HTTP_REFERER'], $_SERVER['REQUEST_URI']); $referer = $fsdb->escape(fs_limited_htmlentities($unescaped_referrer)); } $d->ip_address = $real_ip; $d->site_id = $site_id; $d->remoteaddr = $remoteaddr; $d->useragent = $useragent; $d->url = $url; $d->referer= $referer; $d->unescaped_referrer = $unescaped_referrer; return $d; } function fs_add_hit_immediate__($site_id, $time = null) { if (!fs_db_valid()) { return fs_get_database_status_message(); } $fsdb = &fs_get_db_conn(); $d = fs_get_hit_data($fsdb, $site_id); $site_id = $d->site_id; $remoteaddr = $d->remoteaddr; $useragent = $d->useragent; $url = $d->url; $referer = $d->referer; if ($time === null) { $time = "NOW()"; } else { $time = $fsdb->escape($time); } // break ip address (for ipv6 support) $ips = fs_ip2hex($d->ip_address); if ($ips === false) { // set bad ip addresses to 0. // this will allow detection of said ip addresses by the users, and provide a motivation to // investigate the cause for it. $ips = fs_ip2hex("0.0.0.0"); } $ip0 = $ips[0]; $ip1 = $ips[1]; $res = fs_is_excluded_hit($fsdb, $site_id, $ip0, $ip1, $url, $referer, $useragent); if (true === $res) { return true; } if (is_string($res)) return $res; if($fsdb->query("START TRANSACTION") === false) return fs_debug_rollback(); $useragent_id = fs_insert_useragent_hit($fsdb, $useragent); if ($useragent_id === false) return fs_debug_rollback(); $url_id = fs_insert_url_hit($fsdb, $site_id, $url, $time); if ($url_id === false) return fs_debug_rollback(); $referer_id = fs_insert_ref_hit($fsdb, $d->unescaped_referrer, $time); if ($referer_id === false) return fs_debug_rollback(); require_once(dirname(__FILE__).'/ip2country.php'); $ip2c_res = fs_ip2c($d->ip_address, true); $ccode = ($ip2c_res ? $fsdb->escape($ip2c_res) : "NULL"); $hits = fs_hits_table(); // insert to database. $sql = "INSERT IGNORE INTO `$hits` (ip_int1,ip_int2,timestamp,url_id,url_site_id,referer_id,useragent_id,session_id,country_code) VALUES (0x$ip0, 0x$ip1, $time, $url_id, $site_id, $referer_id, $useragent_id, ".(isset($session_id) ? "$session_id" : "NULL").", $ccode )"; if($fsdb->query($sql) === false) return fs_debug_rollback(); if($fsdb->query("COMMIT") === false) return fs_debug_rollback(); return true; } function fs_add_hit_automatic__($site_id, $time, $is_rss = false) { $res = fs_add_hit_delayed__($site_id, $time, $is_rss); if ($res === true) { require_once(FS_ABS_PATH."/lib/sync/mutex.php"); $mutex = new Mutex(__FILE__); $ret = $mutex->lock(); if (is_string($ret)) { return $ret; } $fsdb = &fs_get_db_conn(); $pending = fs_pending_date_table(); $now = time(); if ((((int)$now - (int)fs_get_system_option('firestats_last_automatic_commit_time',0)) > FS_AUTOMATIC_COMMIT_INTERVAL_SECONDS)) { require(FS_ABS_PATH."/php/commit-pending.php"); // not require_once on purpose! fs_update_system_option('firestats_last_automatic_commit_time',$now, true); } $mutex->unlock(); } return $res; } function fs_add_hit_delayed__($site_id, $time, $is_rss = false) { $pending = fs_pending_date_table(); $fsdb = &fs_get_db_conn(); $d = fs_get_hit_data($fsdb, $site_id); $site_id = $d->site_id; $remoteaddr = $d->remoteaddr; $useragent = $d->useragent; $url = $d->url; $referer = $d->referer; if ($time === null) { $time = "NOW()"; } else { $time = $fsdb->escape($time); } $type = $is_rss ? FS_URL_TYPE_RSS : "NULL"; $sql = "INSERT DELAYED INTO `$pending` ( `timestamp`, `site_id` , `url` , `referrer` , `useragent` , `ip`, `type` ) VALUES ( $time, $site_id, $url, $referer, $useragent, $remoteaddr, $type )"; if($fsdb->query($sql) === false) { return fs_db_error(); } return true; } /** * This function returns the best ip address for the client. * the if the client passed through a proxy it tries to detect the correct client ip. * if its a private (LAN) address it uses first public IP (usually the proxy itself). */ function fs_get_ip_address() { // obtain the X-Forwarded-For value. $headers = function_exists('getallheaders') ? getallheaders() : null; $xf = isset($headers['X-Forwarded-For']) ? $headers['X-Forwarded-For'] : ""; if (empty($xf)) { $xf = isset($GLOBALS['FS_X-Forwarded-For']) ? $GLOBALS['FS_X-Forwarded-For'] : ""; } if (empty($xf)) { $xf = $_SERVER['REMOTE_ADDR']; } else { $xf = $xf.",".$_SERVER['REMOTE_ADDR']; } $fwd = explode(",",$xf); foreach($fwd as $ip) { $ip = trim($ip); $ipver = fs_ip_version($ip); if ($ipver == 4) { $long = ip2long($ip); if ($long != -1 && $long !== false) { if (fs_is_public_ipv4($long)) return $ip; } } else { // assume all ipv6 are public. this is incorrect but it's not really that important with the current state of ipv6. return $ip; } } // if we got this far and still didn't find a public ip, just use the first ip address in the chain. return $fwd[0]; } function fs_is_public_ipv4($long) { // 167772160 - 10.0.0.0 // 184549375 - 10.255.255.255 // // -1408237568 - 172.16.0.0 // -1407188993 - 172.31.255.255 // // -1062731776 - 192.168.0.0 // -1062666241 - 192.168.255.255 // // -1442971648 - 169.254.0.0 // -1442906113 - 169.254.255.255 // // 2130706432 - 127.0.0.0 // 2147483647 - 127.255.255.255 (32 bit integer limit!!!) // // -1 is also b0rked if (($long >= 167772160 AND $long <= 184549375) OR ($long >= -1408237568 AND $long <= -1407188993) OR ($long >= -1062731776 AND $long <= -1062666241) OR ($long >= 2130706432 AND $long <= 2147483647) OR $long == -1) { return false; } return true; } function fs_limited_htmlentities($str) { return str_replace (array ( '<', '>'), array ( '<' , '>'), $str); } function fs_debug_rollback() { $fsdb = &fs_get_db_conn(); $msg = sprintf(fs_r('Database error: %s'), $fsdb->last_error)."
\n". sprintf('SQL: %s', $fsdb->last_query); $fsdb->query("ROLLBACK"); echo $msg; return $msg; } function fs_insert_useragent_hit(&$fsdb, $useragent) { $useragents = fs_useragents_table(); // insert to user agent table (no duplicates) $ret = $fsdb->query("INSERT IGNORE INTO `$useragents` (`useragent`,`md5`) VALUES ($useragent ,MD5(`useragent`))"); if($ret === false) { return false; } // get index of useragent in table, can't use LAST_INSERT_ID() here because of the no-dups policy return $fsdb->get_var("SELECT id from `$useragents` WHERE md5 = MD5($useragent)"); } function fs_insert_url_hit(&$fsdb, $site_id, $url, $time, $type = null) { $urls = fs_urls_table(); $type_str = $type != null ? $fsdb->escape($type) : 'NULL'; if($fsdb->query("INSERT IGNORE INTO `$urls` (`url`,`md5`,`add_time`,`type`,`host`) VALUES ($url,MD5(url),$time,$type_str,substring_index(substring_index(`url`,'/',3),'/',-1))") === false) { return false; } // get index of url in table, can't use LAST_INSERT_ID() here because of the no-dups policy $url_id = $fsdb->get_var("SELECT id FROM $urls WHERE md5 = MD5($url)"); if ($url_id === false) return false; // update site id of url to current site id. // this is only done for the url and not for the referrer: // we don't know the site id of the referrer. if it will appear as a url it will be assigned the site_id. if (false === $fsdb->get_var("UPDATE `$urls` SET `site_id` = $site_id WHERE `id` = $url_id")) { return false; } return $url_id; } function fs_insert_ref_hit(&$fsdb, $unescaped_referrer, $time) { $urls = fs_urls_table(); // insert referers into urls table (no duplicates) require_once(FS_ABS_PATH.'/php/searchengines.php'); $search_engine_id = "NULL"; $search_terms = "NULL"; if ($unescaped_referrer != null) { $engine = null; $terms = null; $res = fs_process_search_engine_referrer($unescaped_referrer, $engine, $terms); if ($res === true && !empty($terms)) { $id = $engine->id; if (!empty($id)) $search_engine_id = $fsdb->escape($id); $search_terms = $fsdb->escape($terms); } } $referrer_breakdown = @parse_url($unescaped_referrer); $host = isset($referrer_breakdown['host']); $has_host = $host != null; $optional_host = ($has_host ? ",`host`":""); $host = $fsdb->escape($host); $optional_host_query = ($has_host ? ",$host":""); $referer = $fsdb->escape($unescaped_referrer); if($fsdb->query("INSERT IGNORE INTO `$urls`(`url`,`md5`,`add_time`,`search_engine_id`,`search_terms` $optional_host) VALUES ($referer,MD5(url),$time,$search_engine_id ,$search_terms $optional_host_query)") === false) { return false; } // get index of url in table, can't use LAST_INSERT_ID() here because of the no-dups policy return $fsdb->get_var("SELECT id from $urls WHERE md5 = MD5($referer)"); } function fs_is_excluded_hit(&$fsdb, $site_id, $ip0, $ip1, $url, $referer, $useragent) { $r = fs_is_excluded_ip($fsdb, $ip0, $ip1); if ($r !== false) return $r; $r = fs_is_excluded_useragent($fsdb, $useragent); if ($r !== false) return $r; $r = fs_is_excluded_url_or_referrer($fsdb, $url, $referer); if ($r !== false) return $r; return false; } function fs_is_excluded_url_or_referrer(&$fsdb, $url, $referer) { $excluded_urls = fs_excluded_urls_table(); $ret = $fsdb->get_var("SELECT COUNT(*) FROM $excluded_urls WHERE $referer REGEXP `url_pattern` OR $url REGEXP `url_pattern`"); if ($ret === false) { return fs_db_error(); } return (int)$ret > 0; } function fs_is_excluded_useragent(&$fsdb, $useragent) { $bots = fs_bots_table(); $ret = $fsdb->get_var("SELECT COUNT(*) FROM $bots WHERE $useragent REGEXP `wildcard`"); if ($ret === false) { return fs_db_error(); } return (int)$ret > 0; } function fs_is_excluded_ip(&$fsdb, $ip0, $ip1) { $excluded_ips = fs_excluded_ips_table(); $excluded_ip = $fsdb->get_var("SELECT COUNT(*) FROM `$excluded_ips` WHERE `start_ip1` <= 0x$ip0 AND `end_ip1` >= 0x$ip0 AND `start_ip2` <= 0x$ip1 AND `end_ip2` >= 0x$ip1"); if ($excluded_ip === false) return fs_db_error(); return ((int)$excluded_ip > 0); } function fs_add_rss_feed_hit($site_id, $close_connection = true) { require_once(dirname(__FILE__).'/init.php'); $res = fs_add_rss_feed_hit__($site_id); if ($close_connection) { $fsdb = &fs_get_db_conn(); $fsdb->disconnect(); fs_get_db_conn(false,true); // clear connection object. } if ($res !== true) { echo "FireStats error : $res"; } } function fs_add_rss_feed_hit__($site_id) { $res = fs_add_hit_with_with_strategy(FS_COMMIT_STRATEGY,$site_id, null, true); if ($res === true) { return fs_delete_old_rss_records(); } else { return $res; } } function fs_delete_old_rss_records() { $today = date("l"); if ($today != fs_get_system_option('firestats_last_rss_maintenance_day',"")) { $rss = fs_rss_subscribers_table(); $fsdb = &fs_get_db_conn(); $time = fs_days_ago_to_unix_time(3); // delete records which were updated more than 3 days ago. $res = $fsdb->query("DELETE FROM $rss WHERE `timestamp` < FROM_UNIXTIME($time)"); if ($res === false) return fs_db_error(); fs_update_system_option('firestats_last_rss_maintenance_day',$today, true); } return true; } function fs_add_rss_immediate__($site_id, $time) { $fsdb = &fs_get_db_conn(); $d = fs_get_hit_data($fsdb, $site_id); $site_id = $d->site_id; $remoteaddr = $d->remoteaddr; $useragent = $d->useragent; $url = $d->url; $referer = $d->referer; $ip_address = $d->ip_address; if ($time == null) $time = "NOW()"; // break ip address (for ipv6 support) $ips = fs_ip2hex($ip_address); if ($ips === false) { // set bad ip addresses to 0. // this will allow detection of said ip addresses by the users, and provide a motivation to // investigate the cause for it. $ips = fs_ip2hex("0.0.0.0"); } $ip0 = $ips[0]; $ip1 = $ips[1]; $res = fs_is_excluded_hit($fsdb, $site_id, $ip0, $ip1, $url, $referer, $useragent); if (is_string($res)) return $res; if (true === $res) { return true; } $useragent_id = fs_insert_useragent_hit($fsdb, $useragent); if ($useragent_id === false) return fs_debug_rollback(); $url_id = fs_insert_url_hit($fsdb, $site_id, $url, "NOW()", FS_URL_TYPE_RSS); if ($url_id === false) return fs_debug_rollback(); $r = fs_get_feed_hit_data($useragent, $ip_address); $rss = fs_rss_subscribers_table(); $identifier = $fsdb->escape($r->identifier); $subscribers = $fsdb->escape($r->subscribers); $sql = "REPLACE INTO $rss (`timestamp`,site_id,identifier,url_id,useragent_id,num_subscribers) VALUES ($time,$site_id,$identifier,$url_id,$useragent_id,$subscribers)"; $ret = $fsdb->query($sql); if ($ret === false) { return fs_db_error(); } return true; } ?>