HEX
Server: Apache
System: Linux vps.teamads.com 4.18.0-553.126.1.el8_10.x86_64 #1 SMP Thu May 28 06:44:09 EDT 2026 x86_64
User: teamadsc (1024)
PHP: 8.1.34
Disabled: NONE
Upload Files
File: /home/teamadsc/public_html/wp-content/plugins/visitors/WPHitsCounter.php
<?php

class WPHitsCounterPro
{

	var $pageId;
	var $pageTitle;
	var $postType;
	var $ipAddress;
	var $ipIsUnknown;
	var $userAgent;
	var $referer;
	var $refererSite;
	var $browser;
	var $searchEngine;
	var $countryInternetCode;
	var $countryId;
	var $keyWords;
	var $requestUri;

	/**

	 * Constructor

	 *

	 * @param integer $page_id

	 * @param string $page_title Optional

	 * @param string $post_type Optional

	 */
	public function __construct($page_id, $page_title = NULL, $post_type = NULL)
	{

		global $_SERVER;

		$this->ipAddress = ahcpro_get_client_ip_address();


		if ($this->ipAddress == 'UNKNOWN') {

			$this->ipIsUnknown = true;

			$this->ipAddress = 'UNKNOWN' . uniqid();
		} else {

			$this->ipIsUnknown = false;
		}



		$this->userAgent = $_SERVER['HTTP_USER_AGENT'];

		$this->pageId = (isset($page_id)) ? $page_id : $_GET['page_id'];

		$this->pageTitle = $page_title;

		$this->postType = $post_type;

		$this->requestUri = trim($_SERVER['REQUEST_URI'], '/');

		//$post_permalink = get_the_permalink($this->pageId);
		//$protocol_arr = array('http://','https://','www.');	
		//$link = str_replace($protocol_arr,'',$post_permalink);
		//$this->requestUri = trim(str_replace($_SERVER['HTTP_HOST'],'',$link),'/');

		if (isset($_SERVER['HTTP_REFERER']) && !empty($_SERVER['HTTP_REFERER'])) {

			$hostName = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);

			if ($hostName != $_SERVER['SERVER_NAME']) {

				$this->referer = $_SERVER['HTTP_REFERER'];

				$this->refererSite = $hostName;
			}
		}

		$this->searchEngine = NULL;

		$this->keyWords = NULL;

		$this->countryId = NULL;
	}

	//--------------------------------------------
	//--------------------------------------------

	/**

	 * Trace visitor hit

	 *

	 * @return void

	 */
	public function traceVisitorHit()
	{
		//print_r($this->updateRecentVisitors($this->ipAddress, $this->referer, $this->searchEngine, $this->browser, $this->countryId));
		//echo 'ddddddddddddddddddddddd';
		//print_r($this->isHitRecorded());exit();
		//$this->cleanUnwantedRecords();
		//print_r($this->browser);
		error_log('referer: ' . $this->referer);

		// This always runs regardless of whether hit is recorded
		if (!empty($this->referer)) {
			$this->refererSite = parse_url($this->referer, PHP_URL_HOST);
			$this->getSearchEngine();

			// Track generic referrals only if NOT a known search engine
			if (empty($this->searchEngine) && !empty($this->refererSite)) {
				// Optional: exclude self-referrals
				if ($this->refererSite !== $_SERVER['HTTP_HOST']) {
					$this->updateReferingSites($this->refererSite);
				}
			}
		}

		if (!empty($this->searchEngine)) {
			$this->updateSearchingVisits($this->searchEngine);
		}
		if (!empty($this->keyWords) && !empty($this->searchEngine)) {

			$this->updateKeywords($this->ipAddress, $this->keyWords, $this->referer, $this->searchEngine, $this->browser, $this->countryId);
		}

		if (!$this->isHitRecorded()) {

			$visitorRecorded = $this->isVisitorRecorded();

			$this->getBrowser();

			$this->getCountryId();
			//print_r($this->browser);
			usleep(10000);

			if (!empty($this->refererSite)) {

				$this->getSearchEngine();
			}


			/*
	    if (!$this->isTodayPreparedInDb()) {

		$this->PrepareForTodayInDb();
	    }*/



			if (!$visitorRecorded) {

				$this->updateVisitsTime(1, 1);

				$this->updateVisitors(1, 1);
			} else {

				$this->updateVisitsTime(0, 1);

				$this->updateVisitors(0, 1);
			}


			if (!empty($this->pageId) && !empty($this->pageTitle) && ($this->postType == 'post' or $this->postType == 'product' or $this->postType == 'page')) {



				$this->updateTitleTraffic($this->pageId, $this->pageTitle);
			}



			if (!empty($this->keyWords) && !empty($this->searchEngine)) {

				$this->updateKeywords($this->ipAddress, $this->keyWords, $this->referer, $this->searchEngine, $this->browser, $this->countryId);
			}



			if (!empty($this->refererSite)) {

				$this->updateReferingSites($this->refererSite);
			}



			if (!empty($this->searchEngine)) {

				$this->updateSearchingVisits($this->searchEngine);
			}



			if (!empty($this->countryId)) {

				if ($visitorRecorded) {

					$this->updateCountries($this->countryId, 0, 1);
				} else {

					$this->updateCountries($this->countryId, 1, 1);
				}
			}

			$this->updateBrowsers($this->browser);



			if (!$visitorRecorded) {

				$this->updateRecentVisitors($this->ipAddress, $this->referer, $this->searchEngine, $this->browser, $this->countryId);
			}



			$this->recordThisHits();
		}
	}

	//--------------------------------------------

	/**

	 * Is visit is already recorded

	 *

	 * @return boolean

	 */
	protected function isHitRecorded()
	{

		global $wpdb;
		$custom_timezone_offset = ahcpro_get_current_timezone_offset();

		$wpdb->insert(
			'ahc_online_users',
			array(
				'date'			=> ahcpro_localtime('Y-m-d H:i:s'),
				'hit_ip_address' => $this->ipAddress,
				'hit_page_id'	=>	$this->pageId,
				'site_id'	=>	get_current_blog_id()
			)
		);

		//$sql = "SELECT COUNT(`hit_id`) AS ct  FROM `ahc_hits` WHERE DATE(`hit_date`) = '". ahcpro_localtime("Y-m-d") ."' AND `hit_ip_address` = %s AND `hit_page_id` = %s";

		$sql = "SELECT COUNT(`hit_id`) AS ct FROM `ahc_hits` WHERE DATE(CONVERT_TZ(CONCAT_WS(' ',hit_date,hit_time),'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "')) = '" . ahcpro_localtime("Y-m-d") . "' AND `hit_ip_address` = %s AND `hit_page_id` = %s  AND `site_id` = %d ";

		$result = $wpdb->get_results($wpdb->prepare($sql, $this->ipAddress, $this->pageId, get_current_blog_id()), OBJECT);

		if ($result !== false) {

			return ((int) $result[0]->ct > 0);
		}
	}

	//--------------------------------------------

	/**

	 * Is visitor is already recorded

	 *

	 * @return boolean

	 */
	protected function isVisitorRecorded()
	{

		global $wpdb;

		$custom_timezone_offset = ahcpro_get_current_timezone_offset();

		/*$sql = "SELECT COUNT(`hit_id`) AS ct  FROM `ahc_hits` WHERE DATE(`hit_date`) = '". gmdate("Y-m-d") ."' AND `hit_ip_address` = %s";*/

		$sql = "SELECT COUNT(`hit_id`) AS ct  FROM `ahc_hits` WHERE site_id = " . get_current_blog_id() . " and DATE(CONVERT_TZ(CONCAT_WS(' ',hit_date,hit_time),'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "')) = '" . ahcpro_localtime("Y-m-d") . "' AND `hit_ip_address` = %s";

		$result = $wpdb->get_results($wpdb->prepare($sql, $this->ipAddress), OBJECT);
		if ($result !== false) {

			return ((int) $result[0]->ct > 0);
		}
	}

	//--------------------------------------------

	/**

	 * Detect client browser

	 *

	 * @return void

	 */
	public function get_browser_id($browser)
	{
		global $wpdb;
		$sql = "SELECT `bsr_id` FROM `ahc_browsers` WHERE `bsr_name` = %s and site_id = %d ";

		$results = $wpdb->get_results($wpdb->prepare($sql, $browser, get_current_blog_id()), OBJECT);

		if ($results !== false && !empty($results)) {
			return $results[0]->bsr_id;
		}
		return 0;
	}
	protected function getBrowser()
	{

		if (strpos($this->userAgent, 'MSIE') !== false) {

			$this->browser = $this->get_browser_id('IE');
		} elseif (strpos($this->userAgent, 'Trident') !== false) {

			$this->browser = $this->get_browser_id('IE');
		} elseif (strpos($this->userAgent, 'Gecko') !== false) {

			if (strpos($this->userAgent, 'Firefox') !== false) {

				$this->browser = $this->get_browser_id('Firefox');
			} elseif (strpos($this->userAgent, 'Netscape') !== false) {

				$this->browser = $this->get_browser_id('Netscape');
			} elseif (strpos($this->userAgent, 'OPR') !== false || strpos($this->userAgent, 'Opera') !== false) {

				$this->browser = $this->get_browser_id('Opera');
			} elseif (strpos($this->userAgent, 'Edg') !== false) {

				$this->browser = $this->get_browser_id('Edge');
			} elseif (strpos($this->userAgent, 'Chrome') !== false) {

				$this->browser = $this->get_browser_id('Chrome');
			} else {

				$this->browser = $this->get_browser_id('Gecko/Mozilla');
			}
		} elseif (strpos($this->userAgent, 'Opera Mini') !== false) {

			$this->browser = $this->get_browser_id('Opera Mini');
		} elseif (strpos($this->userAgent, 'Opera') !== false) {

			$this->browser = $this->get_browser_id('Opera');
		} elseif (strpos($this->userAgent, 'Safari') !== false) {

			$this->browser = $this->get_browser_id('Safari');
		} elseif (strpos($this->userAgent, 'iPad') !== false) {

			$this->browser = $this->get_browser_id('iPad');
		} elseif (strpos($this->userAgent, 'Android') !== false) {

			$this->browser = $this->get_browser_id('Android');
		} elseif (strpos($this->userAgent, 'AIR') !== false) {

			$this->browser = $this->get_browser_id('AIR');
		} elseif (strpos($this->userAgent, 'Fluid') !== false) {

			$this->browser = $this->get_browser_id('Fluid');
		} elseif (strpos($this->userAgent, 'Maxthon') !== false) {

			$this->browser = $this->get_browser_id('Maxthon');
		} else {

			$this->browser = $this->get_browser_id('unknown');
		}
	}

	//--------------------------------------------

	/**

	 * Detect country internet code

	 *

	 * @return void

	 */
	/*protected function getCountryInternetCode()
	{
		if (!$this->ipIsUnknown) {
			// Performance: Use only 2 APIs - primary and fallback
			$apis = array(
				// Primary: ipapi.co - Fast, reliable, 1000 requests/day free
				array(
					'url' => "https://ipapi.co/{$this->ipAddress}/json/",
					'country_field' => 'country_code',
					'timeout' => 3
				),
				// Fallback: ip-api.com - Fast, reliable, unlimited free
				array(
					'url' => "http://ip-api.com/json/{$this->ipAddress}",
					'country_field' => 'countryCode',
					'timeout' => 5
				)
			);

			// Performance: Try primary, then fallback if needed
			foreach ($apis as $api) {
				try {
					$ip_data = $this->optimized_get_link($api['url'], $api['timeout']);

					if (!empty($ip_data)) {
						$country_code = isset($ip_data->{$api['country_field']}) ? trim($ip_data->{$api['country_field']}) : '';

						// Performance: If we get valid country code, use it and stop
						if (!empty($country_code) && $country_code != 'null' && strlen($country_code) == 2) {
							$this->countryInternetCode = strtoupper($country_code);
							return; // Performance: Exit immediately when we have valid data
						}
					}
				} catch (Exception $e) {
					// Performance: Log error only in debug mode
					if (defined('WP_DEBUG') && WP_DEBUG) {
						error_log("Country code API error for {$api['url']}: " . $e->getMessage());
					}
					continue;
				}
			}
		}

		// Fallback to unknown country
		if (empty($this->countryInternetCode)) {
			$this->countryInternetCode = 'XX';
		}
	}*/
	
	protected function getCountryInternetCode()
{
	if (!$this->ipIsUnknown) {
		// Performance: Use only 2 APIs - primary and fallback
		$apis = array(
			// Primary: ipapi.co - Fast, reliable, 1000 requests/day free
			array(
				'url' => "https://ipapi.co/{$this->ipAddress}/json/",
				'country_field' => 'country_code',
				'timeout' => 3
			),
			// Fallback: ipwho.is
			array(
				'url' => "https://ipwho.is/{$this->ipAddress}",
				'country_field' => 'country_code',
				'timeout' => 5
			)
		);

		// Performance: Try primary, then fallback if needed
		foreach ($apis as $api) {
			try {
				$ip_data = $this->optimized_get_link($api['url'], $api['timeout']);

				if (!empty($ip_data) && (!isset($ip_data->success) || $ip_data->success === true)) {
					$country_code = isset($ip_data->{$api['country_field']}) ? trim($ip_data->{$api['country_field']}) : '';

					// Performance: If we get valid country code, use it and stop
					if (!empty($country_code) && $country_code != 'null' && strlen($country_code) == 2) {
						$this->countryInternetCode = strtoupper($country_code);
						return;
					}
				}
			} catch (Exception $e) {
				// Performance: Log error only in debug mode
				if (defined('WP_DEBUG') && WP_DEBUG) {
					error_log("Country code API error for {$api['url']}: " . $e->getMessage());
				}
				continue;
			}
		}
	}

	// Fallback to unknown country
	if (empty($this->countryInternetCode)) {
		$this->countryInternetCode = 'XX';
	}
}
	private function optimized_get_link($url, $timeout = 5)
	{
		// Performance: Check if we have a cached result (optional - implement if needed)
		$cache_key = 'geo_' . md5($url);
		$cached = wp_cache_get($cache_key, 'geolocation');
		if ($cached !== false) {
			return $cached;
		}

		// Performance: Use WordPress HTTP API with optimized settings
		$args = array(
			'timeout' => $timeout,
			'redirection' => 2, // Limit redirects
			'httpversion' => '1.1',
			'user-agent' => 'Mozilla/5.0 (compatible; WordPressBotGeo/1.0)',
			'headers' => array(
				'Accept' => 'application/json',
				'Accept-Encoding' => 'gzip, deflate'
			),
			'compress' => true,
			'decompress' => true,
			'sslverify' => false // Performance: Skip SSL verification for speed (consider security implications)
		);

		$response = wp_remote_get($url, $args);

		// Performance: Quick error checking
		if (is_wp_error($response)) {
			throw new Exception('HTTP request failed: ' . $response->get_error_message());
		}

		$response_code = wp_remote_retrieve_response_code($response);
		if ($response_code !== 200) {
			throw new Exception('HTTP error: ' . $response_code);
		}

		$body = wp_remote_retrieve_body($response);
		if (empty($body)) {
			throw new Exception('Empty response body');
		}

		// Performance: Parse JSON response
		$data = json_decode($body);
		if (json_last_error() !== JSON_ERROR_NONE) {
			throw new Exception('Invalid JSON response');
		}

		// Performance: Cache successful results for 1 hour
		wp_cache_set($cache_key, $data, 'geolocation', 3600);

		return $data;
	}
	//--------------------------------------------

	/**

	 * Detect country ID

	 *

	 * @uses wpdb::prepare()

	 * @uses wpdb::get_results()

	 *

	 * @return void

	 */
	protected function getCountryId()
	{

		global $wpdb;

		$this->getCountryInternetCode();

		if (!empty($this->countryInternetCode)) {

			$sql = "SELECT `ctr_id` FROM `ahc_countries` WHERE `ctr_internet_code` = %s and site_id = %d ";

			$results = $wpdb->get_results($wpdb->prepare($sql, $this->countryInternetCode, get_current_blog_id()), OBJECT);

			if ($results !== false && !empty($results)) {

				$this->countryId = $results[0]->ctr_id;

				return;
			}
		}
	}

	//--------------------------------------------

	/**

	 * Detect search engine

	 *

	 * @uses wpdb::prepare()

	 * @uses wpdb::get_results()

	 *

	 * @return void

	 */
	protected function getSearchEngine()
	{

		global $wpdb;

		$sql = "SELECT `srh_id`, `srh_query_parameter`, `srh_identifier` FROM `ahc_search_engines`";

		$results = $wpdb->get_results($sql, OBJECT);

		if ($results !== false) {

			foreach ($results as $s) {

				if (strpos($this->referer, $s->srh_identifier . '.') !== false) {

					$this->searchEngine = $s->srh_id;

					$this->getKeyWords($s->srh_query_parameter);
				}
			}
		}
	}

	//--------------------------------------------

	/**

	 * Detect search engine

	 *

	 * @uses wpdb::prepare()

	 * @uses wpdb::get_results()

	 *

	 * @return void

	 */
	protected function getKeyWords($query_param)
	{

		$query = parse_url($this->referer, PHP_URL_QUERY);

		$query = rawurldecode($query);

		$arr = array();

		parse_str($query, $arr);

		if (isset($arr[$query_param])) {

			$this->keyWords = $arr[$query_param];
		}
	}

	//--------------------------------------------

	/**

	 * Is there a record prepared for today's visits

	 *

	 * @uses wpdb::get_results()

	 *

	 * @return boolean

	 */
	protected function isTodayPreparedInDb()
	{

		global $wpdb;

		$del_sql = "DELETE v1 FROM ahc_visitors v1, ahc_visitors v2 WHERE v1.`vst_id` > v2.`vst_id` AND v1.`vst_date` = v2.`vst_date`";

		//$del_sql = "DELETE v1 FROM ahc_visitors v1, ahc_visitors v2 WHERE v1.`vst_id` > v2.`vst_id` AND CONVERT_TZ(v1.vst_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "') = CONVERT_TZ(v2.vst_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "') ";

		$del_result = $wpdb->get_results($del_sql, OBJECT);


		$sql = "SELECT COUNT(`vst_id`) AS ct  FROM `ahc_visitors` WHERE site_id = " . get_current_blog_id() . " DATE(`vst_date`) = '" . gmdate("Y-m-d") . "'";

		//$sql = "SELECT COUNT(`vst_id`) AS ct  FROM `ahc_visitors` WHERE DATE(CONVERT_TZ(vst_date,'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "')) = DATE(CONVERT_TZ(NOW( ),'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "'))";

		$result = $wpdb->get_results($sql, OBJECT);

		if ($result !== false) {

			return ((int) $result[0]->ct > 0);
		}
	}

	//--------------------------------------------

	/**

	 * Prepared a record for today's visits

	 *

	 * @uses wpdb::query()

	 *

	 * @return boolean

	 */
	protected function PrepareForTodayInDb()
	{

		global $wpdb;

		$sql = "INSERT INTO `ahc_visitors` (`vst_date`, `vst_visitors`, `vst_visits`, `site_id`) VALUES ('" . gmdate("Y-m-d H:i:s") . "', 0, 0,'" . get_current_blog_id() . "')";

		if ($wpdb->query($sql) !== false) {

			return true;
		}

		return false;
	}

	//--------------------------------------------

	/**

	 * Clean daily hits table

	 *

	 * @uses wpdb::query()

	 *

	 * @return boolean

	 */
	public function cleanHitsTable()
	{
		global $wpdb;

		// Get current time using saved timezone and calculate 90 days ago
		$current_time = $this->getCurrentLocalTime();

		try {
			$timezone = new DateTimeZone($current_time['timezone']);
			$datetime = new DateTime('now', $timezone);
			$datetime->modify('-90 days');
			$threshold_date = $datetime->format('Y-m-d H:i:s');
		} catch (Exception $e) {
			// Fallback calculation using saved timezone
			$threshold_date = date('Y-m-d H:i:s', strtotime('-90 days'));
		}

		// Delete from ahc_online_users where date is older than 90 days
		$sql1 = $wpdb->prepare("DELETE FROM ahc_online_users WHERE `date` < %s", $threshold_date);
		$wpdb->query($sql1);

		// Delete from ahc_hits where hit_date is older than 90 days
		$sql2 = $wpdb->prepare("DELETE FROM `ahc_hits` WHERE `hit_date` < %s", $threshold_date);
		return ($wpdb->query($sql2) !== false);
	}

	//--------------------------------------------

	/**

	 * Update browser visits

	 *

	 * @uses wpdb::prepare()

	 * @uses wpdb::query()

	 *

	 * @param integer $bsr_id

	 * @return boolean

	 */
	protected function updateBrowsers($bsr_id)
	{

		global $wpdb;

		$sql = "UPDATE `ahc_browsers` SET bsr_visits = bsr_visits + 1 WHERE bsr_id = %d and site_id=%d";
		//print_r($sql);
		if ($wpdb->query($wpdb->prepare($sql, $bsr_id, get_current_blog_id())) !== false) {

			return true;
		}

		return false;
	}

	//--------------------------------------------

	/**

	 * Update country visits

	 *

	 * @uses wpdb::prepare()

	 * @uses wpdb::query()

	 *

	 * @param integer $ctr_id

	 * @param integer $visitors Optional

	 * @param integer $visits Optional

	 * @return boolean

	 */
	protected function updateCountries($ctr_id, $visitors = 0, $visits = 0)
	{

		global $wpdb;

		$sql = "UPDATE `ahc_countries` SET ctr_visitors = ctr_visitors + %d, ctr_visits = ctr_visits + %d WHERE ctr_id = %d and site_id = %d";

		return ($wpdb->query($wpdb->prepare($sql, $visitors, $visits, $ctr_id, get_current_blog_id())) !== false);
	}

	//--------------------------------------------

	/**

	 * Update visits sum order by search engine

	 *

	 * @uses wpdb::prepare()

	 * @uses wpdb::get_results()

	 * @uses wpdb::query()

	 *

	 * @param integer $srh_id

	 * @return boolean

	 */
	protected function updateSearchingVisits($srh_id)
	{
		global $wpdb;

		// Get current time using saved timezone
		$current_time = $this->getCurrentLocalTime();
		$custom_timezone_offset = ahcpro_get_current_timezone_offset();

		$sql = "SELECT vtsh_id FROM `ahc_searching_visits` WHERE site_id = %d AND srh_id = %d AND DATE(vtsh_date) = '" . $current_time['date'] . "'";

		$result = $wpdb->get_results($wpdb->prepare($sql, get_current_blog_id(), $srh_id), OBJECT);

		if ($result !== false) {
			if ($wpdb->num_rows > 0) {
				$sql2 = "UPDATE `ahc_searching_visits` SET vtsh_visits = vtsh_visits + 1 WHERE vtsh_id = %d and site_id=%d";
				return ($wpdb->query($wpdb->prepare($sql2, $result[0]->vtsh_id, get_current_blog_id())) !== false);
			} else {
				$sql2 = "INSERT INTO `ahc_searching_visits` (srh_id, vtsh_date, vtsh_visits,site_id) 
                    VALUES (%d, %s, 1,%d)";
				return ($wpdb->query($wpdb->prepare($sql2, $srh_id, $current_time['full'], get_current_blog_id())) !== false); // FIXED: Use saved timezone
			}
		} else {
			return false;
		}
	}


	//--------------------------------------------

	/**

	 * Update visitors count

	 *

	 * @uses wpdb::prepare()

	 * @uses wpdb::query()

	 *

	 * @param integer $visitors Optional

	 * @param integer $visits Optional

	 * @return boolean

	 */
	protected function updateVisitors($visitors = 0, $visits = 0)
	{
		global $wpdb;

		// Get current time using saved timezone
		$current_time = $this->getCurrentLocalTime();

		$sql = "INSERT INTO `ahc_daily_visitors_stats` (vst_date, vst_visitors, vst_visits,site_id) values(%s, %d, %d, %d )";
		$wpdb->query($wpdb->prepare($sql, $current_time['full'], $visitors, $visits, get_current_blog_id())); // FIXED: Use saved timezone

		$sql = "INSERT INTO `ahc_visitors` (vst_date, vst_visitors, vst_visits,site_id) values(%s, %d, %d , %d )";
		return ($wpdb->query($wpdb->prepare($sql, $current_time['full'], $visitors, $visits, get_current_blog_id())) !== false); // FIXED: Use saved timezone
	}

	//--------------------------------------------

	/**

	 * Update referring sites visits table

	 *

	 * @uses wpdb::prepare()

	 * @uses wpdb::query()

	 * @uses wpdb::get_results()

	 *

	 * @param string $rfr_site_name. referring site name

	 * @return boolean

	 */
	protected function updateReferingSites($rfr_site_name)
	{

		global $wpdb;

		$sql = "SELECT rfr_id FROM `ahc_refering_sites` where rfr_site_name = %s and site_id=%d";

		$result = $wpdb->get_results($wpdb->prepare($sql, $rfr_site_name, get_current_blog_id()), OBJECT);

		if ($result !== false) {

			if (!empty($result)) {

				$sql2 = "UPDATE `ahc_refering_sites` SET rfr_visits = rfr_visits + 1 WHERE rfr_id = %d and site_id=%d";

				return ($wpdb->query($wpdb->prepare($sql2, $result[0]->rfr_id, get_current_blog_id())) !== false);
			} else {

				$sql2 = "INSERT INTO `ahc_refering_sites` (rfr_site_name, rfr_visits,site_id) 

						VALUES(%s, 1,%d)";

				return ($wpdb->query($wpdb->prepare($sql2, $rfr_site_name, get_current_blog_id())) !== false);
			}
		} else {

			return false;
		}
	}

	//--------------------------------------------

	/**

	 * Update recent visitors table

	 *

	 * @uses wpdb::prepare()

	 * @uses wpdb::query()

	 *

	 * @param string $vtr_ip_address. IP address

	 * @param string $vtr_referer Optional. Referring site name

	 * @param integer $srh_id Optional. Search engine ID

	 * @param integer $bsr_id Optional. Browser ID

	 * @param integer $ctr_id Optional. Country ID

	 * @return boolean

	 */
	/*protected function updateRecentVisitors($vtr_ip_address, $vtr_referer = '', $srh_id = NULL, $bsr_id = NULL, $ctr_id = NULL)
	{
		global $wpdb;

		// Get current time using saved timezone
		$current_time = $this->getCurrentLocalTime();

		$ahc_city = '';
		$ahc_region = '';

		// Performance: Use only 2 APIs - primary and fallback
		$apis = array(
			// Primary: ipapi.co - Fast, reliable, 1000 requests/day free
			array(
				'url' => "https://ipapi.co/{$vtr_ip_address}/json/",
				'city_field' => 'city',
				'region_field' => 'region',
				'timeout' => 3 // Quick timeout for performance
			),
			// Fallback: ip-api.com - Fast, reliable, unlimited free (non-commercial)
			array(
				'url' => "http://ip-api.com/json/{$vtr_ip_address}",
				'city_field' => 'city',
				'region_field' => 'regionName',
				'timeout' => 5 // Slightly longer timeout for fallback
			)
		);

		// Performance: Try only primary, then fallback if needed
		foreach ($apis as $api) {
			try {
				// Performance: Add timeout to prevent slow responses
				$ip_data = $this->optimized_get_link($api['url'], $api['timeout']);
				if (!empty($ip_data)) {
					$city = isset($ip_data->{$api['city_field']}) ? trim($ip_data->{$api['city_field']}) : '';
					$region = isset($ip_data->{$api['region_field']}) ? trim($ip_data->{$api['region_field']}) : '';
					// Performance: If we get valid data, use it and stop
					if (!empty($city) && $city != 'null' && strlen($city) > 1) {
						$ahc_city = $city;
					}
					if (!empty($region) && $region != 'null' && strlen($region) > 1) {
						$ahc_region = $region;
					}
					// Performance: If we got city data, we're done (don't need to try fallback)
					if (!empty($ahc_city)) {
						break;
					}
				}
			} catch (Exception $e) {
				// Performance: Log error only in debug mode to avoid overhead
				if (defined('WP_DEBUG') && WP_DEBUG) {
					error_log("Geolocation API error for {$api['url']}: " . $e->getMessage());
				}
				continue;
			}
		}

		// Performance: Use prepared statement with proper placeholders
		$sql = "INSERT INTO `ahc_recent_visitors`
        (vtr_ip_address, vtr_referer, srh_id, bsr_id, ctr_id, ahc_city, ahc_region, vtr_date, vtr_time, site_id)
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %d)";

		return ($wpdb->query($wpdb->prepare(
			$sql,
			$vtr_ip_address,
			$vtr_referer,
			$srh_id,
			$bsr_id,
			$ctr_id,
			$ahc_city,
			$ahc_region,
			$current_time['date'],    // FIXED: Use saved timezone instead of gmdate
			$current_time['time'],    // FIXED: Use saved timezone instead of gmdate
			get_current_blog_id()
		)) !== false);
	}*/
	
	protected function updateRecentVisitors($vtr_ip_address, $vtr_referer = '', $srh_id = NULL, $bsr_id = NULL, $ctr_id = NULL)
{
	global $wpdb;

	// Get current time using saved timezone
	$current_time = $this->getCurrentLocalTime();

	$ahc_city = '';
	$ahc_region = '';

	// Performance: Use only 2 APIs - primary and fallback
	$apis = array(
		// Primary: ipapi.co - Fast, reliable, 1000 requests/day free
		array(
			'url' => "https://ipapi.co/{$vtr_ip_address}/json/",
			'city_field' => 'city',
			'region_field' => 'region',
			'timeout' => 3
		),
		// Fallback: ipwho.is
		array(
			'url' => "https://ipwho.is/{$vtr_ip_address}",
			'city_field' => 'city',
			'region_field' => 'region',
			'timeout' => 5
		)
	);

	// Performance: Try only primary, then fallback if needed
	foreach ($apis as $api) {
		try {
			$ip_data = $this->optimized_get_link($api['url'], $api['timeout']);

			if (!empty($ip_data) && (!isset($ip_data->success) || $ip_data->success === true)) {
				$city = isset($ip_data->{$api['city_field']}) ? trim($ip_data->{$api['city_field']}) : '';
				$region = isset($ip_data->{$api['region_field']}) ? trim($ip_data->{$api['region_field']}) : '';

				if (!empty($city) && $city != 'null' && strlen($city) > 1) {
					$ahc_city = $city;
				}
				if (!empty($region) && $region != 'null' && strlen($region) > 1) {
					$ahc_region = $region;
				}

				if (!empty($ahc_city)) {
					break;
				}
			}
		} catch (Exception $e) {
			if (defined('WP_DEBUG') && WP_DEBUG) {
				error_log("Geolocation API error for {$api['url']}: " . $e->getMessage());
			}
			continue;
		}
	}

	// Performance: Use prepared statement with proper placeholders
	$sql = "INSERT INTO `ahc_recent_visitors`
	(vtr_ip_address, vtr_referer, srh_id, bsr_id, ctr_id, ahc_city, ahc_region, vtr_date, vtr_time, site_id)
	VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %d)";

	return ($wpdb->query($wpdb->prepare(
			$sql,
			$vtr_ip_address,
			$vtr_referer,
			$srh_id,
			$bsr_id,
			$ctr_id,
			$ahc_city,
			$ahc_region,
			$current_time['date'],    // FIXED: Use saved timezone instead of gmdate
			$current_time['time'],    // FIXED: Use saved timezone instead of gmdate
			get_current_blog_id()
		)) !== false);
}
	//--------------------------------------------

	/**

	 * Update key words table

	 *

	 * @uses wpdb::prepare()

	 * @uses wpdb::query()

	 *

	 * @param string $vtr_ip_address. IP address

	 * @param string $kwd_keywords. Key word

	 * @param string $kwd_referer. Referring site name.

	 * @param integer $srh_id. Search engine ID

	 * @param integer $bsr_id. Browser ID

	 * @param integer $ctr_id Optional. Country ID

	 * @return boolean

	 */
	protected function updateKeywords($kwd_ip_address, $kwd_keywords, $kwd_referer, $srh_id, $bsr_id, $ctr_id = NULL)
	{
		global $wpdb;

		// Get current time using saved timezone
		$current_time = $this->getCurrentLocalTime();

		$sql = "INSERT INTO `ahc_keywords` (kwd_ip_address, kwd_keywords, kwd_referer, srh_id, ctr_id, bsr_id, kwd_date, kwd_time,site_id) 
            VALUES (%s, %s, %s, %d, %d, %d, %s, %s, %d)";

		return ($wpdb->query($wpdb->prepare(
			$sql,
			$kwd_ip_address,
			$kwd_keywords,
			$kwd_referer,
			$srh_id,
			$ctr_id,
			$bsr_id,
			$current_time['date'],    // FIXED: Use saved timezone instead of gmdate
			$current_time['time'],    // FIXED: Use saved timezone instead of gmdate
			get_current_blog_id()
		)) !== false);
	}

	//--------------------------------------------

	/**

	 * Clean unwanted records. Only keeping a limit of fresh records. Limit is set by AHCPRO_RECENT_VISITORS_LIMIT

	 *

	 * @uses wpdb::prepare()

	 * @uses wpdb::get_results()

	 * @uses wpdb::query()

	 *

	 * @return boolean

	 */
	protected function cleanUnwantedRecords()
	{

		global $wpdb;

		$sql11 = "SELECT vtr_id FROM `ahc_recent_visitors` where site_id = %d ORDER BY vtr_id LIMIT %d";

		$result = $wpdb->get_results($wpdb->prepare($sql11, get_current_blog_id(), AHCPRO_RECENT_VISITORS_LIMIT), OBJECT);

		if ($result !== false) {

			$ids1 = array();

			$length = count($result);

			foreach ($result as $r) {

				$ids1[] = $r->vtr_id;
			}

			$ids1 = implode(',', $ids1);

			$sql12 = "DELETE FROM `ahc_recent_visitors`" . ((!empty($ids1)) ? " WHERE site_id = " . get_current_blog_id() . " and vtr_id NOT IN (" . $ids1 . ")" : "");



			$sql21 = "SELECT kwd_id FROM `ahc_keywords` where site_id=%d ORDER BY kwd_id LIMIT %d";

			$result2 = $wpdb->get_results($wpdb->prepare($sql21, get_current_blog_id(), AHCPRO_RECENT_KEYWORDS_LIMIT), OBJECT);

			if ($result2 !== false) {

				$ids2 = array();

				foreach ($result2 as $r) {

					$ids2[] = $r->kwd_id;
				}

				$ids2 = implode(',', $ids2);

				$sql22 = "DELETE FROM `ahc_keywords`" . ((!empty($ids2)) ? " WHERE kwd_id NOT IN (" . $ids2 . ")" : "");



				if ($wpdb->query($sql12) !== false) {

					return ($wpdb->query($sql22) !== false);
				}
			}
		}

		return false;
	}

	//--------------------------------------------

	/**

	 * Update traffic by title table

	 *

	 * @uses wpdb::prepare()

	 * @uses wpdb::get_results()

	 * @uses wpdb::query()

	 *

	 * @param integer $til_page_id

	 * @param string $til_page_title

	 * @return boolean

	 */
	protected function updateTitleTraffic($til_page_id, $til_page_title)
	{

		global $wpdb;

		$sql = "SELECT til_id FROM `ahc_title_traffic` where til_page_id = %s and site_id=%d";

		$result = $wpdb->get_results($wpdb->prepare($sql, $til_page_id, get_current_blog_id()), OBJECT);
		if ($result !== false) {

			if (!empty($result)) {

				$sql2 = "UPDATE `ahc_title_traffic` 

						SET til_hits = til_hits + 1, til_page_title = %s 

						WHERE til_id = %d and site_id = %d";

				return ($wpdb->query($wpdb->prepare($sql2, $til_page_title, $result[0]->til_id, get_current_blog_id())) !== false);
			} else {

				$sql2 = "INSERT INTO `ahc_title_traffic` (til_page_id, til_page_title, til_hits,site_id)  

						VALUES(%s, %s, 1, %d)";

				return ($wpdb->query($wpdb->prepare($sql2, $til_page_id, $til_page_title, get_current_blog_id())) !== false);
			}
		} else {

			return false;
		}
	}

	//--------------------------------------------

	/**

	 * Update visitor's & visits' times table

	 *

	 * @uses wpdb::prepare()

	 * @uses wpdb::query()

	 *

	 * @param integer $visitors Optional

	 * @param integer $visits Optional

	 * @return boolean

	 */
	protected function updateVisitsTime($visitors = 0, $visits = 0)
	{
		global $wpdb;

		// Get current time using saved timezone
		$current_time = $this->getCurrentLocalTime();
		$time = $current_time['time']; // FIXED: Use saved timezone instead of gmdate

		$sql = "UPDATE `ahc_visits_time` SET vtm_visitors = vtm_visitors + %d, vtm_visits = vtm_visits + %d 
				WHERE  TIME(vtm_time_from) <= '$time' AND TIME(vtm_time_to) >= '$time' and site_id=" . get_current_blog_id();
		$query = $wpdb->prepare($sql, $visitors, $visits);
		$result = ($wpdb->query($query) !== false);

		$sql = "UPDATE `ahc_visits_time` SET vtm_visitors = 1
				WHERE vtm_visitors = 0 AND TIME(vtm_time_from) <= '$time' AND TIME(vtm_time_to) >= '$time' and site_id=" . get_current_blog_id();
		$query = $wpdb->query($sql);

		$sql = "UPDATE `ahc_visits_time` SET vtm_visits = 1
				WHERE vtm_visits = 0 AND TIME(vtm_time_from) <= '$time' AND TIME(vtm_time_to) >= '$time' and site_id = " . get_current_blog_id();
		$query = $wpdb->query($sql);

		return $result;
	}



	//--------------------------------------------

	/**

	 * Record (insert) the visit

	 *

	 * @uses wpdb::prepare()

	 * @uses wpdb::query()

	 *

	 * @return boolean

	 */
	protected function recordThisHits()
	{
		global $wpdb;

		// Get current time using saved timezone
		$current_time = $this->getCurrentLocalTime();

		$sql = "INSERT INTO `ahc_hits`
            (`hit_ip_address`, `hit_user_agent`, `hit_request_uri`, `hit_page_id`, `hit_page_title`, `ctr_id`, `hit_referer`, `hit_referer_site`,
            `srh_id`, `hit_search_words`, `bsr_id`, `hit_date`, `hit_time`, `site_id`)
            VALUES (%s, %s, %s, %s, %s, %d, %s, %s, %d, %s, %d, %s, %s, %d)";

		$result = $wpdb->query($wpdb->prepare(
			$sql,
			$this->ipAddress,
			$this->userAgent,
			$this->requestUri,
			$this->pageId,
			$this->pageTitle,
			$this->countryId,
			$this->referer,
			$this->refererSite,
			$this->searchEngine,
			$this->keyWords,
			$this->browser,
			$current_time['date'],    // FIXED: Use saved timezone instead of gmdate
			$current_time['time'],    // FIXED: Use saved timezone instead of gmdate
			get_current_blog_id()
		));

		return ($result !== false);
	}
	//--------------------------------------------


	/**
	 * Get current time in the site's configured timezone
	 * This replaces the problematic gmdate() calls
	 */

	protected function getCurrentLocalTime()
	{
		// Always store in UTC to avoid double timezone conversion
		$utc_timezone = new DateTimeZone('UTC');
		$datetime = new DateTime('now', $utc_timezone);

		$result = array(
			'date' => $datetime->format('Y-m-d'),
			'time' => $datetime->format('H:i:s'),
			'full' => $datetime->format('Y-m-d H:i:s'),
			'timezone' => 'UTC'
		);

		error_log('Storing in UTC: ' . json_encode($result));
		return $result;
	}
}