opencart

Opencart主要是做外贸电商的,跨境电商之类的,使用的是PHP语言。
OpenCart基于PHP+MYSQL开发,支持无限分类、无限产品、多主题、多种币种、多语言、购买评论、产品点评、搜索引擎优化、在线下单支付、内置多种支付接口等完善的电子商务功能,是国外著名的B2C电子商务系统

界面简洁、友好、符合欧美人使用习惯、是最适合国人建外贸网站的程序之一。(同类型的B2C开源程序国内有Ecshop、ZenCart,国外还有Magento)

安装配置

环境要求:
PHP 5.3+(开启cURL、GD、mCrypt扩展)
MySQL 5.1+
Nginx / Apache(开启mod_rewrite重写模块)

安装流程:
OpenCart最新版本为 2.0.3,可从官网下载,下载地址https://www.opencart.com/index.php?route=download/download,下载最新版本后解压缩到网站根目录,通过浏览器访问首页,会自动进入安装过程。按照提示输入数据库配置信息设置后台密码直接安装完成。安装成功后,安全起见需移除install目录,访问https://your-site/admin即可进入管理后台。

注意事项:
安装前除需开启所需的PHP扩展、Apache服务器扩展,还需将以下目录或文件设置为可写。
system/cache 系统缓存目录
system/logs 系统日志目录 debug::log()将会用到
system/download 下载文件存放位置
system/upload 系统默认上传目录
system/modification 系统程序缓存目录
image/cache 缩略图缓存目录
admin/config.php 管理员配置文件
config.php 前台配置文件
以下为comprame需设为可写的目录或文件
hbsitemaps 谷歌地图生成存放目录
journal-cache Journal2 静态资源缓存目录
vqmod/logs vqmod日志目录
vqmod/vqcache vqmod缓存目录
vqmod/checked.cache vqmod用于保存已缓存的文件名
vqmod/mods.cache vqmod用于保存缓存文件的序列化源码
merchenta-product-feeds.txt 产品feeds list生成文件
product-feeds.txt 产品feeds list 生成文件

设为可写的方法:
*inux系统可终端执行chmod–R 777 path/to命令完成此操作。

结构

表结构

概述对比:
OC官方安装后数据表会有123张,现comprame已有数据表190张。OC默认的数据是以MyISAM为存储引擎,不支持事物和回滚,时间字段的数据类型为datetime类型。从查询读写效率上对比,MyISAM比Innodb快很多倍,但MyISAM并不支持事物和回滚,所以今后创建新数据表都默认使用Innodb引擎。

主要表的前缀:
category_* 产品分类相关表
coupon_* 优惠券相关的表
customer_* 客户相关的表
emailtempate_* 邮件模板相关表
journal2_* journal2插件相关表
order_* 订单数据相关表
product_* 产品数据相关表

文件目录结构

/admin 后台MVC程序目录
/catalog 前台MVC程序目录
/hbsitemaps Google地图生存存放目录
/image 图片资源目录
/image/cache 图片缩略图缓存目录
/media 静态资源目录
/sql/sql.txt 每次发版本所需执行的SQL存放
/system 系统公用类库程序脚本
/system/journal2 journal2插件程序
/system/modification modification缓存目录
/index.php 前台入口文件
/.htaccess Apache 重写配置文件
/d_social_login.php 外部登录文件
/robots.txt 搜索引擎机器人文件

URL重写及路由

URL规则:
RewriteCond%{REQUEST_FILENAME} !-f
RewriteCond%{REQUEST_FILENAME} !-d
RewriteCond%{REQUEST_URI} !.*.(ico|gif|jpg|jpeg|png|js|css)
RewriteRule^([^?]*) index.php?route=$1 [L,QSA]
OC的产品详情页、分类页面都是重写伪静态过后的网址,产品的详情页的网址在后台添加修改产品表单的 General -> SEO Keyword中设置。

直接指定:
除重写外,OC可通过route参数来指定需要访问的MVC路由。例如访问注册动作,MVC动作为 account/register,用户可通过local.comprame.com/index.php?route=account/register直接访问。参数传递示例:local.comprame.com/index.php?route=account/register¶m1=val1&..

重写:
运行opencart的环境必须支持重写,opencart默认推荐Apache服务器,将Apache服务器的mod_rewrite模块开启后,将网站配置directory指令中的AllowOverride设置为All,即可。如果使用nginx服务器,可在location指令中添加
if(!-e request_filename){
rewrite^/(.*) /index.php?_route_=$1 last;
break;
}
重启nginx即可。

程序运行流程

请求URL重写到入口文件

通过重写,将请求地址转发到入口文件,一般为index.php,入口文件可从请求参数 route 获得当前请求网址。如果是直接访问入口文件,通过route参数可指定对应的请求路由。

入口文件加载所类库并实例化

执行入口文件,会先引入配置文件,再通过是否定义 !defined(‘DIR_APPLICATION’)判断是否已安装,如果未定义此常量,则转到安装。
之后,入口文件内会引入所需的类、扩展、并实例化所需的类,包括链接数据库、实例化registry、loader、config、request、response、session、customer、controller……

绑定Action动作

执行动作会预先绑定new Action(‘common/seo_url’)动作,用于解析请求的route参数。

开始SEO插件检查并且指派动作Action

实例化控制器后,会开始执行请求的动作 controller?>dispatch( action, new Action(‘error/not_found’));计算出真正的请求路由,并引入该控制器实例化执行动作,执行完毕后会将内注册加到$response对象。

执行结果返回输出

通过$response->output();格式化内容进行输出

控制器 Controller

存放位置:
OC的控制器程序文件统一存放在 DIR_APPLICATION . ‘controller/’ 目录下。默认的即前台控制器都是放在 /catalog/controller目录下,后台都放在 /admin/controller。

类名规则:
控制器类名以Controller开头,继承自Controller父类。类名的与route路由对应原则:
this?>class=′Controller′.pregreplace(′/[a?zA?Z0?9]/′,′′, path);
所以
示例1:
请求URL:index.php?route= account/register_promotion
对应文件:/catalog/controller/account/register_promotion.php
执行类名:ControllerAccountRegisterPromotion
示例2:
请求URL:index.php?route=test/account/register_promotion
对应文件:/catalog/controller/test/account/register_promotion.php
执行类名:ControllerTestAccountRegisterPromotion

注意信息:
PHP中函数名、类名、方法名是不区分大小写,但为了阅读方便和规范,类名书写应采用驼峰命名方式。

动作Action

动作Action即控制器的成员方法,命名英文字母或下划线开头英文字母数字下划线组成。请求时动作名附带在route参数中,如果未指定,默认动作为 index,注意请求访问以双下划线开头的方法不会被调用。

动作的参数接受:
对于直接请求的动作,可通过网址传递参数,接受可在动作内通过如下方式,先判定是否设置再接收。
if(isset(this->request->get[‘product_id’])){product_id= (int)this->request->get[‘product_id’];
}else{product_id= 0;
}

控制器的动作可直接调用前台其他控制器的动作,参数的传递可通过如下方式进行
传递:
$this->load->controller(‘catalog/feeds/build’,1);

接收:
public function build($notSetSession= false){
}

模型Model

模型文件存放在DIR_APPLICATION . ‘model/’目录下,模型的寻找如下:
file=DIRAPPLICATION.′model/′. model .’.php’;
class=′Model′.pregreplace(′/[a?zA?Z0?9]/′,′′, model);

在Action中引入和调用示例:
this?>load?>model(‘catalog/product′); this->model_catalog_product->getProducts();

视图View

视图文件可任意扩展名结尾,统一存放在DIR_TEMPLATE目录下,默认为.tpl。
在Action的末尾,可通过如下代码实现视图的渲染,并注册到response对象以用于入口文件输出。
this?>response?>setOutput( this->load->view(‘catalog/product_list.tpl’, $data));

插件

VQMOD

vQmod全称是 Virtual File Modification System 又称快速虚拟MOD)是一个虚拟覆盖系统的设计,以避免原有系统核心文件被修改。这个概念是很简单,它通过创建XML搜索/替换脚本文件,而不是直接更改核心文件。这些脚本文件是在页面加载解析为每个“源”核心文件“包括”或“规定”的php函数加载和资源,然后打补丁的脚本文件的变化,并保存到一个临时文件,然后在执行临时文件,在过程中取代了原来的文件。原来的源文件是永远不会改变。这将实现一个“虚拟”的变化中,在没有任何实际修改的核心文件中执行想要的过程和结果。

执行原理:PHP搜索替换。(通过XML读取vqmod/xml下的xml文件,逐个配置内指定的文件进行替换对应的代码,缓存到vqmod/vqcache下生成对应的缓存文件)

相关文件:

缺点:如果改动了要替换的文件的源码,可导致搜索不到对应文字而不替换。
刷新:可通过清空vqmod/checked.cache及vqmod/mods.cache内容强制vqmod重新生成缓存。

SEO插件

用途作用:后台管理操作管理oc_url_alias的数据。
后台位置:Extension -> Modules ->Complete SEO Package

邮件模板Emailtemplate

用途作用:可后台配置的邮件模板,用于格式化发送的邮件内容。
用法示例:
template=newEmailTemplate( this->request, this?>registry); template->addData( this?>request?>post); template->data['password'] = password; template->data['account_login'] = this->url->link(‘account/login’,‘&email=’.this->request->post[‘email’], ‘SSL’);
template?>data[′accountlogintracking′]= template->getTracking($template->data[‘account_login’]);

mail=newMail(); mail->useExternal= this?>config?>get(‘configmailexternal′); mail->setRegistry( this?>registry); mail->protocol = this?>config?>get(‘configmailprotocol′); mail->parameter = this?>config?>get(‘configmailparameter′); mail->smtp_hostname= this?>config?>get(‘configmailsmtphostname′); mail->smtp_username= this?>config?>get(‘configmailsmtpusername′); mail->smtp_password= html_entity_decode( this?>config?>get(‘configmailsmtppassword′),ENTQUOTES,‘UTF?8′); mail->smtp_port= this?>config?>get(‘configmailsmtpport′); mail->smtp_timeout= $this->config->get(‘config_mail_smtp_timeout’);

mail?>setTo( this->request->post[‘email’]);
mail?>setFrom( this->config->get(‘config_email’));
mail?>setSender(htmlentitydecode( this->config->get(‘config_name’), ENT_QUOTES, ‘UTF-8’));
mail?>setSubject( subject);
mail?>setText( message);
template?>load(‘customer.forgotten′); mail = template?>hook( mail);
mail?>send(); template->sent();

Journal2 插件

OC的一款主题模板主题,可最大化的在后台配置前台的模板显示。Journal2 可通过PHP判断设备尺寸,再渲染不同的HTML以自动适配。Journal2插件会在journal-cache下生成JS CSS的静态资源,因此此目录需要可写。

交易及支付流程(TBD)

交易流程 PayULatam支付 PayPal 快速付款 PayPal 标准支付 线下付款及流程

专题

参数接受

在OC中, POST、 _GET、 FILES、 _REQUEST、 SERVER、 _COOKIE都已过滤后封装在 $this->request对象中,如需要再控制器动作中接受,可通先判断是否isset再传值。

过滤方式:
data=htmlspecialchars( data, ENT_COMPAT, ‘UTF-8’);

参考代码:
if(isset(this->request->get[‘order’])){url.='&order=' . $this->request->get[‘order’];
}

多语言支持

语言的设置:
comprame前台默认的是西班牙语,后台使用的是英语。如需更改,可在增加语言文件后再在后台进行设置。后台位置 System -> Settings -> Store -> Local,Language、Administrator Language,在控制器动作中可通过 config?>get(‘configlanguage′)获得前台语言文件ID, config->get(‘config_admin_language’)
获得后台语言文件ID。

翻译的使用:
先载入对应的语言文件,再通过 this?>language?>get对象即可,示例如下: this->load->language(‘catalog/product’);
data[′success′]= this->language->get(‘text_success’);

注意的事项:
1) 由于comprame已经使用了journal2 ,开启多语言支持会导致journal2主题不会引入对应的设置。所以不能开启多语言支持。
原因源码:

?
1
2
3
<code class = "hljs tex" >#D:\website\latin\src\catalog\view\theme\journal2\template\common\language.tpl
#common/header
$data[ 'language' ] = $ this ->load->controller( 'common/language' );</code>

动作Action调用

在Action动作中,可相互调用同端的动作Action(前端的控制器中只能调用前端的,后端调用后端的),实现方式如下:
data[′currency′]= this->load->controller(‘common/currency’);

调用时参数的传递:
this?>load?>controller(′payment/ppexpress′, varArray);

调用时参数的接受:
public function index() {
$varArray= func_get_args(); //获取传递的参数
}

Event事件触发

示例代码:
this?>event?>trigger(′pre.admin.attribute.add′, data);
$data为传递进入的参数,默认为空。涉及表oc_event

?
1
2
3
4
5
6
7
8
9
<code class = "hljs php" >#event执行原理
public function trigger($key, &$arg= array()) {
if (isset($ this ->data[$key])) {
foreach($ this ->data[$key] as $event) {
$action = new Action($event, $arg);
$action->execute($ this ->registry);
       }
    }
}</code>

SQL过滤

SQL的过滤,主要是转换接受参数为int类型或string类型,使用显性类型强制转换。
示例int转换:
this?>db?>query("DELETEFROM".DBPREFIX."attributeWHEREattributeid=′".(int) attribute_id.”’”);

示例string过滤:
sql="ANDnameLIKE′ this->db->escape($data[‘filter_name’]).”%’”;

SQL宽字符注入:
PHP中因为字符集问题可引起SQL宽字符chr(0x5c) chr(0x27) chr(0xbf)
注入,通过字符集强制转换为UTF-8,可防止。

在OC中, this?>request对象clean方法中已经过滤并有字符集转换。 data= htmlspecialchars($data, ENT_COMPAT, ‘UTF-8’);

所以针对传入需进行SQL拼接参数,必须从$this->request中获取!

货币转换

comprame开启支持3种货币,分别是美元USD、比索COP、墨西哥元MXN,前台默认的货币显示为COP(哥伦比亚币),后台员添加和修改产品时,所用的单位都是USD(美元)。
所以在前台显示商品价格,涉及货币转换,转换代码可参考如下:

this?>currency?>convert( value, $this->config->get(‘config_currency’), ‘USD’);

config_currency为后台设置的默认货币。

货币格式化输出:
this?>currency?>format( money, ‘COP’);

注意事项:
COP哥伦比亚比索,其小数点使用的是逗号,而千分是使用的点号。

汇率的更新:
汇率是后台人员手动设置,位置System ->Localisation -> Currencies,涉及表oc_currency。

文件上传

后台通过common/filemanager/upload 进行上传,上传后保存在catalog目录下,默认为image。
// Make sure we have the correct directory
if (isset(this->request->get[‘directory’])){directory = rtrim(DIR_IMAGE . 'catalog/' . str_replace(array('../', '..\\', '..'), '', this->request->get[‘directory’]),‘/’);
}else{directory = DIR_IMAGE . ‘catalog’;
}

对于上传的文件,限制在如下4中mime类型的文件
// Allowed file mime types
$allowed = array(
‘image/jpeg’,
‘image/pjpeg’,
‘image/png’,
‘image/x-png’,
‘image/gif’
);

SESSION操作

在入口文件index.php,SESSION对象已经初始化后注册到了 registry对象中。 session= new Session();
registry?>set(′session′, session);

在动作中,可通过如下方式对SESSION进行操作:
//检测
isset($this->session->data[‘success’])

//赋值
this?>session?>data[′success′]= this->language->get(‘text_success’);

//销毁
unset($this->session->data[‘success’]);

COOKIE操作

//读取
if(isset(this->request->cookie[‘tracking’])){order_data['tracking'] = $this->request->cookie[‘tracking’];
}

//COOKIE的设置还是通过默认的setcookie进行操作
setcookie(‘language’, code,time()+86400?30,′/′, request->server[‘HTTP_HOST’]);

跳转及重定向

在Action动作中通过response对象进行重定向
this?>response?>redirect( this->url->link(‘catalog/attribute’, ‘token=’ . this?>session?>data[′token′]. url, ‘SSL’));

后台通信前台方法

原理:通过CURL请求前台api/login接口,使用api表的用户密码数据录到前台,再CURL请求前台要执行的接口。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<code class = "hljs php" >例子:common/dashboardapiRequest
public function apiRequest($url, $data = array())
{
$json= array();
 
$ this ->load->language( 'sale/order' );
$ this ->load->model( 'sale/order' );
$ this ->load->model( 'user/api' );
 
unset($ this ->session->data[ 'cookie' ]);
 
$api_info= $ this ->model_user_api->getApi($ this ->config->get( 'config_api_id' ));
 
if ($api_info) {
$curl = curl_init();
if (substr(HTTPS_CATALOG, 0 , 5 ) == 'https' ) {
curl_setopt($curl, CURLOPT_PORT, 443 );
       }
 
curl_setopt($curl, CURLOPT_HEADER, false );
curl_setopt($curl, CURLINFO_HEADER_OUT, true );
curl_setopt($curl, CURLOPT_USERAGENT, $ this ->request->server[ 'HTTP_USER_AGENT' ]);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false );
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false );
curl_setopt($curl, CURLOPT_FORBID_REUSE, false );
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true );
curl_setopt($curl, CURLOPT_URL, HTTPS_CATALOG. 'index.php?route=api/login' );
curl_setopt($curl, CURLOPT_POST, true );
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($api_info));
 
$result = curl_exec($curl);
 
if (!$result) {
$json[ 'error' ] = sprintf($ this ->language->get( 'error_curl' ), curl_error($curl), curl_errno($curl));
       } else {
$response = json_decode($result, true );
 
if (isset($response[ 'cookie' ])) {
$ this ->session->data[ 'cookie' ] = $response[ 'cookie' ];
          }
 
curl_close($curl);
       }
    } else {
$json[ 'error' ] = $ this ->language->get( 'error_action' );
    }
 
if (isset($ this ->session->data[ 'cookie' ])) {
$curl = curl_init();
 
if (substr($url, 0 , 5 ) == 'https' ) {
curl_setopt($curl, CURLOPT_PORT, 443 );
       }
 
curl_setopt($curl, CURLOPT_HEADER, false );
curl_setopt($curl, CURLINFO_HEADER_OUT, true );
curl_setopt($curl, CURLOPT_USERAGENT, $ this ->request->server[ 'HTTP_USER_AGENT' ]);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false );
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false );
curl_setopt($curl, CURLOPT_FORBID_REUSE, false );
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true );
curl_setopt($curl, CURLOPT_URL, HTTPS_CATALOG.$url);
 
if ($data) {
curl_setopt($curl, CURLOPT_POST, true );
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data));
       }
 
curl_setopt($curl, CURLOPT_COOKIE, session_name(). '=' .$ this ->session->data[ 'cookie' ]. ';' );
 
$result = curl_exec($curl);
 
if (!$result) {
$json[ 'error' ] = sprintf($ this ->language->get( 'error_curl' ), curl_error($curl), curl_errno($curl));
       } else {
$json= (array)json_decode($result);
       }
 
curl_close($curl);      
    } else {
$json[ 'error' ] = $ this ->language->get( 'error_action' );
    }
 
return $json;
}  </code>

数据分页Pagination

?
1
2
3
4
5
6
7
<code class = "hljs lasso" >$pagination = new Pagination();
$pagination->total = $affiliate_total;
$pagination->page = $page;
$pagination->limit = $ this ->config->get( 'config_limit_admin' );
$pagination->url= $ this ->url->link( 'marketing/affiliate' , 'token=' . $ this ->session->data[ 'token' ] . $url. '&page={page}' , 'SSL' );
 
$data[ 'pagination' ] = $pagination->render();</code>

图片缩略图生成

原理,检测对应尺寸的缩略图文件是否存在,如果不存在或者文件创建时间小于原图创建时间,重新生成对应尺寸的图片,并保存到DIR_IMAGE目录中。

调用源码:

?
1
2
3
4
5
6
7
8
9
10
<code class = "hljs erlang-repl" >$ this ->load->model( 'tool/image' );
if ($product[ 'image' ]){
$image = $ this ->model_tool_image->resize($product[ 'image' ],
     $ this ->config->get( 'config_image_cart_width' ),
     $ this ->config->get( 'config_image_cart_height' ));
} else {
$image = $ this ->model_tool_image->resize( 'no_image.png' ,
     $ this ->config->get( 'config_image_cart_width' ),
     $ this ->config->get( 'config_image_cart_height' ));
}</code>

备注如果没有缩略图,可使用no_image.png生成。
data[′placeholder′]= this->model_tool_image->resize(‘no_image.png’, 100, 100);

后台对应设置图片尺寸:System -> Settings ->Store -> Image
config_image_cart_width 购物车产品缩略图大小
config_image_thumb_width 产品缩略图大小,包括手机端
config_image_popup_width 产品弹出图片大小
config_image_product_width 产品列表图片大小

OC的模板

控制器动作中调用模板的代码:
this?>response?>setOutput( this->load->view(‘catalog/category_list.tpl’, $data));

OC模板为原生PHP,无额外模板解析,模板文件夹扩展名默认为*.tpl,存放在DIR_TEMPLATE
目录中。模板解析后的内容通过PHP 的ob_get_content读取缓冲内容返回到response对象中。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<code class = "hljs php" > public function view($template, $data = array()) {
$file = DIR_TEMPLATE . $template;
if (file_exists($file)) {
extract($data);
ob_start();
require($file);
$output = ob_get_contents();
ob_end_clean();
return $output;
    } else {
trigger_error( 'Error: Could not load template ' . $file . '!' );
exit();
    }
}</code>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值