前些时间我们比较过opencart,zencart,wordpress等系统的优劣,当时我就开始觉得zencart系统在国内的使用正开始没落,最主要的原因可以使用的模板太少了,市面上销售的模板很多都因为之前国内做仿牌使用zencart这些模板人太多,导致SEO等各方面太差了,谷歌浏览器也经常标记使用过这些模板的网站为垃圾网站。而最近咨询我建站方面的很多客户基本上都是要求使用opencart或wordpress。
今天有个客户需要优化opencart的一细节,其中就有个需求根据IP来切换客户国家的默认币种和语言。这里就来写写我的整个开发时相当和步骤。
1.IP查询
获取客户的访问IP后,我们要查询IP所在的国家,这个一般有2种方法,一个是调用第三方的接口,一个是直接查询本地的IP库。其实就这一步你就得考虑下客户的愿意花多少钱来做这件事。因为大部分第三方接口都是收费的,就有免费的接口也会对你调用接口的次数和频率做一些限制,可能当你网站流量大或被蜘蛛爬行时,你的接口调用就达到了限额,导致调用失效了。查询本地IP库也有一个弊端,如果你对IP的查询结果要求的比较细,会消耗你服务器CPU资源。考虑到客户只要查询到国家就行和成本等因素还是用IP库查询的方式。语言的选择我们就不靠IP国家了,因为opencart自带了根据浏览器语言来默认语言。
文件位置:catalog\controller\extension\module\ip.php
<?php
require(DIR_SYSTEM.'library/MaxMind/Db/Reader/InvalidDatabaseException.php');
require(DIR_SYSTEM.'library/MaxMind/Db/Reader/Decoder.php');
require(DIR_SYSTEM.'library/MaxMind/Db/Reader/Metadata.php');
require(DIR_SYSTEM.'library/MaxMind/Db/Reader/Util.php');
require(DIR_SYSTEM.'library/MaxMind/Db/Reader.php');
class ControllerExtensionModuleIp extends Controller {
public function index() {
if (isset($this->session->data['currency']))
return true;
$file = DIR_SYSTEM.'library/MaxMind/dbip-country-lite-2023-04.mmdb';
$reader = new \MaxMind\Db\Reader($file);
$ipAddress = $this->get_client_ip();
$ip_info = $reader->get($ipAddress);
$reader->close();
if($ip_info){
$country_iso_code = $ip_info['country']['iso_code'];
$currency = $this->get_country_default_currency($country_iso_code);
if($currency){
$this->load->model('localisation/currency');
$currencies = $this->model_localisation_currency->getCurrencies();
if(array_key_exists($currency, $currencies)){
$this->session->data['currency'] = $currency;
}
}
}
}
public function get_client_ip(){
if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) { //使用cloudflare 转发的IP地址
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
} else {
if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
$ip = getenv('HTTP_CLIENT_IP');
} elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
$ip = getenv('HTTP_X_FORWARDED_FOR');
} elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
$ip = getenv('REMOTE_ADDR');
} elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
$ip = $_SERVER['REMOTE_ADDR'];
}
}
return $ip;
}
public function get_country_default_currency($country_iso_code){
$country_map_currency = [
'NZ'=>'NZD',
'CK'=>'NZD',
'NU'=>'NZD',
'PN'=>'NZD',
'TK'=>'NZD',
'AU'=>'AUD',
'CX'=>'AUD',
'CC'=>'AUD',
'HM'=>'AUD',
'KI'=>'AUD',
'NR'=>'AUD',
'NF'=>'AUD',
'TV'=>'AUD',
'AS'=>'EUR',
'AD'=>'EUR',
'AT'=>'EUR',
'BE'=>'EUR',
'FI'=>'EUR',
'FR'=>'EUR',
'GF'=>'EUR',
'TF'=>'EUR',
'DE'=>'EUR',
'GR'=>'EUR',
'GP'=>'EUR',
'IE'=>'EUR',
'IT'=>'EUR',
'LU'=>'EUR',
'MQ'=>'EUR',
'YT'=>'EUR',
'MC'=>'EUR',
'NL'=>'EUR',
'PT'=>'EUR',
'RE'=>'EUR',
'WS'=>'EUR',
'SM'=>'EUR',
'SI'=>'EUR',
'ES'=>'EUR',
'VA'=>'EUR',
'GS'=>'GBP',
'GB'=>'GBP',
'JE'=>'GBP',
'IO'=>'USD',
'GU'=>'USD',
'MH'=>'USD',
'FM'=>'USD',
'MP'=>'USD',
'PW'=>'USD',
'PR'=>'USD',
'TC'=>'USD',
'US'=>'USD',
'UM'=>'USD',
'VG'=>'USD',
'VI'=>'USD',
'HK'=>'HKD',
'CA'=>'CAD',
'JP'=>'JPY',
'AF'=>'AFN',
'AL'=>'ALL',
'DZ'=>'DZD',
'AI'=>'XCD',
'AG'=>'XCD',
'DM'=>'XCD',
'GD'=>'XCD',
'MS'=>'XCD',
'KN'=>'XCD',
'LC'=>'XCD',
'VC'=>'XCD',
'AR'=>'ARS',
'AM'=>'AMD',
'AW'=>'ANG',
'AN'=>'ANG',
'AZ'=>'AZN',
'BS'=>'BSD',
'BH'=>'BHD',
'BD'=>'BDT',
'BB'=>'BBD',
'BY'=>'BYR',
'BZ'=>'BZD',
'BJ'=>'XOF',
'BF'=>'XOF',
'GW'=>'XOF',
'CI'=>'XOF',
'ML'=>'XOF',
'NE'=>'XOF',
'SN'=>'XOF',
'TG'=>'XOF',
'BM'=>'BMD',
'BT'=>'INR',
'IN'=>'INR',
'BO'=>'BOB',
'BW'=>'BWP',
'BV'=>'NOK',
'NO'=>'NOK',
'SJ'=>'NOK',
'BR'=>'BRL',
'BN'=>'BND',
'BG'=>'BGN',
'BI'=>'BIF',
'KH'=>'KHR',
'CM'=>'XAF',
'CF'=>'XAF',
'TD'=>'XAF',
'CG'=>'XAF',
'GQ'=>'XAF',
'GA'=>'XAF',
'CV'=>'CVE',
'KY'=>'KYD',
'CL'=>'CLP',
'CN'=>'CNY',
'CO'=>'COP',
'KM'=>'KMF',
'CD'=>'CDF',
'CR'=>'CRC',
'HR'=>'HRK',
'CU'=>'CUP',
'CY'=>'CYP',
'CZ'=>'CZK',
'DK'=>'DKK',
'FO'=>'DKK',
'GL'=>'DKK',
'DJ'=>'DJF',
'DO'=>'DOP',
'TP'=>'IDR',
'ID'=>'IDR',
'EC'=>'ECS',
'EG'=>'EGP',
'SV'=>'SVC',
'ER'=>'ETB',
'ET'=>'ETB',
'EE'=>'EEK',
'FK'=>'FKP',
'FJ'=>'FJD',
'PF'=>'XPF',
'NC'=>'XPF',
'WF'=>'XPF',
'GM'=>'GMD',
'GE'=>'GEL',
'GI'=>'GIP',
'GT'=>'GTQ',
'GN'=>'GNF',
'GY'=>'GYD',
'HT'=>'HTG',
'HN'=>'HNL',
'HU'=>'HUF',
'IS'=>'ISK',
'IR'=>'IRR',
'IQ'=>'IQD',
'IL'=>'ILS',
'JM'=>'JMD',
'JO'=>'JOD',
'KZ'=>'KZT',
'KE'=>'KES',
'KP'=>'KPW',
'KR'=>'KRW',
'KW'=>'KWD',
'KG'=>'KGS',
'LA'=>'LAK',
'LV'=>'LVL',
'LB'=>'LBP',
'LS'=>'LSL',
'LR'=>'LRD',
'LY'=>'LYD',
'LI'=>'CHF',
'CH'=>'CHF',
'LT'=>'LTL',
'MO'=>'MOP',
'MK'=>'MKD',
'MG'=>'MGA',
'MW'=>'MWK',
'MY'=>'MYR',
'MV'=>'MVR',
'MT'=>'MTL',
'MR'=>'MRO',
'MU'=>'MUR',
'MX'=>'MXN',
'MD'=>'MDL',
'MN'=>'MNT',
'MA'=>'MAD',
'EH'=>'MAD',
'MZ'=>'MZN',
'MM'=>'MMK',
'NA'=>'NAD',
'NP'=>'NPR',
'NI'=>'NIO',
'NG'=>'NGN',
'OM'=>'OMR',
'PK'=>'PKR',
'PA'=>'PAB',
'PG'=>'PGK',
'PY'=>'PYG',
'PE'=>'PEN',
'PH'=>'PHP',
'PL'=>'PLN',
'QA'=>'QAR',
'RO'=>'RON',
'RU'=>'RUB',
'RW'=>'RWF',
'ST'=>'STD',
'SA'=>'SAR',
'SC'=>'SCR',
'SL'=>'SLL',
'SG'=>'SGD',
'SK'=>'SKK',
'SB'=>'SBD',
'SO'=>'SOS',
'ZA'=>'ZAR',
'LK'=>'LKR',
'SD'=>'SDG',
'SR'=>'SRD',
'SZ'=>'SZL',
'SE'=>'SEK',
'SY'=>'SYP',
'TW'=>'TWD',
'TJ'=>'TJS',
'TZ'=>'TZS',
'TH'=>'THB',
'TO'=>'TOP',
'TT'=>'TTD',
'TN'=>'TND',
'TR'=>'TRY',
'TM'=>'TMT',
'UG'=>'UGX',
'UA'=>'UAH',
'AE'=>'AED',
'UY'=>'UYU',
'UZ'=>'UZS',
'VU'=>'VUV',
'VE'=>'VEF',
'VN'=>'VND',
'YE'=>'YER',
'ZM'=>'ZMK',
'ZW'=>'ZWD',
'AX'=>'EUR',
'AO'=>'AOA',
'AQ'=>'AQD',
'BA'=>'BAM',
'CD'=>'CDF',
'GH'=>'GHS',
'GG'=>'GGP',
'IM'=>'GBP',
'LA'=>'LAK',
'MO'=>'MOP',
'ME'=>'EUR',
'PS'=>'JOD',
'BL'=>'EUR',
'SH'=>'GBP',
'MF'=>'ANG',
'PM'=>'EUR',
'RS'=>'RSD',
'USAF'=>'USD'
];
if(isset($country_map_currency[$country_iso_code])){
return $country_map_currency[$country_iso_code];
}else{
return false;
}
}
}
2.勾子触发货币切换代码
opencart在文件调用时都用了好多勾子,这样很多扩展我们就不需要去直接修改核心文件,只要加上对应的勾子调用,这样大大提高了代码的维护性。
文件:system/config/catalog.php,查找“'startup/startup'”,在其上面加上'extension/module/ip/index'
这个勾子 加上后,你会发现你的模板可能触发勾子,也可能无效,因为opencart有一套对核心文件修改的规则,当你要修改核心文件时,你不能直接去修改对应的文件,你必须使用Modification的机制去做。Modification管理着整个网站需要修改核心的记录,有时可能多个插件需要修改同一个文件,这时如果你加一下我加一个,很容易导致代码的不可维护,而通过Modification我们则能高效的维护代码。
<?xml version="1.0" encoding="utf-8"?>
<modification>
<name>根据IP国家默认切换币种</name>
<code>Default currency by ip</code>
<version>1.0</version>
<author>微信:ChineseMarcelo</author>
<link>https://blog.youkuaiyun.com/jxayxym</link>
<file path="system/config/catalog.php">
<operation>
<search><![CDATA[ 'startup/startup', ]]></search>
<add position="before">
<![CDATA[
'extension/module/ip/index',
]]>
</add>
</operation>
</file>
</modification>