分类归档 OPENCART

通过清心醉

opencart规格积分无法增加的解决方案

需要的动作:
1:用户加入购物车,有其他的规格,增加其他规格的积分的显示
controller/checkout/cart.php里的index控制器里修改:

$jifennum=0; //重新定义积分 = 0 ;
foreach ($product[‘option’] as $option) {
if ($option[‘type’] != ‘file’) {
$value = $option[‘value’];
} else {
$upload_info = $this->model_tool_upload->getUploadByCode($option[‘value’]);

if ($upload_info) {
$value = $upload_info[‘name’];
} else {
$value = ”;
}
}

$option_data[] = array(
‘name’ => $option[‘name’],
‘value’ => (utf8_strlen($value) > 20 ? utf8_substr($value, 0, 20) . ‘..’ : $value)
);
//新增判断语句,判断积分的增减
if (!empty($option[‘points_prefix’]) && !empty($option[‘points’])){
if ($option[‘points_prefix’]==’+’){
$jifennum = ($jifennum+$option[‘points’]);
} else {
$jifennum = ($jifennum-$option[‘points’]);
}
}
//判断结束
}
$jifennum = ($jifennum*$product_total); //购买的数量,同时增加积分的总值

$jifen=($product[‘reward’]+$jifennum);
#然后,$data[‘products’][]多维数组重新修改显示的值:

// Display prices
if (($this->config->get(‘config_customer_price’) && $this->customer->isLogged()) || !$this->config->get(‘config_customer_price’)) {
$price = $this->currency->format($this->tax->calculate($product[‘price’], $product[‘tax_class_id’], $this->config->get(‘config_tax’)));
} else {
$price = false;
}

// Display prices
if (($this->config->get(‘config_customer_price’) && $this->customer->isLogged()) || !$this->config->get(‘config_customer_price’)) {
$total = $this->currency->format($this->tax->calculate($product[‘price’], $product[‘tax_class_id’], $this->config->get(‘config_tax’)) * $product[‘quantity’]);
} else {
$total = false;
}

$recurring = ”;

if ($product[‘recurring’]) {
$frequencies = array(
‘day’ => $this->language->get(‘text_day’),
‘week’ => $this->language->get(‘text_week’),
‘semi_month’ => $this->language->get(‘text_semi_month’),
‘month’ => $this->language->get(‘text_month’),
‘year’ => $this->language->get(‘text_year’),
);

if ($product[‘recurring’][‘trial’]) {
$recurring = sprintf($this->language->get(‘text_trial_description’), $this->currency->format($this->tax->calculate($product[‘recurring’][‘trial_price’] * $product[‘quantity’], $product[‘tax_class_id’], $this->config->get(‘config_tax’))), $product[‘recurring’][‘trial_cycle’], $frequencies[$product[‘recurring’][‘trial_frequency’]], $product[‘recurring’][‘trial_duration’]) . ‘ ‘;
}

if ($product[‘recurring’][‘duration’]) {
$recurring .= sprintf($this->language->get(‘text_payment_description’), $this->currency->format($this->tax->calculate($product[‘recurring’][‘price’] * $product[‘quantity’], $product[‘tax_class_id’], $this->config->get(‘config_tax’))), $product[‘recurring’][‘cycle’], $frequencies[$product[‘recurring’][‘frequency’]], $product[‘recurring’][‘duration’]);
} else {
$recurring .= sprintf($this->language->get(‘text_payment_cancel’), $this->currency->format($this->tax->calculate($product[‘recurring’][‘price’] * $product[‘quantity’], $product[‘tax_class_id’], $this->config->get(‘config_tax’))), $product[‘recurring’][‘cycle’], $frequencies[$product[‘recurring’][‘frequency’]], $product[‘recurring’][‘duration’]);
}
}

$data[‘products’][] = array(
‘key’ => $product[‘key’],
‘thumb’ => $image,
‘name’ => $product[‘name’],
‘model’ => $product[‘model’],
‘option’ => $option_data,
‘recurring’ => $recurring,
‘quantity’ => $product[‘quantity’],
‘stock’ => $product[‘stock’] ? true : !(!$this->config->get(‘config_stock_checkout’) || $this->config->get(‘config_stock_warning’)),
//’reward’ => ($product[‘reward’] ? sprintf($this->language->get(‘text_points’), $product[‘reward’]) : ”),
‘reward’ => ($product[‘reward’] ? sprintf($this->language->get(‘text_points’), $jifen) : ”),
‘price’ => $price,
‘total’ => $total,
‘href’ => $this->url->link(‘product/product’, ‘product_id=’ . $product[‘product_id’])
);

这样,用户在购物车看到的赠送积分的规则就变了

然后是后台管理员

2: 后台管理员对订单的操作,首先是修改添加的积分值
sale/order/info方法内

$data[‘reward’] = $order_info[‘reward’]; //获取赠送积分,自然已经自动区分了不同的会员等级

然后该方法内还有个foreach ($products as $product) 循环

$product_num = $product[‘quantity’]; //获取产品的数量
$jifen = 0; //订单规格的积分增加
foreach ($options as $option) {
//嵌入开发规格积分
$guige = $this->model_sale_order->getOrderOptionsData($option[‘product_option_id’],$product[‘product_id’],$option[‘product_option_value_id’]);
if (!empty($guige[‘points_prefix’]) && !empty($guige[‘points’])){

if ($guige[‘points_prefix’]==’+’){
$jifen = ($jifen+($guige[‘points’]*$product_num)); //因为是按数量来计算的
} else {
$jifen = ($jifen-($guige[‘points’]*$product_num));
}
}
if ($option[‘type’] != ‘file’) {
$option_data[] = array(
‘name’ => $option[‘name’],
‘value’ => $option[‘value’],
‘type’ => $option[‘type’]
);
} else {
$upload_info = $this->model_tool_upload->getUploadByCode($option[‘value’]);

if ($upload_info) {
$option_data[] = array(
‘name’ => $option[‘name’],
‘value’ => $upload_info[‘name’],
‘type’ => $option[‘type’],
‘href’ => $this->url->link(‘tool/upload/download’, ‘token=’ . $this->session->data[‘token’] . ‘&code=’ . $upload_info[‘code’], ‘SSL’)
);
}
}
}
$data[‘reward’] =($data[‘reward’]+$jifen); //把对应的规格积分进行相加

在这里引用了一个model
方法原型为:
public function getOrderOptionsData($product_option_id,$product_id,$value,$quantity){
$option_query = $this->db->query(“SELECT po.product_option_id, po.option_id, od.name, o.type FROM ” . DB_PREFIX . “product_option po
LEFT JOIN `” . DB_PREFIX . “option` o ON (po.option_id = o.option_id)
LEFT JOIN ” . DB_PREFIX . “option_description od ON (o.option_id = od.option_id)
WHERE po.product_option_id = ‘” . (int)$product_option_id . “‘
AND po.product_id = ‘” . (int)$product_id . “‘”);
$option_data=array();
if ($option_query->num_rows) {
if ($option_query->row[‘type’] == ‘select’ || $option_query->row[‘type’] == ‘radio’ || $option_query->row[‘type’] == ‘image’) {
$option_value_query = $this->db->query(“SELECT pov.option_value_id, ovd.name, pov.quantity, pov.subtract, pov.price, pov.price_prefix, pov.points, pov.points_prefix, pov.weight, pov.weight_prefix FROM ” . DB_PREFIX . “product_option_value pov LEFT JOIN ” . DB_PREFIX . “option_value ov ON (pov.option_value_id = ov.option_value_id) LEFT JOIN ” . DB_PREFIX . “option_value_description ovd ON (ov.option_value_id = ovd.option_value_id) WHERE pov.product_option_value_id = ‘” . (int)$value . “‘ AND pov.product_option_id = ‘” . (int)$product_option_id . “‘ AND ovd.language_id = ‘” . (int)$this->config->get(‘config_language_id’) . “‘”);

if ($option_value_query->num_rows) {
if ($option_value_query->row[‘price_prefix’] == ‘+’) {
$option_price += $option_value_query->row[‘price’];
} elseif ($option_value_query->row[‘price_prefix’] == ‘-‘) {
$option_price -= $option_value_query->row[‘price’];
}

if ($option_value_query->row[‘points_prefix’] == ‘+’) {
$option_points += $option_value_query->row[‘points’];
} elseif ($option_value_query->row[‘points_prefix’] == ‘-‘) {
$option_points -= $option_value_query->row[‘points’];
}

if ($option_value_query->row[‘weight_prefix’] == ‘+’) {
$option_weight += $option_value_query->row[‘weight’];
} elseif ($option_value_query->row[‘weight_prefix’] == ‘-‘) {
$option_weight -= $option_value_query->row[‘weight’];
}

if ($option_value_query->row[‘subtract’] && (!$option_value_query->row[‘quantity’] || ($option_value_query->row[‘quantity’] < $quantity))) {
$stock = false;
}

$option_data= array(
‘product_option_id’ => $product_option_id,
‘product_option_value_id’ => $value,
‘option_id’ => $option_query->row[‘option_id’],
‘option_value_id’ => $option_value_query->row[‘option_value_id’],
‘name’ => $option_query->row[‘name’],
‘value’ => $option_value_query->row[‘name’],
‘type’ => $option_query->row[‘type’],
‘quantity’ => $option_value_query->row[‘quantity’],
‘subtract’ => $option_value_query->row[‘subtract’],
‘price’ => $option_value_query->row[‘price’],
‘price_prefix’ => $option_value_query->row[‘price_prefix’],
‘points’ => $option_value_query->row[‘points’],
‘points_prefix’ => $option_value_query->row[‘points_prefix’],
‘weight’ => $option_value_query->row[‘weight’],
‘weight_prefix’ => $option_value_query->row[‘weight_prefix’]
);
}
} elseif ($option_query->row[‘type’] == ‘checkbox’ && is_array($value)) {
foreach ($value as $product_option_value_id) {
$option_value_query = $this->db->query(“SELECT pov.option_value_id, ovd.name, pov.quantity, pov.subtract, pov.price, pov.price_prefix, pov.points, pov.points_prefix, pov.weight, pov.weight_prefix FROM ” . DB_PREFIX . “product_option_value pov LEFT JOIN ” . DB_PREFIX . “option_value ov ON (pov.option_value_id = ov.option_value_id) LEFT JOIN ” . DB_PREFIX . “option_value_description ovd ON (ov.option_value_id = ovd.option_value_id) WHERE pov.product_option_value_id = ‘” . (int)$product_option_value_id . “‘ AND pov.product_option_id = ‘” . (int)$product_option_id . “‘ AND ovd.language_id = ‘” . (int)$this->config->get(‘config_language_id’) . “‘”);

if ($option_value_query->num_rows) {
if ($option_value_query->row[‘price_prefix’] == ‘+’) {
$option_price += $option_value_query->row[‘price’];
} elseif ($option_value_query->row[‘price_prefix’] == ‘-‘) {
$option_price -= $option_value_query->row[‘price’];
}

if ($option_value_query->row[‘points_prefix’] == ‘+’) {
$option_points += $option_value_query->row[‘points’];
} elseif ($option_value_query->row[‘points_prefix’] == ‘-‘) {
$option_points -= $option_value_query->row[‘points’];
}

if ($option_value_query->row[‘weight_prefix’] == ‘+’) {
$option_weight += $option_value_query->row[‘weight’];
} elseif ($option_value_query->row[‘weight_prefix’] == ‘-‘) {
$option_weight -= $option_value_query->row[‘weight’];
}

if ($option_value_query->row[‘subtract’] && (!$option_value_query->row[‘quantity’] || ($option_value_query->row[‘quantity’] < $quantity))) {
$stock = false;
}

$option_data= array(
‘product_option_id’ => $product_option_id,
‘product_option_value_id’ => $product_option_value_id,
‘option_id’ => $option_query->row[‘option_id’],
‘option_value_id’ => $option_value_query->row[‘option_value_id’],
‘name’ => $option_query->row[‘name’],
‘value’ => $option_value_query->row[‘name’],
‘type’ => $option_query->row[‘type’],
‘quantity’ => $option_value_query->row[‘quantity’],
‘subtract’ => $option_value_query->row[‘subtract’],
‘price’ => $option_value_query->row[‘price’],
‘price_prefix’ => $option_value_query->row[‘price_prefix’],
‘points’ => $option_value_query->row[‘points’],
‘points_prefix’ => $option_value_query->row[‘points_prefix’],
‘weight’ => $option_value_query->row[‘weight’],
‘weight_prefix’ => $option_value_query->row[‘weight_prefix’]
);
}
}
} elseif ($option_query->row[‘type’] == ‘text’ || $option_query->row[‘type’] == ‘textarea’ || $option_query->row[‘type’] == ‘file’ || $option_query->row[‘type’] == ‘date’ || $option_query->row[‘type’] == ‘datetime’ || $option_query->row[‘type’] == ‘time’) {
$option_data= array(
‘product_option_id’ => $product_option_id,
‘product_option_value_id’ => ”,
‘option_id’ => $option_query->row[‘option_id’],
‘option_value_id’ => ”,
‘name’ => $option_query->row[‘name’],
‘value’ => $value,
‘type’ => $option_query->row[‘type’],
‘quantity’ => ”,
‘subtract’ => ”,
‘price’ => ”,
‘price_prefix’ => ”,
‘points’ => ”,
‘points_prefix’ => ”,
‘weight’ => ”,
‘weight_prefix’ => ”
);
}
}
return $option_data;
}
最后是对积分进行增加和减少的操作
sale/order/addReward()添加积分和removeReward()移除积分

我们来从写addReward()
public function addReward() {
$this->load->language(‘sale/order’);

$json = array();

if (!$this->user->hasPermission(‘modify’, ‘sale/order’)) {
$json[‘error’] = $this->language->get(‘error_permission’);
$json[‘error’]= ‘后台API错误4’;
} else {
if (isset($this->request->get[‘order_id’])) {
$order_id = $this->request->get[‘order_id’];
} else {
$order_id = 0;
}

$this->load->model(‘sale/order’);

$order_info = $this->model_sale_order->getOrder($order_id);
//嵌入开发添加积分开始
$data[‘products’] = array(); //订单产品集
$products = $this->model_sale_order->getOrderProducts($order_id); //获取订单的所有产品
foreach ($products as $product) {
$option_data = array(); //产品规格
$options = $this->model_sale_order->getOrderOptions($order_id, $product[‘order_product_id’]); //获取规格
$product_num = $product[‘quantity’]; //获取产品的数量
$jifen = 0; //订单规格的积分增加
foreach ($options as $option) {
$guige = $this->model_sale_order->getOrderOptionsData($option[‘product_option_id’],$product[‘product_id’],$option[‘product_option_value_id’],$product_num);
if (!empty($guige[‘points_prefix’]) && !empty($guige[‘points’])){
if ($guige[‘points_prefix’]==’+’){
$jifen = ($jifen+($guige[‘points’]*$product_num)); //因为是按数量来计算的
} else {
$jifen = ($jifen-($guige[‘points’]*$product_num));
}
}
}
}
$reward =($order_info[‘reward’]+$jifen); //把对应的规格积分进行相加
//嵌入开发添加积分结束
if ($order_info && $order_info[‘customer_id’] && ($reward > 0)) {
$this->load->model(‘sale/customer’);

$reward_total = $this->model_sale_customer->getTotalCustomerRewardsByOrderId($order_id);

if (!$reward_total) {
//$this->model_sale_customer->addReward($order_info[‘customer_id’], $this->language->get(‘text_order_id’) . ‘ #’ . $order_id, $order_info[‘reward’], $order_id);
$this->model_sale_customer->addReward($order_info[‘customer_id’], $this->language->get(‘text_order_id’) . ‘ #’ . $order_id, $reward, $order_id);
}
}
$json[‘success’] = $this->language->get(‘text_reward_added’);
}
$this->response->addHeader(‘Content-Type: application/json’);
$this->response->setOutput(json_encode($json));
}
removeReward()的话,是根据订单的ID来实现直接删除对应ID,这个不需要修改,但为了避免员工在后台进行到底积分赠送,用户购买之后又把积分移除从新生成积分的刷分过程
直接关闭移除功能

通过清心醉

Opencart多站点BUG修复

今天做了下OPENCART内的外贸多语言多站点的开发,在OPENCART里默认有一个站点,如果有新添加站点后,重新修改默认站点的数据,导致默认站点的config_url不存在的现象。

先来分析下OPENCART修改默认店铺的流程:

默认的站点,使用的是setting/setting,修改的话不存在store_id的参数,如果是其他站点store_id为必须。

问题就来了。 因为默认站点不存在config_url的配置参数:

来看看setting的edit模型:
public function editSetting($code, $data, $store_id = 0) {
$this->db->query(“DELETE FROM `” . DB_PREFIX . “setting` WHERE store_id = ‘” . (int)$store_id . “‘ AND `code` = ‘” . $this->db->escape($code) . “‘”);

foreach ($data as $key => $value) {
if (substr($key, 0, strlen($code)) == $code) {
if (!is_array($value)) {
$this->db->query(“INSERT INTO ” . DB_PREFIX . “setting SET store_id = ‘” . (int)$store_id . “‘, `code` = ‘” . $this->db->escape($code) . “‘, `key` = ‘” . $this->db->escape($key) . “‘, `value` = ‘” . $this->db->escape($value) . “‘”);
} else {
$this->db->query(“INSERT INTO ” . DB_PREFIX . “setting SET store_id = ‘” . (int)$store_id . “‘, `code` = ‘” . $this->db->escape($code) . “‘, `key` = ‘” . $this->db->escape($key) . “‘, `value` = ‘” . $this->db->escape(serialize($value)) . “‘, serialized = ‘1’”);
}
}
}
}

在执行之前,OC已经完全的删除STORE=0的所有参数信息,然后重新写入

这样因为没有了默认的站点配置,就无法对基础站点的信息进行完整的区分,当然config.php里的文件就有定义常量HTTP_SERVER和HTTPS_SERVER但是多语言的实现URL的问题就会比较麻烦。

解决方法:

setting.tpl模型中添加个

<input type=”text” name=”config_url” value=”<?php echo HTTP_CATALOG; ?>” id=”input-owner” class=”form-control” />

 

 

通过清心醉

分析Opencart前端获取幻灯片的流程

小O这点做的和小M有点像

通过top/left/right布局,来调用对应的模型数据

$modules = $this->model_design_layout->getLayoutModules($layout_id, ‘content_top’);

#->根据布局ID和位置来提取布局内的模块

#->模型中读取layout_module根据排序提取布局ID和位置对应的模型数据

#->数据中会有一个$module[‘code’]的参数,使用的是类型.ID做连接

#->$part = explode(‘.’, $module[‘code’]);

#->然后使用foreach循环提取code值

$setting_info = $this->model_extension_module->getModule($part[1]);  #->根据PART来获取,PART稍后分析
#->操作数据模型-> module WHERE module_id='”.(int)$module_id.”‘”;

public function getModule($module_id) {
$query = $this->db->query(“SELECT * FROM ” . DB_PREFIX . “module WHERE module_id = ‘” . (int)$module_id . “‘”);
if ($query->row) {
return json_decode($query->row[‘setting’], true);
} else {
return array();
}
}

#->模型中,如果有存在对应的模型ID,解码JSON的setting数据到数组并返回

#->来看看JSON原型:{“name”:”Home Page”,”banner_id”:”7″,”width”:”1140″,”height”:”380″,”status”:”1″}

#->可以了,提取了有banner_id参数了

#->接下来$part[0]其实应该是类型 html/slideshow等

#->比如slideshow就是幻灯了

#->自然就要包含/module/slideshow控制器了

#->$data[‘modules’][] = $this->load->controller(‘module/’ . $part[0], $setting_info);

#-> 这样,在ControllerModuleSlideshow控制器里,index()方法中的参数也就存在了

最后作者说下part的参数值:通过打印出我们可以看到:

array(2) { [0]=> string(9) “slideshow” [1]=> string(2) “27” }
array(2) { [0]=> string(4) “html” [1]=> string(2) “32” }

第一就是类型了,第二是module的参数ID;这样就可以很精准的获取了!

 

通过清心醉

OPENCART无法发邮件-MAIL使用SMTP类文件

最近发现OPENCART发邮件系统有点问题,不知道是配置问题还是怎么的,老是出现错误.

由于邮件系统都是使用/system/library/mail.php里的mail函数

而默认使用方法是:

$mail = new Mail();
$mail->protocol = $this->config->get(‘config_mail_protocol’);
$mail->parameter = $this->config->get(‘config_mail_parameter’);
$mail->smtp_hostname = $this->config->get(‘config_mail_smtp_hostname’);
$mail->smtp_username = $this->config->get(‘config_mail_smtp_username’);
$mail->smtp_password = html_entity_decode($this->config->get(‘config_mail_smtp_password’), ENT_QUOTES, ‘UTF-8’);
$mail->smtp_port = $this->config->get(‘config_mail_smtp_port’);
$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(html_entity_decode($this->config->get(‘config_name’), ENT_QUOTES, ‘UTF-8′));
$mail->setSubject($subject);
$mail->setText($message);
$mail->send();

在类里对成员protocol 进行判断使用MSTP还是SENDMAIL方法

为了保证OPENCART的核心可以正常的使用,作者修改了SMTP的类方法,但只能使用SMTP的类操作,暂未对SENDMAIL进行操作.

使用方法和默认的操作相同

$mail=new mail();
$mail->parameter=’13823819185@139.com’; #抄送一份
$mail->smtp_hostname=’smtp.ym.163.com’;  #邮箱地址
$mail->smtp_username=’admin@qingxinzui.com’;  #用户名
$mail->smtp_password=’************’;  #密码
$mail->smtp_port=’25’; #端口
$mail->smtp_timeout=’30’; #超时施加 //默认5,进行重写
$mailto=”收件人@qingxinzui.com”;
$mailtitle=”测试邮件”; //邮件标题
$mailbody =”<center><div style=’font-size:24px;color:red;’>标题</div></center>”;
$mailbody.=”<table align=’center’ width=’50%’ border=’1′ cellpadding=’2′ cellspacing=’0′>”;
$mailbody.=”<tr><td><center>联系人</center></td><td>名字</td></tr>”;
$mailbody.=”<tr><td><center>联系电话</center></td><td>电话</td></tr>”;
$mailbody.=”<tr><td><center>联系地址</center></td><td>地址</td></tr>”;
$mailbody.=”<tr><td><center>店铺名称</center></td><td>店名</td></tr>”;
$mailbody.=”</table>”;
$mail->setTo($mailto); //收件人
$mail->setFrom($mail->smtp_username); //发件人
$mail->setSubject(html_entity_decode($mailtitle, ENT_QUOTES, ‘UTF-8′));
$mail->setText($mailbody);
$mail->send();

以下为class mail类的封装:

class mail
{
protected $to; //收件人
protected $from; //发件人
protected $subject;
protected $text;
public $protocol;
public $smtp_hostname; #主机地址 smtp.qq.com
public $smtp_username; #用户名
public $smtp_password; #密码
public $smtp_port;  #邮件端口
public $smtp_timeout; #超时时间
public $newline;
public $verp;
public $parameter; //#附加发送
private $ishostname; //主机值保留localhost
public $log_file;
public $debug;
public $auth; //验证
private $sock;

function __construct()
{
$this->smtp_port=25; //构造方法给予端口赋默认值
$this->smtp_timeout=30; //构造方法给予超时赋默认值
$this->ishostname  = “localhost”; //默认值,禁止外部修改
$this->debug=TRUE; //开启调试
$this->log_file=””; //日志文件
$this->sock=FALSE;
$this->protocol=’SMTP’; #邮件类型
$this->auth=TRUE;
$this->newline = “\n”;
$this->verp = false;
$this->parameter=”;
}

public function setTo($to) {
$this->to = $to;
}

public function setFrom($from) {
$this->from = $from;
}

public function setReplyTo($reply_to) {
$this->reply_to = $reply_to;
}

public function setSubject($subject) {
$this->subject = $subject;
}

public function setText($text) {
$this->text = $text;
}

function send()
{
$this->sendmail($this->to, $this->from, $this->subject,$this->text,’HTML’,$this->parameter);
}

private function sendmail($to, $from, $subject = “”, $body = “”, $mailtype, $cc = “”, $bcc = “”, $additional_headers = “”)
{
//收件人,发件人,邮件标题,邮件内容,邮件类型,抄送等参数
$header= “”;
$mail_from = $this->get_address($this->strip_comment($from));
$body= mb_ereg_replace(“(^|(\r\n))(\\.)”, “\\1.\\3”, $body);
$header .= “MIME-Version:1.0\r\n”;
if ($mailtype == “HTML”) {
$header .= ‘Content-type: text/html; charset=utf-8’ . “\r\n”;
}
$header .= “To: ” . $to . “\r\n”;
if ($cc != “”) {
$header .= “Cc: ” . $cc . “\r\n”;
}
$header .= “From: ” .$from . “\r\n”;
$header .= “Subject: ” . $subject . “\r\n”;
$header .= $additional_headers;
$header .= “Date: ” . date(“r”) . “\r\n”;
$header .= “X-Mailer:By (PHP/” . phpversion() . “)\r\n”;
list($msec, $sec) = explode(” “, microtime());
$header .= “Message-ID: <” . date(“YmdHis”, $sec) . “.” . ($msec * 1000000) . “.” . $mail_from . “>\r\n”;
$TO = explode(“,”, $this->strip_comment($to));

if ($cc != “”) {
$TO = array_merge($TO, explode(“,”, $this->strip_comment($cc))); //合并一个或多个数组
}

if ($bcc != “”) {
$TO = array_merge($TO, explode(“,”, $this->strip_comment($bcc)));
}
$sent = TRUE;
foreach ($TO as $rcpt_to) {
$rcpt_to = $this->get_address($rcpt_to);
if (!$this->smtp_sockopen($rcpt_to)) {
$this->log_write(“Error: Cannot send email to ” . $rcpt_to . “\n”);
$sent = FALSE;
continue;

}
if ($this->smtp_send($this->ishostname, $mail_from, $rcpt_to, $header, $body)) {
$this->log_write(“E-mail has been sent to <” . $rcpt_to . “>\n”);
} else {
$this->log_write(“Error: Cannot send email to <” . $rcpt_to . “>\n”);
$sent = FALSE;
}
fclose($this->sock);
$this->log_write(“Disconnected from remote host\n”);
}
echo “<br>”;
return $sent;
}

private function smtp_send($helo, $from, $to, $header, $body = “”)
{
if (!$this->smtp_putcmd(“HELO”, $helo)) {
return $this->smtp_error(“sending HELO command”);
}
#auth
if ($this->auth) {
if (!$this->smtp_putcmd(“AUTH LOGIN”, base64_encode($this->smtp_username))) {
return $this->smtp_error(“sending HELO command”);
}

if (!$this->smtp_putcmd(“”, base64_encode($this->smtp_password))) {
return $this->smtp_error(“sending HELO command”);
}
}
#
if (!$this->smtp_putcmd(“MAIL”, “FROM:<” . $from . “>”)) {
return $this->smtp_error(“sending MAIL FROM command”);
}

if (!$this->smtp_putcmd(“RCPT”, “TO:<” . $to . “>”)) {
return $this->smtp_error(“sending RCPT TO command”);
}

if (!$this->smtp_putcmd(“DATA”)) {
return $this->smtp_error(“sending DATA command”);
}

if (!$this->smtp_message($header, $body)) {
return $this->smtp_error(“sending message”);
}

if (!$this->smtp_eom()) {
return $this->smtp_error(“sending <CR><LF>.<CR><LF> [EOM]”);
}

if (!$this->smtp_putcmd(“QUIT”)) {
return $this->smtp_error(“sending QUIT command”);
}

return TRUE;
}

private function smtp_sockopen($address)
{
if ($this->smtp_hostname == “”) {
return $this->smtp_sockopen_mx($address);
} else {
return $this->smtp_sockopen_relay();
}
}

private function smtp_sockopen_relay()
{
$this->log_write(“Trying to ” . $this->smtp_hostname . “:” . $this->smtp_port . “\n”);
if (empty($this->smtp_timeout))
{
$this->smtp_timeout=5;
}
$this->sock = @fsockopen($this->smtp_hostname, $this->smtp_port, $errno, $errstr, $this->smtp_timeout);

//var_dump($this->sock);die();

if (!($this->sock && $this->smtp_ok())) {
$this->log_write(“Error: Cannot connenct to relay host ” . $this->smtp_hostname . “\n”);
$this->log_write(“Error: ” . $errstr . ” (” . $errno . “)\n”);
return FALSE;
}
$this->log_write(“Connected to relay host ” . $this->smtp_hostname . “\n”);
return TRUE;
}

private function smtp_sockopen_mx($address)
{
$domain = ereg_replace(“^.+@([^@]+)$”, “\\1”, $address);
if (!@getmxrr($domain, $MXHOSTS)) {
$this->log_write(“Error: Cannot resolve MX \”” . $domain . “\”\n”);
return FALSE;
}
foreach ($MXHOSTS as $host) {
$this->log_write(“Trying to ” . $host . “:” . $this->smtp_port . “\n”);
$this->sock = @fsockopen($host, $this->smtp_port, $errno, $errstr, $this->smtp_timeout);
if (!($this->sock && $this->smtp_ok())) {
$this->log_write(“Warning: Cannot connect to mx host ” . $host . “\n”);
$this->log_write(“Error: ” . $errstr . ” (” . $errno . “)\n”);
continue;
}
$this->log_write(“Connected to mx host ” . $host . “\n”);
return TRUE;
}
$this->log_write(“Error: Cannot connect to any mx hosts (” . implode(“, “, $MXHOSTS) . “)\n”);
return FALSE;
}

private function smtp_message($header, $body)
{
fputs($this->sock, $header . “\r\n” . $body);
$this->smtp_debug(“> ” . str_replace(“\r\n”, “\n” . “> “, $header . “\n> ” . $body . “\n> “));

return TRUE;
}

private function smtp_eom()
{
fputs($this->sock, “\r\n.\r\n”);
$this->smtp_debug(“. [EOM]\n”);

return $this->smtp_ok();
}

private function smtp_ok()
{
$response = str_replace(“\r\n”, “”, fgets($this->sock, 512));
$this->smtp_debug($response . “\n”);

if (!mb_ereg(“^[23]”, $response)) {
fputs($this->sock, “QUIT\r\n”);
fgets($this->sock, 512);
$this->log_write(“Error: Remote host returned \”” . $response . “\”\n”);
return FALSE;
}
return TRUE;
}

private function smtp_putcmd($cmd, $arg = “”)
{
if ($arg != “”) {
if ($cmd == “”)
$cmd = $arg;
else
$cmd = $cmd . ” ” . $arg;
}

fputs($this->sock, $cmd . “\r\n”);
$this->smtp_debug(“> ” . $cmd . “\n”);

return $this->smtp_ok();
}

private function smtp_error($string)
{
$this->log_write(“Error: Error occurred while ” . $string . “.\n”);
return FALSE;
}

private function log_write($message)
{
$this->smtp_debug($message);

if ($this->log_file == “”) {
return TRUE;
}

$message = date(“M d H:i:s “) . get_current_user() . “[” . getmypid() . “]: ” . $message;
if (!@file_exists($this->log_file) || !($fp = @fopen($this->log_file, “a”))) {
$this->smtp_debug(“Warning: Cannot open log file \”” . $this->log_file . “\”\n”);
return FALSE;
}
flock($fp, LOCK_EX);
fputs($fp, $message);
fclose($fp);

return TRUE;
}

private function strip_comment($address)
{
$comment = “\\([^()]*\\)”;
while (mb_ereg($comment, $address)) {
$address = mb_ereg_replace($comment, “”, $address);
}

return $address;
}

private function get_address($address)
{
$address = mb_ereg_replace(“([ \t\r\n])+”, “”, $address);
$address = mb_ereg_replace(“^.*<(.+)>.*$”, “\\1”, $address);

return $address;
}

private function smtp_debug($message)
{
if ($this->debug) {
echo $message . “<br>”;
}
}

private function get_attach_type($image_tag) //
{

$filedata = array();

$img_file_con = fopen($image_tag, “r”);
unset($image_data);
while ($tem_buffer = AddSlashes(fread($img_file_con, filesize($image_tag))))
$image_data .= $tem_buffer;
fclose($img_file_con);
$filedata[‘context’]  = $image_data;
$filedata[‘filename’] = basename($image_tag);
$extension            = substr($image_tag, strrpos($image_tag, “.”), strlen($image_tag) – strrpos($image_tag, “.”));
switch ($extension) {
case “.gif”:
$filedata[‘type’] = “image/gif”;
break;
case “.gz”:
$filedata[‘type’] = “application/x-gzip”;
break;
case “.htm”:
$filedata[‘type’] = “text/html”;
break;
case “.html”:
$filedata[‘type’] = “text/html”;
break;
case “.jpg”:
$filedata[‘type’] = “image/jpeg”;
break;
case “.tar”:
$filedata[‘type’] = “application/x-tar”;
break;
case “.txt”:
$filedata[‘type’] = “text/plain”;
break;
case “.zip”:
$filedata[‘type’] = “application/zip”;
break;
default:
$filedata[‘type’] = “application/octet-stream”;
break;
}
return $filedata;
}
}

通过清心醉

PHP开发之OPENCART多用户权限控制

由于使用OPENCART管理员的核心代码进行二次开发,很多时候用户的操作权限是很重要的,否则就会出现越权修改其他商家的产品等信息.

由于现在作者编写的是B2O2O的类型,暂时还在O2O的开发阶段(B2因为是多域名区分而已,一样需要多用户实现,所以先把重心放在O2O上用户数据的区分上)

作者昨天写了一个图片库区分的方法,该方法类似,主要针对于常用的产品及用户信息(后期B2整合O2O的时候还需要对分类进行划分,思路相同)权限区分功能.

1:用户的登陆数据表是唯一的,有独立的唯一性;

2:用户上传的产品末尾添加字段:product_laction_id; //

 

OPENCART判断用户是否登陆,其实是判断是否存在$this->session->data[‘user_id’]的参数值

session是一个对象,data是session对象内的一个数组.

在登陆之后,可自行创建新的参数值,比如作者创建的是:

$this->session->data[‘location_user_id’]

虽然值是相同的,但访问权限用任意一个就可以了

 

为什么呢? 因为OPENCART触发的页面都是以GET的方式获取,如果说你有很强大的前端工程师支撑你完全可以纯AJAX化.

具体是唯一,GET的时候,我们就必须要判断下用户的合法性了

假设有两个用户ID

ID1=100;

ID2=200;

/index.php?route=localisation/location&token=TQEAMbDBFvt6CmRbYszezUn9GmozQQjr&location_user_id=100

我们看上面的链接中,请求localisation里的location控制器,调用默认的index方法

token为OPENCART的加密权限方式,但只是用于区分用户是否已登陆

最后一个参数location_user_id=100;

就是打开控制器之后,根据GET的location_user_id的值,显示用户ID=100的商家信息

直接改200就变ID=200的商家信息了,就会受到恶意的修改.

方法:针对GET的location_user_id与$this->session->data[‘location_user_id’]判断,不存在即die();

不过建议,最好在执行模型SQL语句的时候强制执行.

不管UPDATE还是DELETE.统一WHERE user_id= ‘$location_user_id’;

 

通过清心醉

opencart-B2B-O2O-C2C开发之区分用户的图片操作方法

不管B2B,O2O,C2C,都是要完整的区分用户的目录结构.因为后台都是多用户操作.

在这作者假设你已经可以使用OPENCART二次开发来划分用户的登陆及显示数据.

假设创建一个用户之后,创建一个图片目录,目录名为用户的编号(假设编号$userid为1001);

mkdir(DIR_IMAGE . ‘catalog/’.$this->session->data[‘user_id’] , 0777);

chmod(DIR_IMAGE . ‘catalog/’.$this->session->data[‘user_id’] , 0777);

然后是用户独立后台上传图片,创建目录,进入目录时的方法:

在FileManager控制器中替换掉:

if (isset($this->request->get[‘directory’]))
{
$directory = DIR_IMAGE . ‘catalog/’. $this->request->get[‘directory’];
} else
{
$directory = DIR_IMAGE . ‘catalog/’.$this->session->data[‘user_id’];
}

 

 

 

通过清心醉

opencart开发前台显示指定分类的产品模组(块)

和开发支付方式一样,开发模块需要有对应的MVC+L参数,并且Language里必须有$_[‘header_title’]模块名.同时该模型名必须是唯一的.

opencart后台会循环读取/controller/module里的模块PHP文件代码,然后根据每个文件的$_[‘header_title’]获取模块的标题名称.

同时该文件的类名(比如作者现在开发显示分类的产品,类是:class ControllerModuleCategoryproduct extends Controller) .

类名是Categoryproduct,然后根据命名规则,查询extension表内的code有无对应的参数值,如果没有,用户可以安装,否则是添加更多.

我们来看看extension表内是如何区分的:

extension_id=>’27’,type=>’module’,code=’categoryproduct’;

//类型为module里的文件,参数是类名为categoryproduct的模块,安装后就可以看到

extension_id=>’28’,type=>’payment’,code=’paypal’;

//类型为payment支付扩展里的文件,参数是类名为paypal的模块.

好了,说了数据库表内的关系,来看看完整控制器吧(视图请自行编写)

class ControllerModuleCategoryproduct extends Controller {
private $error = array();

public function index() {
$this->load->language(‘module/categoryproduct’);

$this->document->setTitle($this->language->get(‘heading_title’));

$this->load->model(‘extension/module’);

if (($this->request->server[‘REQUEST_METHOD’] == ‘POST’) && $this->validate()) {
if (!isset($this->request->get[‘module_id’])) {
$this->model_extension_module->addModule(‘categoryproduct’, $this->request->post);
} else {
$this->model_extension_module->editModule($this->request->get[‘module_id’], $this->request->post);
}

$this->session->data[‘success’] = $this->language->get(‘text_success’);

$this->response->redirect($this->url->link(‘extension/module’, ‘token=’ . $this->session->data[‘token’], ‘SSL’));
}

$data[‘heading_title’] = $this->language->get(‘heading_title’);

$data[‘text_edit’] = $this->language->get(‘text_edit’);
$data[‘text_enabled’] = $this->language->get(‘text_enabled’);
$data[‘text_disabled’] = $this->language->get(‘text_disabled’);

$data[‘entry_name’] = $this->language->get(‘entry_name’);
$data[‘entry_product’] = $this->language->get(‘entry_product’);
$data[‘entry_limit’] = $this->language->get(‘entry_limit’);
$data[‘entry_width’] = $this->language->get(‘entry_width’);
$data[‘entry_height’] = $this->language->get(‘entry_height’);
$data[‘entry_status’] = $this->language->get(‘entry_status’);

$data[‘help_product’] = $this->language->get(‘help_product’);

$data[‘button_save’] = $this->language->get(‘button_save’);
$data[‘button_cancel’] = $this->language->get(‘button_cancel’);

if (isset($this->error[‘warning’])) {
$data[‘error_warning’] = $this->error[‘warning’];
} else {
$data[‘error_warning’] = ”;
}

if (isset($this->error[‘name’])) {
$data[‘error_name’] = $this->error[‘name’];
} else {
$data[‘error_name’] = ”;
}

if (isset($this->error[‘width’])) {
$data[‘error_width’] = $this->error[‘width’];
} else {
$data[‘error_width’] = ”;
}

if (isset($this->error[‘height’])) {
$data[‘error_height’] = $this->error[‘height’];
} else {
$data[‘error_height’] = ”;
}

$data[‘breadcrumbs’] = array();

$data[‘breadcrumbs’][] = array(
‘text’ => $this->language->get(‘text_home’),
‘href’ => $this->url->link(‘common/dashboard’, ‘token=’ . $this->session->data[‘token’], ‘SSL’)
);

$data[‘breadcrumbs’][] = array(
‘text’ => $this->language->get(‘text_module’),
‘href’ => $this->url->link(‘extension/module’, ‘token=’ . $this->session->data[‘token’], ‘SSL’)
);

if (!isset($this->request->get[‘module_id’])) {
$data[‘breadcrumbs’][] = array(
‘text’ => $this->language->get(‘heading_title’),
‘href’ => $this->url->link(‘module/categoryproduct’, ‘token=’ . $this->session->data[‘token’], ‘SSL’)
);
} else {
$data[‘breadcrumbs’][] = array(
‘text’ => $this->language->get(‘heading_title’),
‘href’ => $this->url->link(‘module/categoryproduct’, ‘token=’ . $this->session->data[‘token’] . ‘&module_id=’ . $this->request->get[‘module_id’], ‘SSL’)
);
}

if (!isset($this->request->get[‘module_id’])) {
$data[‘action’] = $this->url->link(‘module/categoryproduct’, ‘token=’ . $this->session->data[‘token’], ‘SSL’);
} else {
$data[‘action’] = $this->url->link(‘module/categoryproduct’, ‘token=’ . $this->session->data[‘token’] . ‘&module_id=’ . $this->request->get[‘module_id’], ‘SSL’);
}

$data[‘cancel’] = $this->url->link(‘extension/module’, ‘token=’ . $this->session->data[‘token’], ‘SSL’);

if (isset($this->request->get[‘module_id’]) && ($this->request->server[‘REQUEST_METHOD’] != ‘POST’)) {
$module_info = $this->model_extension_module->getModule($this->request->get[‘module_id’]);
}

$data[‘token’] = $this->session->data[‘token’];

if (isset($this->request->post[‘name’])) {
$data[‘name’] = $this->request->post[‘name’];
} elseif (!empty($module_info)) {
$data[‘name’] = $module_info[‘name’];
} else {
$data[‘name’] = ”;
}

$this->load->model(‘catalog/category’);  //使用分类

$data[‘categorys’] = array();
//定义分类数组

if (isset($this->request->post[‘category’]))
{
$data[‘categorys’] = $this->request->post[‘category’];
//如果有存在POST过来的category,直接视图上使用
}
else
{   //否则
$categorys = $this->model_catalog_category->getCategoryAll();
foreach ($categorys as $category)
{
$data[‘categorys’][] = array(
‘category_id’ => $category[‘category_id’],
‘name’       => $category[‘name’]
);
}
}
if (isset($this->request->post[‘limit’])) {
$data[‘limit’] = $this->request->post[‘limit’];
} elseif (!empty($module_info)) {
$data[‘limit’] = $module_info[‘limit’];
} else {
$data[‘limit’] = 8;
}

if (isset($this->request->post[‘width’])) {
$data[‘width’] = $this->request->post[‘width’];
} elseif (!empty($module_info)) {
$data[‘width’] = $module_info[‘width’];
} else {
$data[‘width’] = 200;
}

if (isset($this->request->post[‘height’])) {
$data[‘height’] = $this->request->post[‘height’];
} elseif (!empty($module_info)) {
$data[‘height’] = $module_info[‘height’];
} else {
$data[‘height’] = 300;
}

if (isset($this->request->post[‘status’])) {
$data[‘status’] = $this->request->post[‘status’];
} elseif (!empty($module_info)) {
$data[‘status’] = $module_info[‘status’];
} else {
$data[‘status’] = ”;
}

$data[‘header’] = $this->load->controller(‘common/header’);
$data[‘column_left’] = $this->load->controller(‘common/column_left’);
$data[‘footer’] = $this->load->controller(‘common/footer’);

$this->response->setOutput($this->load->view(‘module/categoryproduct.tpl’, $data));
}

protected function validate() {
if (!$this->user->hasPermission(‘modify’, ‘module/categoryproduct’)) {
$this->error[‘warning’] = $this->language->get(‘error_permission’);
}

if ((utf8_strlen($this->request->post[‘name’]) < 3) || (utf8_strlen($this->request->post[‘name’]) > 64)) {
$this->error[‘name’] = $this->language->get(‘error_name’);
}

if (!$this->request->post[‘width’]) {
$this->error[‘width’] = $this->language->get(‘error_width’);
}

if (!$this->request->post[‘height’]) {
$this->error[‘height’] = $this->language->get(‘error_height’);
}

return !$this->error;
}
}

OPENCART的模块如果有执行安装,数据不单只是追加到extension表.为什么呢?

因为opencart一个模块可以在多个地方使用.比如作者现在开发的主页显示指定分类的产品

可以选择分类ID为1,也可以添加为2,也可以添加为3等等.如果是同一个页面,一个位置,只是上下位不同,可以使用同一个视图类型.

来看看OPENCART是如何实现多元化的:

在module表内:

module_id=>模块ID

name=>模块名字(多元化的关键,一个模块派生出来的多个名字命名)

code=>模块参数(categoryproduct)

setting=>数值(JSON类型);

接着是前台获取模块参数的控制器,文中使用的视图请自行编写

class ControllerModuleCategoryproduct extends Controller
{
public function index($setting)
{
$this->load->language(‘module/categoryproduct’);
$data[‘heading_title’] = $this->language->get(‘categoryproduct’);
$this->load->model(‘catalog/category’);
$data[‘categoryname’]=$this->model_catalog_category->getCategoryname($setting[‘category’]);

$data[‘text_tax’] = $this->language->get(‘text_tax’);

$data[‘button_cart’] = $this->language->get(‘button_cart’);
$data[‘button_wishlist’] = $this->language->get(‘button_wishlist’);
$data[‘button_compare’] = $this->language->get(‘button_compare’);

if (!$setting[‘limit’]) {
$setting[‘limit’] = 4;
}  //如果没设置数量,那么数量为4

$this->load->model(‘catalog/product’);
$this->load->model(‘tool/image’);
//获取分类产品及图行工具模型
$category_id=$setting[‘category’]; //获取分类ID
$products_id=$this->model_catalog_product->getCategoryProducts($category_id);
$data[‘products’]=array();
for ($o=0;$o<count($products_id);$o++)
{
if ($o==$setting[‘limit’]) //判断循环提取的数量是否达到了要求
{
break;
}
$product_info = $this->model_catalog_product->getProduct($products_id[$o][‘product_id’]);
if ($product_info)
{
if ($product_info[‘image’])
{
$image = $this->model_tool_image->resize($product_info[‘image’], $setting[‘width’], $setting[‘height’]);
} else
{
$image = $this->model_tool_image->resize(‘placeholder.png’, $setting[‘width’], $setting[‘height’]);
}

if (($this->config->get(‘config_customer_price’) && $this->customer->isLogged()) || !$this->config->get(‘config_customer_price’)) {
$price = $this->currency->format($this->tax->calculate($product_info[‘price’], $product_info[‘tax_class_id’], $this->config->get(‘config_tax’)));
} else {
$price = false;
}

if ((float)$product_info[‘special’]) {
$special = $this->currency->format($this->tax->calculate($product_info[‘special’], $product_info[‘tax_class_id’], $this->config->get(‘config_tax’)));
} else {
$special = false;
}

if ($this->config->get(‘config_tax’)) {
$tax = $this->currency->format((float)$product_info[‘special’] ? $product_info[‘special’] : $product_info[‘price’]);
} else {
$tax = false;
}

if ($this->config->get(‘config_review_status’)) {
$rating = $product_info[‘rating’];
} else {
$rating = false;
}

$data[‘products’][$o] = array(
‘product_id’  => $product_info[‘product_id’],
‘thumb’       => $image,
‘name’        => $product_info[‘name’],
‘description’ => utf8_substr(strip_tags(html_entity_decode($product_info[‘description’], ENT_QUOTES, ‘UTF-8’)), 0, $this->config->get(‘config_product_description_length’)) . ‘..’,
‘price’       => $price,
‘special’     => $special,
‘tax’         => $tax,
‘rating’      => $rating,
‘href’        => $this->url->link(‘product/product’, ‘product_id=’ . $product_info[‘product_id’])
);
}
}
if ($data[‘products’])
{
if (file_exists(DIR_TEMPLATE . $this->config->get(‘config_template’) . ‘/template/module/categoryproduct.tpl’)) {
return $this->load->view($this->config->get(‘config_template’) . ‘/template/module/categoryproduct.tpl’, $data);
} else {
return $this->load->view(‘default/template/module/categoryproduct.tpl’, $data);
}
}
}
}

 

 

通过清心醉

opencart是如何实现管理员登陆的?

首先我们要知道一个:MVC设计模式的规则.

一般都是使用一个文件来做分发控制(如果是MAGNETO还有路由控制,当然OPENCART也可以使用VQMOD实现).

index.php就是OPENCART的分发控制:

看看这一句:$controller->addPreAction(new Action(‘common/login/check’));

实例化后的$controller调用方法:

注:OPENCART的一切数据基本使用$this->session对象,而用户基本使用$this->user对象.在这些对象里封装了获取购物车数据,用户数据等方法.

控制流程:

执行check()方法,如果不存在user_id($this->user->isLogged()的返回值),跳转到common/login的index方法(index为默认方法,具体可以查看controller的封装)

index()中,默认再一次判断是否存在有user对象的user_id值

如果存在跳转仪表盘.

接着,判断是否存在有POST的参数和是否合法:

if (($this->request->server[‘REQUEST_METHOD’] == ‘POST’) && $this->validate())

validate的方法原型::

/**
* 判断用户的登陆参数
* 错误的话返回flase;
*
* @return boolean
*/
protected function validate() {

if (!isset($this->request->post[‘username’])
|| !isset($this->request->post[‘password’])
|| !$this->user->shangjialogin($this->request->post[‘username’], $this->request->post[‘password’]))
{
$this->error[‘warning’] = $this->language->get(‘error_login’);
}
return !$this->error;
}

上文的红色字体中,就是作者新增加的模型方法,如果用户密码正确,返回true,否则false;

这样,就需要在模型里对$this->user类的私有成员user_id进行赋值.

成功达到管理员登陆的效果!

 

通过清心醉

opencart获取title的标准方法

PHP内置就有_get和_set的方式,虽然作者也没用过。但其实这两个魔术方法,_get就是获取数据,_set就是写入数据,这一点大家都应该有听过。

再来是OPENCART的获取页面标题的TITLE的方法。

由于OPENCART是使用MVC+L的设计模式,在C控制器层中,部分会有返回视图,比如头部(headert.tpl)和尾部(footer.tpl),这样设计的好处就是,头尾基本不会变,变的只是内容体,而头部有个需要变更的就是TITLE了。(至于描述及关键字一般不考虑,如果是产品一般直接UPDATE成产品的参数)

直接来上代码解释

假设我做了一个后台的支付管理插件,那么后台的支付管理插件的TITLE的获取是:

$this->load->language(‘paymunt/paypal’); //获取贝宝语言包
$this->document->setTitle($this->language->get(‘heading_title’));

第二句就是重中之重了。

如果你有用心观察OPENCART的每一个language都会发现第一个基本就是$_[‘heading_title’]。

没错,这就是给页面的标题用set的模式写进setTitle()方法处理

而且document是一个对象类型。

系统又是如何知道写入的标题是什么呢?

假设在一个控制器中(如PAYPAL)用了以上的方法。

先给TITLE赋值。

这就要特别注意作者前面说的,OPENCART使用的是MVC+L,头尾是以return 返回视图的方式。

所以说,在paypal控制器中写入了TITLE的值之后。

在使用:$data[‘header’]=$this->load->controller(‘common/header’);

 

以下是完整的:paypal控制器标题参数

$this->load->language(‘paymunt/paypal’); //获取贝宝语言包
$this->document->setTitle($this->language->get(‘heading_title’)); //写入参数到document对象中
$data[‘header’]=$this->load->controller(‘shangjia/header’); //头部直接调用

我们来看看header.php控制器中:

$data[‘title’] = $this->document->getTitle(); //直接调用每一个模型/插件的heading_title;

通过清心醉

OPENCART微信NATIVE-JSAPI支付插件

opencart微信NATIVE-JSAPI支付插件,完美支持最新2.0.3版本:

非DEMO类型的插件.
部分人使用DEMO来使用,用户就需要修改PHP的配置文件.

插件特点:
后台完全自定义:无需懂任何PHP代码.上传安装即可.

需要的后台参数:
1:绑定支付的APPID
2:公众帐号APPSECRET
3:商户支付密钥KEY
4:商户号MCHID
5:状态
6:启用微信二维码支付
7:启用微信客户端支付
8:订单已支付后的状态

注:
第6条和第7条为选择状态
即用户可以启用二维码扫描支付和微心客户端内的JSAPI来支付
由于JSAPI支付复杂,而且手机差的会卡,所以允许只打开一个来使用

其他说明:
二维码支付直接设置好了参数就可以使用.
至于JSAPI的支付,需要进入公众平台设置:
设置1:
进入公众平台-微信支付-开发配置-公众号支付-支付授权目录:
填写完整的域名(如):http://www.qingxinzui.com/catalog/controller/payment

设置2:
进入公众平台-开发者中心-配置项-网页服务-网页帐号-OAuth2.0网页授权:
填写完整的域名(如):qingxinzui.com
第一是JSAPI允许的请求路径和回调路径,第二是因为JSAPI需要获取用户的OPPENID信息.

需要的请到作者的网站购买.

通过清心醉

OPENCART 支付宝(ALIPAY)支付插件

opencart支付宝(alipay)支付插件包含企业版及个人版.
企业版默认打开电脑端及移动端支付.
个人版为担保交易,为了保证个人商家交易上的纠纷,由商家自行到alipay官网进行货运的跟踪.
后台需要设置以下几个参数:
1:合作者身份ID
2:交易安全校验码
3:支付宝帐户
4:选择项-状态
5:选择项-支付模式
6:选择项-订单已支付后的状态
注:
第5条为:
企业版模式为即时到帐收款,直接填写对应的参数值即可.
担保交易由于考虑到个人商家的利益,未添加自动执行发货.
原因是如果用户申请退款没有详细的发货记录会被取消订单. 请自行到官网进行发货
第6条为订单交易成功之后,订单的状态(提取后台所有订单状态模式,用户自行定义)

需要的请到作者的网站购买

通过清心醉

opencart前台获取支付方式的方法

在checkout.tpl视图文件里,进行了ajax的请求#collapse-payment-method

然后我们来看看请求的payment-method控制器

在index方法里

有这么几句:

$this->load->model(‘extension/extension’);
$results = $this->model_extension_extension->getExtensions(‘payment’);
$recurring = $this->cart->hasRecurringProducts();
foreach ($results as $result) {
if ($this->config->get($result[‘code’] . ‘_status’)) {
$this->load->model(‘payment/’ . $result[‘code’]);
$method = $this->{‘model_payment_’ . $result[‘code’]}->getMethod($this->session->data[‘payment_address’], $total);
if ($method) {
if ($recurring) {
if (method_exists($this->{‘model_payment_’ . $result[‘code’]}, ‘recurringPayments’) && $this->{‘model_payment_’ . $result[‘code’]}->recurringPayments()) {
$method_data[$result[‘code’]] = $method;
}
} else {
$method_data[$result[‘code’]] = $method;
}
}
}
}

作者前文写的安装配置,是因为要遵循opencart的模块规则标准,而如果定义为插件了的话

除了自定义的数据表,还会追加写入extension扩展表及setting环境配置表(可以当成为开关表)

在需要的时候,首先extension里提取当前需要使用的扩展类型

在$results = $this->model_extension_extension->getExtensions(‘payment’);这一句就可以看到

而且getExtensions的原型是:

function getExtensions($type) {
$query = $this->db->query(“SELECT * FROM ” . DB_PREFIX . “extension WHERE `type` = ‘” . $this->db->escape($type) . “‘”);

return $query->rows;
}

我们在来看数据库参数:

extension表

‘extension_id’=>’234’
‘type’=>’payment’
‘code’=>’ckzalipay’

当获取了扩展插件名之后,在获取插件的当前状态.$this->config->get($result[‘code’] . ‘_status’);

接着引用模型文件$this->load->model(‘payment/’ . $result[‘code’]);

其实等价于$this->load->mode(‘payment/ckzalipay’);

然后强制调用getMethod方法

$method = $this->{‘model_payment_’ . $result[‘code’]}->getMethod($this->session->data[‘payment_address’], $total);

等价于$method = $this->model_payment_ckzalipay->getMethod($this->session->data[‘payment_address’], $total);

getMethod($address, $total)里就是显示支付列表的参数

因为是在foreach循环里,所以会提取出所有打开的支付方式.

 

 

 

 

 

 

 

通过清心醉

opencart创建支付宝支付后台

由于处于开发阶段,可能需要更多的参数需要进行填写.暂时写的先贴上

默认需要有个install()安装控制器方法和uninstall()卸载方法

附上控制器和模型的类方法:

class ControllerPaymentCkzalipay extends Controller {
function index()
{
$this->load->language(‘payment/ckzalipay’);   //默认配置语言包
$this->document->setTitle($this->language->get(‘heading_title’)); //页面标题头
$this->load->model(‘setting/setting’);        //模块/插件的启用和关闭状态表
$this->load->model(‘payment/ckzalipay’); //模型配置模型包
/**
* 开始导入语言包
*/
$data[‘heading_title’] = $this->language->get(‘heading_title’);
$data[‘ckz_id’]=$this->language->get(‘ckz_id’);
$data[‘ckz_key’]=$this->language->get(‘ckz_key’);
$data[‘ckz_account’]=$this->language->get(‘ckz_account’);
$data[‘ckz_save’]=$this->language->get(‘ckz_save’);
$data[‘ckz_false’]=$this->language->get(‘ckz_false’);
$data[‘text_enabled’]=$this->language->get(‘text_enabled’);
$data[‘text_disabled’]=$this->language->get(‘text_disabled’);
$data[‘zhuangtai’]=$this->language->get(‘zhuangtai’);
$data[‘ckz_jishi_text’]=$this->language->get(‘ckz_jishi_text’);
$data[‘ckz_danbao_text’]=$this->language->get(‘ckz_danbao_text’);
$data[‘ckz_alipay_moshi’]=$this->language->get(‘ckz_alipay_moshi’);

/**
* 导入其他栏
*/
$data[‘header’] = $this->load->controller(‘common/header’);
$data[‘column_left’] = $this->load->controller(‘common/column_left’);
$data[‘footer’] = $this->load->controller(‘common/footer’);

/**
* 导入支付宝配置的参数
*/
$data[‘config’]=array();
if(isset($this->request->post[‘ckz_id’])
&& isset($this->request->post[‘ckz_key’])
&& isset($this->request->post[‘ckz_account’])
&& isset($this->request->post[‘ckz_zhuangtai’])
&& isset($this->request->post[‘ckz_moshi’])
)
{
//var_dump($_POST);die();
$data[‘config’][‘ckzalipay_id’]=$this->request->post[‘ckz_id’];
$data[‘config’][‘ckzalipay_key’]=$this->request->post[‘ckz_key’];
$data[‘config’][‘ckzalipay_account’]=$this->request->post[‘ckz_account’];
$data[‘config’][‘ckzalipay_type’]=$this->request->post[‘ckz_moshi’];
//以上三个参数为获取POST数据
$this->model_payment_ckzalipay->setckzalipayconfig($this->request->post[‘ckz_id’],
$this->request->post[‘ckz_key’],
$this->request->post[‘ckz_account’],
$this->request->post[‘ckz_moshi’]);
//执行更新用户的模型数据
$this->model_payment_ckzalipay->update_setting_value($this->request->post[‘ckz_zhuangtai’]);
//更新setting模块状态
$data[‘status_value’]=$this->request->post[‘ckz_zhuangtai’];
//获取当前模块的启用/关闭值得
}
else
{
$data[‘config’]=$this->model_payment_ckzalipay->getckzalipayconfig();
if (empty($data[‘config’]))
{
$data[‘config’][‘ckzalipay_id’]=’this is id’;
$data[‘config’][‘ckzalipay_key’]=’this is key’;
$data[‘config’][‘ckzalipay_account’]=’this is account’;
$data[‘config’][‘ckzalipay_type’]=’0′;
}
if($this->model_payment_ckzalipay->getckzalipayconfig_setting())
{
$data[‘status_value’]=1;
}
else
{
$data[‘status_value’]=0;
}
}
$data[‘action’] = $this->url->link(‘payment/ckzalipay’, ‘token=’ . $this->session->data[‘token’], ‘SSL’); //保存的时候请求的方法
$data[‘cancel’] = $this->url->link(‘extension/payment’, ‘token=’ . $this->session->data[‘token’], ‘SSL’);  //取消的时候返回的页面
$this->response->setOutput($this->load->view(‘payment/ckzalipay.tpl’, $data));
}

function install()
{
/**
* 加载语言模型文件
*/
$this->load->model(‘payment/ckzalipay’);
$this->load->model(‘setting/setting’);
$this->model_payment_ckzalipay->install();
}

function uninstall()
{
$this->load->model(‘payment/ckzalipay’);
$this->model_payment_ckzalipay->uninstall();
}
}

 

/**
* model file
*
*  由于是支付模块,属于extension
*  所以默认调用了安装,会给extension表内添加对应的字段
*
* */
class ModelPaymentCkzalipay extends Model
{
function install()
{
/**
$this->db->query(”
CREATE TABLE `” . DB_PREFIX . “order_ckzalipay` (
`order_id` int(11) NOT NULL,
`ckzalipay_order_id` varchar(255) NOT NULL,
`free_shipping`  tinyint NOT NULL DEFAULT 0,
KEY `ckzalipay_order_id` (`ckzalipay_order_id`),
PRIMARY KEY `order_id` (`order_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
“);

$this->db->query(”
CREATE TABLE `” . DB_PREFIX . “order_ckzalipay_product` (
`order_product_id`  int NOT NULL ,
`ckzalipay_order_item_code`  varchar(255) NOT NULL,
PRIMARY KEY (`order_product_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
“);
*/
/**
* 创建支付宝支付配置
* 参数为:
* 验证ID,验证KEY,用户帐户及支付类型(即使到帐和担保交易)
* 其中type=1时为即时到帐
* type=0时为担保交易
*/
$this->db->query(”
CREATE TABLE `” . DB_PREFIX . “order_ckzalipay_config` (
`ckzalipay_id`  varchar(255) NOT NULL ,
`ckzalipay_key`  varchar(255) NOT NULL ,
`ckzalipay_account` varchar(255) NOT NULL ,
`ckzalipay_type` varchar(32) NOT NULL,
PRIMARY KEY (`ckzalipay_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
“);

//添加系统模块/插件配置开关
$this->db->query(”
INSERT INTO `” . DB_PREFIX . “setting`
(`store_id`, `code`, `key`, `value`, `serialized`)
VALUES (‘0’, ‘config’, ‘ckzalipay_status’, ‘0’, ‘0’);
“);

}
function uninstall()
{
//以下两个参数暂时不执行
// $this->db->query(“DROP TABLE IF EXISTS `” . DB_PREFIX . “order_ckzalipay`;”);
// $this->db->query(“DROP TABLE IF EXISTS `” . DB_PREFIX . “order_ckzalipay_product`;”);
$this->db->query(“DROP TABLE IF EXISTS `” . DB_PREFIX . “order_ckzalipay_config`;”);
$this->db->query(“DELETE FROM `” . DB_PREFIX . “setting` WHERE `key`=’ckzalipay_status’;”);
}

/**
* 获取清心醉-支付宝的参数配置
* 返回一行数据(只有一行)
* @return unknown
*/
function getckzalipayconfig()
{
$config=$this->db->query(“SELECT * FROM `” . DB_PREFIX . “order_ckzalipay_config`;”);
$config=$config->row; //提取一行数据 全部为rows;
return $config;
}

/**
* 用户写入的清心醉-支付宝数据进行写入保存
* @param unknown $id
* @param unknown $key
* @param unknown $account
*/
function setckzalipayconfig($id,$key,$account,$type)
{
$config=$this->getckzalipayconfig();//首先获取看看有没有数据
if (empty($config))
{
$this->db->query(”
INSERT INTO `” . DB_PREFIX . “order_ckzalipay_config`
(`ckzalipay_id`,`ckzalipay_key`,`ckzalipay_account`,`ckzalipay_type`)
VALUES(‘$id’,’$key’,’$account’,’$type’);
“);
}
else
{
$this->db->query(“UPDATE`” . DB_PREFIX . “order_ckzalipay_config` SET `ckzalipay_id`= ‘$id’, `ckzalipay_key`=’$key’, `ckzalipay_account`=’$account’, `ckzalipay_type`=’$type’;”);
}
}

/**
* 判断开起的模块/插件中key值中是否存在对应的
* $kye的值明确为 ckzalipay_status
* ckzalipay为插件的名称
* status为插件的启用状态
* @param unknown $key
* @return boolean
*/
function getckzalipayconfig_setting()
{
$keys=$this->db->query(“SELECT * FROM `” . DB_PREFIX . “setting` WHERE `key`=’ckzalipay_status'”);
$keys=$keys->row;
if (!empty($keys))
{
if ($keys[‘value’]==1)
{
return true;
}
else {
return false;
}
}
else {
return false;
}
}

function update_setting_value($value)
{
$this->db->query(“UPDATE`” . DB_PREFIX . “setting` SET `value`= ‘$value’ WHERE `key`=’ckzalipay_status’;”);
}
}

通过清心醉

opencart去除父级URL

opencart去除父级URL,看标题就知道是为了SEO而优化。如果不去除,就会出现重复的页面。

打开/catalog/controller/common/seo_url.php文件

找到$url .= ‘/’ . $query->row[‘keyword’];

替换成$url = ‘/’ . $query->row[‘keyword’];

细心点你会发现少了一个字符串连接符“.”;

通过清心醉

opencart导入分类扩展的代码思路

作者封装的OPENCART导入其他网站的分类的信息,需要提供PDO的连接参数和导入的7个数据参数.

class Category_PHP
{
public $pdo; //私有数据成员PDO连接
private $dbname;
private $user;
private $password;
private $pre;

/**
* 构造方法获取PDO的连接参数
* @return PDO
*/
function __construct()
{
#################
#参数初始化开始
##################
$this->pre=’mmc_’;
$this->dbname=’opencart’;
$this->user=’root’;
$this->password=”;
#################
#参数初始化结束
##################
$pdo=new PDO (“mysql:host=localhost;dbname=$this->dbname;charset=utf8”,$this->user,$this->password);
return $this->pdo=$pdo;
}

/**
* 表前缀组合,返回一个数据表名称
* @param unknown $table
* @return string
*/
protected function table($table)
{
return “$this->pre”.”$table”;
}

/**
* 写入数据库分类表  根分类
* @param unknown $data
*/
protected function insert_opencart_calss($data=array())
{
/**
* 以下7个参数为必填项,比如url可以自己重新组合
*/
$id=$data[‘1’];  //分类的ID
$mixid=$data[‘2’];  //分类的上级ID
$name=$data[‘3’]; //名称
$description=$data[‘4’]; //元描述
$keywords=$data[‘5’]; //关键字组合
$title=$data[‘6’]; //元标题
$url=$data[‘7’]; //伪静态的URL

$time=date(“Y-m-d H:i:s”);
$this->category($id,$time,$time);
$this->category_path($id,$mixid); //写入目录扩展
$this->category_url($id, $url); //写入重写URL
$this->category_description($id, $name, $description, $keywords, $title); //写入产品的详细信息
$this->category_to_layout($id); //写入分类的布局
$this->category_to_store($id); //写入分类的店铺

}

#########################################################################################
#    写入分类的其他扩展开始(不管根分类还是子分类)
#########################################################################################
/**
* 写入category_description分类详细扩展
* 需要分类ID,分类名称,分类描述(分类元描述)
* @param unknown $id
* @param unknown $name
* @param unknown $description
* @param unknown $keywords
* @param unknown $title
*/
protected function category($id,$time,$time)
{
$table=$this->table(‘category’); //获取分类数据表
$sql=”INSERT INTO $table (`category_id`, `parent_id`, `top`, `column`, `sort_order`, `status`, `date_added`, `date_modified`)
VALUES (‘$id’, ‘0’, ‘1’, ‘1’, ‘1’, ‘1’, ‘$time’,’$time’)”;
$this->pdo->exec($sql);
}

protected function category_description($id,$name,$description,$keywords,$title)
{
$table=$this->table(‘category_description’);
$sql=”INSERT INTO $table(`category_id`,`language_id`,`name`,`description`,`meta_title`,`meta_keyword`,`meta_description`)
VALUES(‘$id’,’1′,’$name’,’$description’,’$title’,’$keywords’,’$description’)”;
$this->pdo->exec($sql);
}
/**
* 写入category_path目录数据表扩展
* @param unknown $id
* @param unknown $pathid
*/
protected function category_path($id=0,$pathid=0)
{
$table=$this->table(‘category_path’);
if ($pathid==0) //如果父ID==0
{
$sql=”INSERT INTO $table(`category_id`,`path_id`,`level`)VALUES(‘$id’,’$id’,’0′)”;
}
else
{
$sql=”INSERT INTO $table(`category_id`,`path_id`,`level`)VALUES(‘$id’,’$pathid’,’0′)”;
}
$this->pdo->exec($sql);
}
/**
* 重写分类的URL格式
* @param unknown $id
* @param unknown $url
*/
protected function category_url($id,$url)
{
$table=$this->table(‘url_alias’);
$urlid=”category_id=”.”$id”; //分类的ID
$sql=”INSERT INTO $table(`query`,`keyword`,`language_id`)VALUES(‘$urlid’,’$url’,’1′)”;
$this->pdo->exec($sql);
}

/**
* 写入分类的布局
* @param unknown $id
*/
protected function category_to_layout($id)
{
$table=$this->table(‘category_to_layout’);
$sql=”INSERT INTO $table(`category_id`,`store_id`,`layout_id`)VALUES(‘$id’,’0′,’0′)”;
$this->pdo->exec($sql);
}
/**
* 写入分类对应的店铺
* @param unknown $id
*/
protected function category_to_store($id)
{
$table=$this->table(‘category_to_store’);
$sql=”INSERT INTO $table(`category_id`,`store_id`)VALUES(‘$id’,’0′)”;
$this->pdo->exec($sql);
}
#########################################################################################
#    写入分类的其他扩展结束(不管根分类还是子分类)
#########################################################################################
}

通过清心醉

opencart开发|opencart建站|opencart分类强制添加seo-keyword

上文说了,opencart产品的大概流程是在product控制器里,add的方法中,引用

$this->model_catalog_product->addProduct($this->request->post);

opencart的分类也是差不多,在category控制器里的add方法中:

public function addCategory($data) 我们同样可以强制添加

SEO有两种方式:目录和文件

分类的权重比文件高,所以不能以.html做后缀,所以我们强制添加SEO-KEYWORD的时候,一定要注意.

而且分类一般都不会重复的,如果重复也很麻烦,可以读取重写记录记性判断,存在则使用”-“+ID的方式组合.

和修改产品一样,如果你能看懂作者前一篇文章,那么修改的方法你已经很清楚了.在这就不进行过多的介绍了.

通过清心醉

opencart开发|opencart建站|opencart产品强制添加seo-keyword

上文说了opencart的SEO优化,现在作者要讲的就是以产品的名称作为opencart产品的seo-keyword.

因为作者只考虑新增加产品即Add,所以晚点再看Edit修改产品是否会导致seo-keyword变更.

在product控制器里,add的方法中,引用了这么一句

$this->model_catalog_product->addProduct($this->request->post);

我们在对应的模型方法里找到该方法:

if (isset($data[‘keyword’])) {
$this->db->query(“INSERT INTO ” . DB_PREFIX . “url_alias SET query = ‘product_id=” . (int)$product_id . “‘, keyword = ‘” . $this->db->escape($data[‘keyword’]) . “‘”);
}

如果keyword的变量存在则写入重写URL,简单了.修改一下:

首先定义个私有成员:

private $name;

因为产品的名称是在数组$data[‘product_description’]里,而该方法里就有对该数组进行foreach循环

foreach ($data[‘product_description’] as $language_id => $value) {
$this->db->query(“INSERT INTO ” . DB_PREFIX . “product_description SET product_id = ‘” . (int)$product_id . “‘, language_id = ‘” . (int)$language_id . “‘, name = ‘” . $this->db->escape($value[‘name’]) . “‘, description = ‘” . $this->db->escape($value[‘description’]) . “‘, tag = ‘” . $this->db->escape($value[‘tag’]) . “‘, meta_title = ‘” . $this->db->escape($value[‘meta_title’]) . “‘, meta_description = ‘” . $this->db->escape($value[‘meta_description’]) . “‘, meta_keyword = ‘” . $this->db->escape($value[‘meta_keyword’]) . “‘”);
$tempname=$value[‘name’]; //提取产品名称
for ($i=0 ; $i<strlen($tempname); $i++)
{
if ($tempname[$i]==’ ‘||$tempname[$i]==’,’||$tempname[$i]==’,’||$tempname[$i]==’。’||$tempname[$i]==’ ‘)
{
//对上述字符进行转化。
$tempname[$i]=’-‘;
}
}
$this->name=$tempname.”-“.”$product_id”.”.html”;
}

然后修改过$data[‘keyword’]的操作

删除if (!isset($data[‘keyword’])) 判断,

直接写入MYSQL:
$this->db->query(“INSERT INTO ” . DB_PREFIX . “url_alias SET query = ‘product_id=” . (int)$product_id . “‘, keyword = ‘” . $this->db->escape($this->name) . “‘”);

这样不添加keyword的情况下,一样会生成对应的URL.

通过清心醉

opencart开发|opencart SEO优化

今天用opencart建站,发现opencart对SEO的问题,发现有3个是需要对opencart二次开发的.

第一:产品URL带有父类的URL,这样会出现过多的重复页;

第二:产品添加的时候如果SEOKEY不填写则会以动态形式写入;

第三:分类和第二个一样,必须填写SEOKEY.

耐何上传产品的小妹妹不懂啥叫SEO,对网站的认识也比较少,自己辛苦下,进行下开发:  请确保后台开启了高级URL Rewrite’s(伪静态)

先说第一点:针对opencart去除父类url的方法:

前台控制器里的common的核心里有个seo_url.php

foreach ($data as $key => $value) {
if (isset($data[‘route’])) {
if (($data[‘route’] == ‘product/product’ && $key == ‘product_id’) || (($data[‘route’] == ‘product/manufacturer/info’ || $data[‘route’] == ‘product/product’) && $key == ‘manufacturer_id’) || ($data[‘route’] == ‘information/information’ && $key == ‘information_id’)) {
$query = $this->db->query(“SELECT * FROM ” . DB_PREFIX . “url_alias WHERE `query` = ‘” . $this->db->escape($key . ‘=’ . (int)$value) . “‘”);

if ($query->num_rows && $query->row[‘keyword’]) {
//$url .= ‘/’ . $query->row[‘keyword’];
$url = ‘/’ . $query->row[‘keyword’];
unset($data[$key]);
}
} elseif ($key == ‘path’) {
$categories = explode(‘_’, $value);

foreach ($categories as $category) {
$query = $this->db->query(“SELECT * FROM ” . DB_PREFIX . “url_alias WHERE `query` = ‘category_id=” . (int)$category . “‘”);

if ($query->num_rows && $query->row[‘keyword’]) {
//$url .= ‘/’ . $query->row[‘keyword’];
$url = ‘/’ . $query->row[‘keyword’];
} else {
$url = ”;

break;
}
}

unset($data[$key]);
}
}
}

通过清心醉

opencart开发|opencart修改产品的添加方式

opencart产品上传一样是麻烦.前文作者说了opencart修改分类的添加方式,产品也是一样的.

看返回的模板:$this->response->setOutput($this->load->view(‘catalog/product_form.tpl’, $data));

简单,模板文件直接暴露,找到后,修改需要的就OK了.

通过清心醉

opencart开发|opencart修改分类的添加方式

opencart的后台虽然很简结,但对于新手来说,上传产品添加分类会很矛盾

有些必须添加带有*号的放后面,不认真去熟悉就没办法好好的使用.

(关于这点magento做的比较好,使用了JS来红色显示未写入数据的行数)

首先是针对分类:

在category.php的分类控制器里:

不管是Edit还是Add的方法

最后都是使用了getForm()的方法来显示视图

而该方法最终使用了$this->response->setOutput($this->load->view(‘catalog/category_form.tpl’, $data));

这一块模板里就包含了新分类/修改分类等表单,直接找到自己需要的修改位置或者删除不需要的就OK了.