Your IP : 216.73.216.95


Current Path : /var/test/www/alh/catalog/model/extension/module/
Upload File :
Current File : /var/test/www/alh/catalog/model/extension/module/geo_ip_tools.php

<?php
//==============================================================================
// Geo IP Tools v303.2
// 
// Author: Clear Thinking, LLC
// E-mail: johnathan@getclearthinking.com
// Website: http://www.getclearthinking.com
// 
// All code within this file is copyright Clear Thinking, LLC.
// You may not copy or reuse code within this file without written permission.
//==============================================================================

class ModelExtensionModuleGeoIpTools extends Model {
	private $type = 'module';
	private $name = 'geo_ip_tools';
	private $testing_mode;
	
	//==============================================================================
	// curlRequest()
	//==============================================================================
	private function curlRequest($url) {
		$curl = curl_init($url);
		curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 3);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($curl, CURLOPT_TIMEOUT, 3);
		$response = json_decode(curl_exec($curl), true);
		if (curl_error($curl)) $response = ''; // non-standard
		curl_close($curl);
		return $response;
	}
	
	//==============================================================================
	// getLocation()
	//==============================================================================
	public function getLocation($ip) {
		$settings = $this->getSettings();
		$this->testing_mode = $settings['testing_mode'];
		
		if (empty($settings['status'])) {
			$this->logMessage('Extension is disabled');
			return;
		}
		
		// Retrieve geo ip info from database
		$file = '';
		$location = array();
		
		if (file_exists(DIR_SYSTEM . 'library/' . $this->name . '/GeoLite2-City.mmdb')) {
			$file = DIR_SYSTEM . 'library/' . $this->name . '/GeoLite2-City.mmdb';
		} elseif (file_exists(DIR_SYSTEM . 'library/' . $this->name . '/GeoLite2-Country.mmdb')) {
			$file = DIR_SYSTEM . 'library/' . $this->name . '/GeoLite2-Country.mmdb';
		}
		
		if ($file) {
			require_once(DIR_SYSTEM . 'library/' . $this->name . '/Reader.php');
			$reader = new Reader($file);
			$loc = $reader->get($ip);
			$reader->close();
			
			$location = array(
				'city'			=> (isset($loc['city']['names']['en'])) ? $loc['city']['names']['en'] : '',
				'iso_code_2'	=> (isset($loc['country']['iso_code'])) ? $loc['country']['iso_code'] : '',
				'postcode'		=> (isset($loc['postal']['code'])) ? $loc['postal']['code'] : '',
				'zone_code'		=> (isset($loc['subdivisions'][0]['iso_code'])) ? $loc['subdivisions'][0]['iso_code'] : '',
			);
		}
		
		// Retrieve geo ip info from ip-api.com
		if (empty($location)) {
			$loc = $this->curlRequest('http://ip-api.com/json/' . $ip);
			
			if (!empty($loc) && $loc['status'] != 'fail') {
				$location = array(
					'city'			=> $loc['city'],
					'iso_code_2'	=> $loc['countryCode'],
					'postcode'		=> $loc['zip'],
					'zone_code'		=> $loc['region'],
				);
			}
		}
		
		// Return if no location is set
		if (empty($location)) {
			$this->logMessage('Geo IP location was not able to be retrieved');
			return array(
				'disable_popup'	=> true,
				'city'			=> '',
				'country_id'	=> '',
				'postcode'		=> '',
				'zone_id'		=> '',
			);
		}
		
		// Retrieve country_id and zone_id
		$country_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "country WHERE iso_code_2 = '" . $this->db->escape($location['iso_code_2']) . "'");
		$location['country_id'] = (isset($country_query->row['country_id'])) ? $country_query->row['country_id'] : '';
		
		$zone_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "zone WHERE code = '" . $this->db->escape($location['zone_code']) . "' AND country_id = " . (int)$location['country_id']);
		$location['zone_id'] = (isset($zone_query->row['zone_id'])) ? $zone_query->row['zone_id'] : '';
		
		return $location;
	}
	
	//==============================================================================
	// getBrowserLocation()
	//==============================================================================
	public function getBrowserLocation($geocode) {
		$settings = $this->getSettings();
		
		$location = array(
			'city'			=> '',
			'zone_code'		=> '',
			'zone_id'		=> '',
			'iso_code_2'	=> '',
			'country_id'	=> '',
			'postcode'		=> '',
			'geocode'		=> $geocode,
		);
		
		$address_request = $this->curlRequest('https://maps.googleapis.com/maps/api/geocode/json?key=' . $settings['google_apikey'] . '&latlng=' . $geocode);
		if (empty($address_request['results'])) {
			$google_error = $address_request['status'] . (!empty($address_request['error_message']) ? ': ' . $address_request['error_message'] : '');
			$this->logMessage('The Google geocoding service returned the error "' . $google_error . '" for location ' . $geocode);
			return $location;
		}
		
		foreach ($address_request['results'][0]['address_components'] as $address_component) {
			if (in_array('locality', $address_component['types']) || in_array('sublocality', $address_component['types'])) {
				$location['city'] = $address_component['short_name'];
			}
			if (in_array('administrative_area_level_1', $address_component['types'])) {
				$location['zone_code'] = $address_component['short_name'];
			}
			if (in_array('country', $address_component['types'])) {
				$location['iso_code_2'] = $address_component['short_name'];
			}
			if (in_array('postal_code', $address_component['types'])) {
				$location['postcode'] = $address_component['short_name'];
			}
		}
		
		$country_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "country WHERE iso_code_2 = '" . $this->db->escape($location['iso_code_2']) . "'");
		$location['country_id'] = (isset($country_query->row['country_id'])) ? $country_query->row['country_id'] : '';
		
		$zone_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "zone WHERE code = '" . $this->db->escape($location['zone_code']) . "' AND country_id = " . (int)$location['country_id']);
		$location['zone_id'] = (isset($zone_query->row['zone_id'])) ? $zone_query->row['zone_id'] : '';
		
		return $location;
	}
	
	//==============================================================================
	// setLocation()
	//==============================================================================
	public function setLocation($location) {
		$settings = $this->getSettings();
		$this->testing_mode = $settings['testing_mode'];
		
		if ($settings['set_session_data']) {
			foreach (array('shipping', 'payment') as $address_type) {
				$this->session->data['country_id'] = $location['country_id'];
				$this->session->data['zone_id'] = $location['zone_id'];
				$this->session->data['postcode'] = $location['postcode'];
				$this->session->data['city'] = $location['city'];
				
				$this->session->data[$address_type . '_country_id'] = $location['country_id'];
				$this->session->data[$address_type . '_zone_id'] = $location['zone_id'];
				$this->session->data[$address_type . '_postcode'] = $location['postcode'];
				$this->session->data[$address_type . '_city'] = $location['city'];
				
				$this->session->data['guest'][$address_type] = $location;
				$this->session->data['guest'][$address_type . '_address'] = $location;
				$this->session->data['guest']['customer_group_id'] = $this->config->get('config_customer_group_id');
				$this->session->data[$address_type . '_address'] = $location;
			}
		}
		
		$this->session->data['geoip_data'] = array(
			'ip'				=> $this->request->server['REMOTE_ADDR'],
			'time'				=> time(),
			'location'			=> $location,
			'blocked_urls'		=> array(),
			'blocked_message'	=> '',
		);
		
		if (empty($location['zone_code'])) {
			$zone_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "zone WHERE zone_id = " . (int)$location['zone_id']);
			$location['zone_code'] = (isset($zone_query->row['code'])) ? $zone_query->row['code'] : '';
		}
		
		if (empty($location['iso_code_2'])) {
			$country_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "country WHERE country_id = " . (int)$location['country_id']);
			$location['iso_code_2'] = (isset($country_query->row['iso_code_2'])) ? $country_query->row['iso_code_2'] : '';
		}
		
		$this->logMessage('Geo IP location for IP address ' . $this->request->server['REMOTE_ADDR'] . ' was set to [' . $location['city'] . ', ' . $location['zone_code'] . ', ' . $location['postcode'] . ', ' . $location['iso_code_2'] . ']');
		$this->logMessage('User Agent: ' . $this->request->server['HTTP_USER_AGENT']);
	}
	
	//==============================================================================
	// checkBlocksAndStoreRedirects()
	//==============================================================================
	public function checkBlocksAndStoreRedirects() {
		if ((isset($this->request->get['route']) && $this->request->get['route'] == 'error/not_found') || empty($this->session->data['geoip_data'])) return '';
		
		$settings = $this->getSettings();
		$this->testing_mode = $settings['testing_mode'];
		
		$redirect = '';
		
		$s = $this->request->server;
		$url = 'http' . (!empty($s['HTTPS']) && $s['HTTPS'] != 'off' ? 's' : '') . '://' . $s['HTTP_HOST'] . urldecode(substr($s['REQUEST_URI'], -1) == '/' ? substr($s['REQUEST_URI'], 0, -1) : $s['REQUEST_URI']);
		
		if ((isset($this->session->data['geoip_data']['time']) && $this->session->data['geoip_data']['time'] < filemtime(DIR_LOGS . $this->name . '.autobackup')) || $this->request->server['REMOTE_ADDR'] != $this->session->data['geoip_data']['ip']) {
			// Unset geo IP location if extension settings have been changed, or visitor IP address has changed
			if ($this->request->server['REMOTE_ADDR'] != $this->session->data['geoip_data']['ip']) {
				$this->logMessage('Visitor IP address has changed from ' . $this->session->data['geoip_data']['ip'] . ' to ' . $this->request->server['REMOTE_ADDR'] . ' so geo IP location was unset');
			} else {
				$this->logMessage('Extension settings have been modified, so geo IP location for IP address ' . $this->session->data['geoip_data']['ip'] . ' was unset');
			}
			unset($this->session->data['geoip_data']);
			$redirect = $url;
		} else {
			// Check for blocked URLs or a blocked message
			foreach ($this->session->data['geoip_data']['blocked_urls'] as $blocked_url) {
				if (preg_match('/^' . str_replace('\*', '.*?', preg_quote($blocked_url, '/')) . '$/', $url)) {
					$block = true;
				}
			}
			
			if (!empty($block) || !empty($this->session->data['geoip_data']['blocked_message'])) {
				$this->logMessage('[' . $url . '] is blocked for this customer\'s location or IP');
				$redirect = $this->url->link('error/not_found');
			}
			
			// Check for a store redirect
			if (!empty($this->session->data['geoip_data']['store_redirect']) && $this->session->data['geoip_data']['store_redirect']['store_id'] != $this->config->get('config_store_id')) {
				$redirect = $this->session->data['geoip_data']['store_redirect']['url'] . substr($this->request->server['REQUEST_URI'], 1);
				$this->logMessage('Redirecting back to store ' . $redirect);
			}
		}
				
		return $redirect;
	}
	
	//==============================================================================
	// checkLocation()
	//==============================================================================
	public function checkLocation($location) {
		$settings = $this->getSettings();
		$this->testing_mode = $settings['testing_mode'];
		
		// Get geo zones
		$geo_zones = array();
		$geo_zones_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "zone_to_geo_zone WHERE country_id = " . (int)$location['country_id'] . " AND (zone_id = 0 OR zone_id = " . (int)$location['zone_id'] . ")");
		foreach ($geo_zones_query->rows as $geo_zone) {
			$geo_zones[] = $geo_zone['geo_zone_id'];
		}
		
		// Loop through rows
		$redirect = '';
		
		foreach ($settings['geoiprule'] as $row) {
			// Check stores
			if (!empty($row['store'])) {
				$store_id = ($row['store'] == 'default') ? 0 : (int)$row['store'];
				if ($store_id != $this->config->get('config_store_id')) {
					continue;
				}
			}
			
			// Check geo zones
			if (!empty($row['geo_zone'])) {
				if ($row['geo_zone'] == 'everywhere_else') {
					if (!empty($geo_zones)) continue;
				} else {
					if (!in_array($row['geo_zone'], $geo_zones)) continue;
				}
			}
			
			// Check IP ranges
			if (!empty($row['ips'])) {
				$ips = array_filter(explode(',', str_replace(array("\n", ',,', ' '), array(',', ',', ''), $row['ips'])));
				foreach ($ips as $range) {
					$range = explode('-', $range);
					if (empty($range[1])) $range[1] = $range[0];
					$in_range = false;
					
					if (ip2long($this->session->data['geoip_data']['ip']) >= ip2long($range[0]) && ip2long($this->session->data['geoip_data']['ip']) <= ip2long($range[1])) {
						$in_range = true;
						break;
					}
				}
				if (!$in_range) {
					continue;
				}
			}
			
			// Set store redirect
			if (!empty($row['store_redirect'])) {
				if ($row['store_redirect'] == 'default') {
					$store_url = HTTP_SERVER;
				} else {
					$store_url = $this->db->query("SELECT * FROM " . DB_PREFIX . "store WHERE store_id = " . (int)$row['store_redirect'])->row['url'];
				}
				$redirect = $store_url;
				$this->session->data['geoip_data']['store_redirect'] = array(
					'store_id'	=> ($row['store_redirect'] == 'default') ? 0 : (int)$row['store_redirect'],
					'url'		=> $store_url,
				);
			}
			
			// Set currency and language
			if (!empty($row['currency']) && $row['currency'] != $this->session->data['currency']) {
				$this->session->data['currency'] = $row['currency'];
				$this->logMessage('Setting currency to: ' . $this->session->data['currency']);
			}
			
			/*
			$http_accept_language = strtolower(substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 5));
			$language_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "language WHERE `code` = '" . $this->db->escape($http_accept_language) . "'");
			if ($language_query->num_rows) {
				$this->session->data['language'] = $http_accept_language;
				$this->logMessage('Setting language to: ' . $this->session->data['language']);
			} else
			*/
			if (!empty($row['language']) && $row['language'] != $this->session->data['language']) {
				$this->session->data['language'] = $row['language'];
				$this->logMessage('Setting language to: ' . $this->session->data['language']);
			}
			
			// Check redirect
			if (!empty($row['redirect'])) {
				$redirect = $row['redirect'];
				//$this->session->data['geoip_data']['store_redirect'] = array('store_id' => 999, 'url' => $row['redirect']);
			}
			
			// Set blocked URLs
			if (!empty($row['block'])) {
				if (strpos($row['block'], 'http://') === false && strpos($row['block'], 'https://') === false) {
					$this->session->data['geoip_data']['blocked_message'] = $row['block'];
				} else {
					$blocked_urls = array_filter(explode(',', str_replace(array("\n", ',,', ' '), array(',', ',', ''), $row['block'])));
					$this->session->data['geoip_data']['blocked_urls'] = array_merge($this->session->data['geoip_data']['blocked_urls'], $blocked_urls);
				}
			}
			
		} // end row loop
		
		if (!$redirect) {
			$s = $this->request->server;
			$redirect = 'http' . (!empty($s['HTTPS']) && $s['HTTPS'] != 'off' ? 's' : '') . '://' . $s['HTTP_HOST'] . urldecode(substr($s['REQUEST_URI'], -1) == '/' ? substr($s['REQUEST_URI'], 0, -1) : $s['REQUEST_URI']);
			$redirect = str_replace('index.php?route=extension/' . $this->type . '/' . $this->name . '/setLocation', '', $redirect);
		}
		
		$this->logMessage('Redirecting to ' . $redirect);
		return $redirect;
	}
	
	//==============================================================================
	// Private functions
	//==============================================================================
	private function getSettings() {
		$code = (version_compare(VERSION, '3.0', '<') ? '' : $this->type . '_') . $this->name;
		
		$settings = array();
		$settings_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "setting WHERE `code` = '" . $this->db->escape($code) . "' ORDER BY `key` ASC");
		
		foreach ($settings_query->rows as $setting) {
			$value = $setting['value'];
			if ($setting['serialized']) {
				$value = (version_compare(VERSION, '2.1', '<')) ? unserialize($setting['value']) : json_decode($setting['value'], true);
			}
			$split_key = preg_split('/_(\d+)_?/', str_replace($code . '_', '', $setting['key']), -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
			
				if (count($split_key) == 1)	$settings[$split_key[0]] = $value;
			elseif (count($split_key) == 2)	$settings[$split_key[0]][$split_key[1]] = $value;
			elseif (count($split_key) == 3)	$settings[$split_key[0]][$split_key[1]][$split_key[2]] = $value;
			elseif (count($split_key) == 4)	$settings[$split_key[0]][$split_key[1]][$split_key[2]][$split_key[3]] = $value;
			else 							$settings[$split_key[0]][$split_key[1]][$split_key[2]][$split_key[3]][$split_key[4]] = $value;
		}
		
		return $settings;
	}
	
	private function logMessage($message) {
		if ($this->testing_mode) {
			file_put_contents(DIR_LOGS . $this->name . '.messages', print_r($message, true) . "\n", FILE_APPEND|LOCK_EX);
		}
	}
}
?>