Current Path : /var/test/www/alh/catalog/model/extension/module/ |
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); } } } ?>