分类归档 Ecshop

通过清心醉

ecshop Access is denied

ecshop重新安装之后,配置邮件服务器时,提示”ecshop Access is denied”,一开始以为端口被封了,又不想给服务器安装TELNET来测试连接.经过一番的测试,发现是SELINUX的安全机制的影响.

关闭SELINUX服务即可:

vi /etc/selinux/config

#SELINUX=enforcing修改为SELINUX=disabled

然后reboot即可.

通过清心醉

配置ecshop的Nginx+Apache+Mysql+Php环境

为什么一定要使用Nginx,还有搭配的教程作者在NGINX+APACHE+PHP+MYSQL整合已经说过了.

可是配置ecshop真的好麻烦,主要麻烦在PHP不能使用超过5.3的版本,否则就是修改所有的核心代码,那工程量会要人命的.

首先根据作者链接中所说,安装nginx+apache

确保nginx是可以正常访问的,并且apache启动是无错误的

注:在这假设目录使用apache的默认目录/var/www/html

然后我们来安装mysql,由于centos自带的mysql可能有点老,所以如果可以的话update下

yum install mysql mysql-server

记得顺便修改下mysql的root密码

mysql -u root;

mysql> use mysql;

mysql> UPDATE user SET password= PASSWORD(‘新密码’) WHERE user = ‘root’;

mysql> FLUSH PRIVILEGES;

然后:service mysqld restart;

重新进入MYSQL创建个UTF的ECSHOP数据库

create database if not exists ecshop default charset utf8 collate utf8_general_ci;

至于安装PHP,其实ecshop对PHP的最大限制是php 5.3.3

直接yum  也可以.

编译准备工作 yum groupinstall “Development tools”
然后是编译安装 PHP 需要用到的 devel 包:
yum install libxml2-devel gd-devel libmcrypt-devel libcurl-devel openssl-devel
接下来下载对应的PHP
编译安装 php的参数:
进入PHP目录
./configure –with-apxs2=/usr/local/apache2/bin/apxs –disable-cli –enable-shared –with-libxml-dir –with-gd –with-openssl –enable-mbstring –with-mcrypt –with-mysqli –with-mysql –enable-opcache –enable-mysqlnd –enable-zip –with-zlib-dir –with-pdo-mysql –with-jpeg-dir –with-freetype-dir –with-curl –without-pdo-sqlite –without-sqlite3

make
make install
cp php.ini-production /usr/local/lib/php.ini

是时候让 apache 知道有 php 的存在了,在 apache 配置文件 httpd.conf 中添加:
LoadModule php5_module modules/libphp5.so
#上面那行可能在编译安装 php 的过程中已经由系统自动添加了
<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>

OK!重启 apache,人品好的人是不会出现问题的。

因为Nginx接收到的动态请求会转发给apache,所以不需要使用php-fpm,除非使用nginx+mysql+php的搭配。

好了,到此ecshop的Nginx+Apache+Mysql+Php环境配置完成。

 

 

通过清心醉

Ecshop扫描二维码支付原理

连续折腾了3天,被腾讯的API接口搞的半条命了。最后还是被迫修改官方的SDK;

居然是二维码,自然要生成带短链接的URL图片。

大概流程

1:根据订单,公众号,商户号,KEY–》请求接口获取详细配置参数

2:通过第一次请求获取的参数,根据产品名称,价格(注意单位为分,记得要*100计算,订单号,随机数等,再次请求接口获取短链接

3:把短链接生成二维码;

4:为了实现页面跳转,实现AJAX请求判断是否支付成功。

有需要的用户直接到

我的网站

购买

通过清心醉

Nginx下Ecshop伪静态规则

注:如果您的Nginx里有多个站点,请针对单一vhost里的站点.conf写

if (!-e $request_filename)
{
rewrite “^/index\.html” /index.php last;
rewrite “^/category$” /index.php last;
rewrite “^/feed-c([0-9]+)\.xml$” /feed.php?cat=$1 last;
rewrite “^/feed-b([0-9]+)\.xml$” /feed.php?brand=$1 last;
rewrite “^/feed\.xml$” /feed.php last;
rewrite “^/category-([0-9]+)-b([0-9]+)-min([0-9]+)-max([0-9]+)-attr([^-]*)-([0-9]+)-(.+)-([a-zA-Z]+)(.*)\.html$” /category.php?id=$1&brand=$2&price_min=$3&price_max=$4&filter_attr=$5&page=$6&sort=$7&order=$8 last;
rewrite “^/category-([0-9]+)-b([0-9]+)-min([0-9]+)-max([0-9]+)-attr([^-]*)(.*)\.html$” /category.php?id=$1&brand=$2&price_min=$3&price_max=$4&filter_attr=$5 last;
rewrite “^/category-([0-9]+)-b([0-9]+)-([0-9]+)-(.+)-([a-zA-Z]+)(.*)\.html$” /category.php?id=$1&brand=$2&page=$3&sort=$4&order=$5 last;
rewrite “^/category-([0-9]+)-b([0-9]+)-([0-9]+)(.*)\.html$” /category.php?id=$1&brand=$2&page=$3 last;
rewrite “^/category-([0-9]+)-b([0-9]+)(.*)\.html$” /category.php?id=$1&brand=$2 last;
rewrite “^/category-([0-9]+)(.*)\.html$” /category.php?id=$1 last;
rewrite “^/goods-([0-9]+)(.*)\.html” /goods.php?id=$1 last;
rewrite “^/article_cat-([0-9]+)-([0-9]+)-(.+)-([a-zA-Z]+)(.*)\.html$” /article_cat.php?id=$1&page=$2&sort=$3&order=$4 last;
rewrite “^/article_cat-([0-9]+)-([0-9]+)(.*)\.html$” /article_cat.php?id=$1&page=$2 last;
rewrite “^/article_cat-([0-9]+)(.*)\.html$” /article_cat.php?id=$1 last;
rewrite “^/article-([0-9]+)(.*)\.html$” /article.php?id=$1 last;
rewrite “^/brand-([0-9]+)-c([0-9]+)-([0-9]+)-(.+)-([a-zA-Z]+)\.html” /brand.php?id=$1&cat=$2&page=$3&sort=$4&order=$5 last;
rewrite “^/brand-([0-9]+)-c([0-9]+)-([0-9]+)(.*)\.html” /brand.php?id=$1&cat=$2&page=$3 last;
rewrite “^/brand-([0-9]+)-c([0-9]+)(.*)\.html” /brand.php?id=$1&cat=$2 last;
rewrite “^/brand-([0-9]+)(.*)\.html” /brand.php?id=$1 last;
rewrite “^/tag-(.*)\.html” /search.php?keywords=$1 last;
rewrite “^/snatch-([0-9]+)\.html$” /snatch.php?id=$1 last;
rewrite “^/group_buy-([0-9]+)\.html$” /group_buy.php?act=view&id=$1 last;
rewrite “^/auction-([0-9]+)\.html$” /auction.php?act=view&id=$1 last;
rewrite “^/exchange-id([0-9]+)(.*)\.html$” /exchange.php?id=$1&act=view last;
rewrite “^/exchange-([0-9]+)-min([0-9]+)-max([0-9]+)-([0-9]+)-(.+)-([a-zA-Z]+)(.*)\.html$” /exchange.php?cat_id=$1&integral_min=$2&integral_max=$3&page=$4&sort=$5&order=$6 last;
rewrite “^/exchange-([0-9]+)-([0-9]+)-(.+)-([a-zA-Z]+)(.*)\.html$” /exchange.php?cat_id=$1&page=$2&sort=$3&order=$4 last;
rewrite “^/exchange-([0-9]+)-([0-9]+)(.*)\.html$” /exchange.php?cat_id=$1&page=$2 last;
rewrite “^/exchange-([0-9]+)(.*)\.html$” /exchange.php?cat_id=$1 last;
}

通过清心醉

Ecshop-二维码分享mobile和电脑端同步

由于Ecshop的mobile端使用了MVC的分层,而二维码的扫描生成的时候是根据电脑端的产品ID进行截取,然后转化为mobile端的URL。

比如我有个产品,产品的电脑端URL为127.0.0.1/goods.php?id=100;

作者根据产品的ID,重写为mobile的地址:

$id=$_GET[‘id’];
if(isset($id)&&!empty($id))
{
if(is_numeric($id))
{
$url=”http://127.0.0.1/mobile/index.php?m=default&c=goods&a=index&id=”.$id;
}
}

这样就有个小小的问题,因为Ecshop不是使用自适应(如果是MAGENTO,根据URL就自动跳转合适的分辨率)。

如果用户电脑端访问,那就看的很难看了!

从URL里可以看出使用goods控制器的index方法

我们可以在方法里这么写

$id=$_GET[‘id’];
if(isset($id)&&!empty($id))
{
if(is_numeric($id))
{
$ua = strtolower($_SERVER[‘HTTP_USER_AGENT’]);
$uachar = “/(nokia|sony|ericsson|mot|samsung|sgh|lg|philips|panasonic|alcatel|lenovo|cldc|midp|mobile)/i”;
if(($ua == ” || preg_match($uachar, $ua))&& !strpos(strtolower($_SERVER[‘REQUEST_URI’]),’wap’))
{

}
else
{
$url=”http://127.00.1/goods.php?id=”.$id;
echo “<script>setTimeout(\”this.location=’$url’\”,1);</script>”;
}
}
}

 

 

通过清心醉

Ecshop用户未登陆购买产品二次开发

默认的用户登陆,都是在user.php文件里执行。

可产品购买流程等,都是在flow.php里执行,如果用户没有登陆,会GET请求回flow.php本页的step=login。

然后大约264行有这么一句:if ($user->login($_POST[‘username’], $_POST[‘password’],isset($_POST[‘remember’])))

#在这严重鄙视下EC,面向对象的思维根本就没完整。在user.php里做了用户名/邮件/电话号码及二维码图片登陆,导致我这里又要重写一个。

首先写个手机判断方法:

function is_telephone($phone)
{
$chars = “/^13[0-9]{1}[0-9]{8}$|15[0-9]{1}[0-9]{8}$|18[0-9]{1}[0-9]{8}$/”;
if (preg_match($chars, $phone))
{
return true;
}
else
{
return false;
}
}

然后::修改IF语句:if ($user->login($_POST[‘username’], $_POST[‘password’],isset($_POST[‘remember’])))

改为:

$username=$_POST[‘username’];
if(is_email($username)) //首先判断是否符合邮件
{
$sql =”select user_name from “.$ecs->table(‘users’).” where email='”.$username.”‘”; //SQL语句
$username_e = $db->getOne($sql); //如果有存在的数据赋值给变量
if($username_e) //如果存在不为空的话
{
$username=$username_e; //重新赋值
}
}
if(is_telephone($username))
{
$sql =”select user_name from “.$ecs->table(‘users’).” where mobile_phone='”.$username.”‘”;
$username_e = $db->getOne($sql);
if($username_e)
{
$username=$username_e;
}
}
if ($user->login($username, $_POST[‘password’],isset($_POST[‘remember’])))
{
update_user_info(); //更新用户信息
recalculate_price(); // 重新计算购物车中的商品价格

// 检查购物车中是否有商品 没有商品则跳转到首页
$sql = “SELECT COUNT(*) FROM ” . $ecs->table(‘cart’) . ” WHERE session_id = ‘” . SESS_ID . “‘ “;
if ($db->getOne($sql) > 0)
{
ecs_header(“Location: flow.php?step=checkout\n”);
}
else
{
ecs_header(“Location:index.php\n”);
}

exit;
}

同时为了方便提醒用户可以以上三种方法登陆;

修改flow.dwt文件:找到对应的input添加:

placeholder=”用户名/邮箱/手机号”

 

通过清心醉

Ecshop使用积分购买产品

一说起积分,大家都不陌生了。在商店了购买产品送积分,然后通过积分兑换产品或者使用积分代替现金购买产品。那么Ecshop里的积分规则又是如何呢?

在数据库users表段里有这么一个字段->pay_points,就是用来存储用户的积分数据的。

先来说说积分是如何产生的:

当用户购买一件价格为¥500产品的时候,下了订单成功,并且成功支付了,当从第三方收款返回来的时候,自动更新订单状态。同时以产品的价格(¥500,如果价格为¥500.5,也当500计算)写入pay_points字段内,表示用户已经有了500的积分。

生成积分的公式:

1元=1积分;10元=10积分;依此类推

至于积分的使用就不同了。

作者说过了,积分可以用来代替现金用来购买产品。

比如后台上传这么一个产品,

产品价格:200.00

积分购买金额:10

当加入购物车进行结算生成订单的时候,有这么一项:其他信息->使用积分购买

假设用户有2000积分,但最高只能使用1000,为什么呢?产品后台不是设置了积分购买金额=10吗?

因为那是积分的元数,其实就是10元

积分购买金额其实就是=参数*100;所以如果设置为10,最多可以用1000积分来享受优惠。

等下了订单的时候,产品的价格就为190元了。因为积分已经使用了1000代替10元。

虽然这价格显示是190元,但如果用户成功的购买之后,返送的积分其实还是200,在这ecshop使用产品自身价格来做积分获取,不管使用了多少积分都是如此。

如果用户下了订单,不付款,积分会一直扣住不返回,这时候只需要用户自行登陆取消订单,或者后台管理人员对久未付款的订单进行无效的时候,积分进行返回!

 

通过清心醉

Ecshop时间戳设置原理

其实正确的来说应该是UNIX的时间戳.ECSHOP使用了该方法来记录时间,说真的,多此一举!

再进行二次开发的时候,看到很多本是使用时间存储数据,可偏是一堆堆的数字.

其实ECSHOP在写入MYSQL的时候,先获取当前的系统时间.(当然时区要设置为+8,如:ini_set(‘date.timezone’,’Asia/Shanghai’);)

比如获取的时间变量$time.经过strtotime($time)后就变成了时间戳,具体时间戳的开始计算时间自行GOOGLE.

写入之后就是一串数字了.

然后提取出来的时候.

比如:

$t=1431394669; //
echo date(‘Y-m-d H:i:s’, $t);

就还原出来了.

通过清心醉

Ecshop禁止名字内包含某字符

为什么这么写?其实很多人都会拉

strstr()的方法就可以搞定。

今天做微信的扫描登陆,其中有一个最让我头疼的,默非就是用户名的重复了。

通过微信扫描登陆获取的openid,判断数据库是否存在,如不存在,则创建新的用户。

用户名作者是使用了作者的网名小写qxz_+用户最大的ID+1

比如微信扫描之后,系统要添加一个用户(当前用户的最大ID为23)

那么生成的用户帐户就是qxz_24的了。问题来了,如果用户自行注册的话,已经申请了qxz_24的名字,那这就会产生BUG了,虽然你也可以进行ID+1的方式,那就很不好了。

所以修改下文件,禁止名字中包含有”qxz_”这4个字段

1:修改user_passport.dwt模板,找到注册的那一块,在JS里进行判断。(当然也可以不用,毕竟这里不写入数据库)

2:修改user.php文件

找到:$username = isset($_POST[‘username’]) ? trim($_POST[‘username’]) : ”;

在下面加入:

if(strstr($username,’qxz_’)) //判断是否包含微信登陆特有的
{
echo “名字包含qxz_,禁止注册”;exit;
}

这样,qxz_的名字前缀就专门可提供给微信登陆的用户使用了。

如果有mobile端的

查找到你的注册PHP文件,如果有使用MVC的话我相信你看的懂上面的了很快就能找到了。

比如作者的,MVC里对$username有用户名/手机/邮箱的判断注册

为了保险起见,在3个判断之后,我在进行一次

if(strstr($username,’qxz_’)) //判断是否包含微信登陆特有的
{
echo “名字包含qxz_,禁止注册”;exit;
}

的判断,保证有该字段的名字/邮箱(电话肯定更不用说了,正则都过不去!)不会存在qxz_;

通过清心醉

Ecshop网银支付注册/设置

由于网银在线已经被京东收购,网银支付被改名为京东钱包。然后注册为商家。

注册收款服务挺麻烦的,在这作者来给需要的朋友进行详细点的说明。可以加快注册成功!

由于公司里的已经注册成功,所以文字进行说明。

1:申请的时候,请确保网站上有包含公司的名称。(比如页面TITLE/和公司介绍);

2:页脚必须包含ICP备案号;

3:选择的类型为“线下商超”,等申请通过之后一样会提示为网上商城;

4:企业代表人是否和商家帐号是同一人,如果是,资料填写一样的,如果不是,需要写授权书,被授权人需要在申请单上填写自己的身份信息。

5:其实只要1和2的过了,后面的都会有红色字体的提示修改的;

 

如果以上的都已经通过了。那么会生成一份合同,这时候,已经可以去设置网银支付了。

设置以前,我们在京东企业版-安全中心-密钥设置-网关支付密钥管理

设置15位数的MD5密钥。记住改数值,要写入ECSHOP后台的。

至于后台还有个商户ID:这个不是用户的商户号。

在网关支付密钥管理那里,有这么一个:

1

黑色被涂改过的就是商户编号了。(格式其实就是商户ID号+3位数的数字)

通过清心醉

Ecshop解决产品详细页图片模糊的问题

电脑端的打开了产品的页面,产品的图片默认是很模糊的,没有去认真的追踪源码里的获取参数.不过应该就是缩略图强制放大.

解决的方法很简单.修改goods.dwt产品模板

搜索 $goods.goods_img  这是默认显示的第一张图片

如果需要查看图片的位置可以追溯下源代码,看SQL进行处理的时候返回的路径

代码先不管了,修改$goods.goods_img为$goods.original_img,就可以解决问题.

因为每个人使用的主题不一样,代码位置都不一样,但$goods.good_img一般都会继续使用,除非部分主题开发者修改了别的命名.

通过清心醉

Ecshop控制搜索/分类里的产品显示数量

其实很简单,$size的值修改下

系统有判断是否为数字等等,如果不是强制转化为10

直接修改$size=12就可以了。

搜索显示数量修改文件/search.php 245行

分类显示数量修改文件/category.php  49行

通过清心醉

Ecshop二次开发-增加自定义属性的搜索

首先把作者修改好了的贡献出来,需要的朋友请自行下载(放心没写后门)

Ecshop搜索强化-增加自定义属性搜索

ECSHOP前台可按商品名称关键词、商品货号关键词等查找商品,但不能按特点货号查找。特点货号是ECSHOP特点库存的仅有识别号,树立特点库存后,特点货号保存在products表中,下面分析怎么开发按特点货号关键词查找。
search.php

$keywords .= “(goods_name LIKE ‘%$val%’ OR goods_sn LIKE ‘%$val%’ OR keywords LIKE ‘%$val%’ $sc_dsad)”;
修改为
$keywords .= “(goods_name LIKE ‘%$val%’ OR goods_sn LIKE ‘%$val%’ OR product_sn LIKE ‘%$val%’ OR keywords LIKE ‘%$val%’ $sc_dsad)”;

ECSHOP默认使用的是goods_name\goods_sn\keywords。其实要想搜索出来的产品条件更多,可以goods_brief产品描述等,不过这样会影响速度,不建议。上面修改的SQL语句中增加了product_sn特点货号关键字的搜索

 

$sql = “SELECT COUNT(*) FROM ” .$ecs->table(‘goods’). ” AS g “.
“WHERE g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 $attr_in “.
“AND (( 1 ” . $categories . $keywords . $brand . $min_price . $max_price . $intro . $outstock .” ) “.$tag_where.” )”;
修改为:
$sql = “SELECT COUNT(*) FROM ” .$ecs->table(‘goods’). ” AS g “.
“LEFT JOIN ” . $GLOBALS[‘ecs’]->table(‘products’) . ” AS p “.
“ON g.goods_id = p.goods_id “.
“WHERE g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 $attr_in “.
“AND (( 1 ” . $categories . $keywords . $brand . $min_price . $max_price . $intro . $outstock .” ) “.$tag_where.” )”;

// 取得契合条件的商品总数,SQL语句增加goods表与products表衔接查询。

接下来就是查询产品了,同样要增加goods表与products表链接查询。

$sql = “SELECT g.goods_id, g.goods_name, g.market_price, g.is_new, g.is_best, g.is_hot, g.shop_price AS org_price, “.
“NULL.user_price, g.shop_price * ‘$_SESSION[discount]’) AS shop_price, “.
“g.promote_price, g.promote_start_date, g.promote_end_date, g.goods_thumb, g.goods_img, g.goods_brief, g.goods_type “.
“FROM ” .$ecs->table(‘goods’). ” AS g “.
“LEFT JOIN ” . $GLOBALS[‘ecs’]->table(‘member_price’) . ” AS mp “.
“ON mp.goods_id = g.goods_id AND mp.user_rank = ‘$_SESSION[user_rank]’ “.
“WHERE g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 $attr_in “.
“AND (( 1 ” . $categories . $keywords . $brand . $min_price . $max_price . $intro . $outstock . ” ) “.$tag_where.” ) ” .
“ORDER BY $sort $order”;
修改为:
/* 查询商品 */
$sql = “SELECT g.goods_id, g.goods_name, g.market_price, g.is_new, g.is_best, g.is_hot, g.shop_price AS org_price, “.
“IFNULL(mp.user_price, g.shop_price * ‘$_SESSION[discount]’) AS shop_price, “.
“g.promote_price, g.promote_start_date, g.promote_end_date, g.goods_thumb, g.goods_img, g.goods_brief, g.goods_type “.
“FROM ” .$ecs->table(‘goods’). ” AS g “.
“LEFT JOIN ” . $GLOBALS[‘ecs’]->table(‘member_price’) . ” AS mp “.
“ON mp.goods_id = g.goods_id AND mp.user_rank = ‘$_SESSION[user_rank]’ “.
“LEFT JOIN ” . $GLOBALS[‘ecs’]->table(‘products’) . ” AS p “.
“ON g.goods_id = p.goods_id “.
“WHERE g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 $attr_in “.
“AND (( 1 ” . $categories . $keywords . $brand . $min_price . $max_price . $intro . $outstock . ” ) “.$tag_where.” ) ” .
“ORDER BY $sort $order”;

到此搜索自定义属性的产品开发完毕。

 

通过清心醉

Ecshop同步手机/邮箱/用户名登陆方法

首先作者提醒下,邮箱关系倒不到,不过考虑到后期肯定也要做个邮箱验证。

而手机是必须要有验证的,否则的话建议在模板里关闭手机注册/修改功能,否则上线之后手机号重复是个很严肃的问题。

言归正转:

修改user.php文件。

ECSHOP登陆的,请求的是该页面

elseif ($action == ‘act_login’) 在这里是请求登陆

当获取了参数之后是执行if ($user->login($username, $password,isset($_POST[‘remember’])))里的

所以我们需要写在这之前

首先我们在文件结尾处写个判断电话号码的正则表达式:

function is_telephone($phone)
{
$phones= “/^13[0-9]{1}[0-9]{8}$|15[0-9]{1}[0-9]{8}$|18[0-9]{1}[0-9]{8}$/”;
if (preg_match($phones, $phone))
{
return true;
}
else
{
return false;
}
}

接下来:

if(is_email($username)) //首先判断是否符合邮件
{
$sql =”select user_name from “.$ecs->table(‘users’).” where email='”.$username.”‘”; //SQL语句
$username_e = $db->getOne($sql); //如果有存在的数据赋值给变量
if($username_e) //判断前一句的返回值
{
$username=$username_e; //重新赋值
}
}
if(is_telephone($username))
{
$sql =”select user_name from “.$ecs->table(‘users’).” where mobile_phone='”.$username.”‘”;
$username_e = $db->getOne($sql);
if($username_e)
{
$username=$username_e;
}
}
 if ($user->login($username, $password,isset($_POST[‘remember’]))) 必须写在该语句前,才能很好的判断。因为会给$username重新赋值

这样就可以完整的多登陆方式了!

通过清心醉

Ecshop二次开发-增加立即结算

Ecshop默认的购物流程是先增加到购物车,然后再执行结算生成订单,如果客户看到了产品想直接购买,就会多个无趣的购物车过程。

修改方法网上也有,但可能说的不是很明细。而且该方法也会有争议的地方。

比如用户直接购买但未完成,然后返回主页什么的,购物车是否要清空重新计算,这个得看个人的需求。作者默认是不修改购物车的内容。

好了。直接说开发过程。

产品详细页在goods.dwt文件里

约337行(各人主题不一样。你可以搜索javascript:addToCart({$goods.goods_id}))

这是直接加入购物车的,我们在这下一行新增一个立即计算的URL

<a href=”javascript:Clearing({$goods.goods_id})”>立即结算</a>

点击时触发Clearing方法,参数为产品的ID,这时候我们的触发按钮就做好了。在写JS以前我们先来看JS的文件体:

 

 

/js/common.js文件

function addToCart(goodsId, parentId)  有这么一个方法是AJAX的POST请求,里面有个Ajax.call()方法在transport.js文件里有写请求方法等。

在该方法里有个Ajax.call(….. addToCartResponse, ‘POST’, ‘JSON’)  //这里的addToCartResponse就是回调方法了

我们复制addToCart和addToCartResponse这两个方法

重新命名为Cliaring和Cliaringreturn  //第一个为AJAX请求,第二个为回调

修改Cliaring里的Ajax.call请求的回调URL::

Ajax.call(….. addToCartResponse, ‘POST’, ‘JSON’)为Ajax.call(….. Cliaringreturn, ‘POST’, ‘JSON’)

接下来,我们修改Cliaringreturn的回调里的一个变量URL

var cart_url = ‘flow.php?step=checkout‘;  修改为var cart_url = ‘flow.php?step=cart‘;

到此修改就完毕了。

针对mobile手机端的话,其实是大同小异,只是mobile开发者使用了MVC的结构,这时候我们一样可以借鉴。

 

通过清心醉

Ecshop-mobile-网银支付开发

如果是针对电脑端的,系统默认已经封装了很多的方法可以使用。

针对mobile端:ECTouch

首先我们在创建订单的时候,系统会循环输出数据库里存在的支付方式,因为手机端不同于电脑端,ECTouch自己有创建一个表:

先说说流程,如果订单被创建,选择的是网银支付,那么就会有个表单POST到网银支付网关

请求的URL地址为:pay3.chinabank.com.cn/PayGate

由于公司的网关支付接口刚申请,只能使用测试阶段,测试后发现跳转过后的其实是电脑端的页面,说明应该还有其他的手机端请求,等公司的申请下来了再来公布应该请求的URL地址

首先我们应该有个语言包wangyin.php文件:

<?php
if (! defined(‘IN_ECTOUCH’)) {
die(‘非法访问’);
}
global $_LANG;
$_LANG[‘wangyin’] = ‘网银支付’;
$_LANG[‘wangyin_desc’] = ‘网银在线支付’;
$_LANG[‘wangyin_account’] = ‘网银商家帐号’;
$_LANG[‘wangyin_key’] = ‘网银KEY’;
$_LANG[‘pay_button’] = ‘立即使用网银在线支付’;
?>

在language/zh_cn/目录(注是插件里)

然后我们来看核心的文件wangyin.php:panment目录里

<?php
/*
* 网银支付插件手机端
* 作者:清心醉
* 更多开发请参考 http://www.qingxinzui.com/
*
* 参数说明:
* 由于使用的是手机端的开发
* 目录应该为:
* mobile/pulgins/payment/
*
* 更多需要在后台显示出来的参数,可以在语言包里增加
*/
if (!defined(‘IN_ECTOUCH’))
{
die(‘非法访问!’);
}
$payment_lang = ROOT_PATH . ‘plugins/payment/language/’ . C(‘lang’) . ‘/’ . basename(__FILE__);

if (file_exists($payment_lang))
{
include_once ($payment_lang);
L($_LANG);
}

if (isset($set_modules) && $set_modules == TRUE)
{
$i = isset($modules) ? count($modules) : 0;
$modules[$i][‘code’] = basename(__FILE__, ‘.php’);
$modules[$i][‘desc’] = ‘wangyin_desc’;
$modules[$i][‘is_cod’] = ‘0’;
$modules[$i][‘is_online’] = ‘1’;
$modules[$i][‘pay_fee’] = ‘0’;
$modules[$i][‘author’] = ‘<a href=”http://www.qingxinzui.com”  target=”_black”>清心醉</a>’;
$modules[$i][‘website’] = ‘http://www.qingxinzui.com/’;
$modules[$i][‘version’] = ‘1.0.0’;
$modules[$i][‘config’] = array(
array(‘name’ => ‘wangyin_account’, ‘type’ => ‘text’, ‘value’ => ‘1001’),
array(‘name’ => ‘wangyin_key’, ‘type’ => ‘text’, ‘value’ => ‘test’),
);
return;
}

class wangyin
{
function wangyin()
{
}

function __construct()
{
$this->wangyin();
}
function get_code($order, $payment)
{
$data_vid = trim($payment[‘wangyin_account’]);
$data_vpaykey = trim($payment[‘wangyin_key’]);
$data_orderid = $order[‘order_sn’];
$data_vamount = $order[‘order_amount’];
$data_vmoneytype = ‘CNY’;
$data_vreturnurl = return_url(basename(__FILE__, ‘.php’));
if (empty($order[‘order_id’]))
{
$remark1 = “qingxinzui”;
}
else
{
$remark1 = ”;
}

$MD5KEY =$data_vamount.$data_vmoneytype.$data_orderid.$data_vid.$data_vreturnurl.$data_vpaykey;
/*
* 在这里特别要注意拼接的顺序
*/
$MD5KEY = strtoupper(md5($MD5KEY));
//MD5转大写

$def_url = ‘<br /><form style=”text-align:center;” method=”post” name=”E_FORM” action=”https://pay3.chinabank.com.cn/PayGate” target=”_blank”>’;
//请求URL,根据多种不同的版本action的参数不同
$def_url .= “<input type=HIDDEN name=’v_mid’ value='”.$data_vid.”‘>”;
$def_url .= “<input type=HIDDEN name=’v_oid’ value='”.$data_orderid.”‘>”;
$def_url .= “<input type=HIDDEN name=’v_amount’ value='”.$data_vamount.”‘>”;
$def_url .= “<input type=HIDDEN name=’v_moneytype’ value='”.$data_vmoneytype.”‘>”;
$def_url .= “<input type=HIDDEN name=’v_url’ value='”.$data_vreturnurl.”‘>”;
$def_url .= “<input type=HIDDEN name=’v_md5info’ value='”.$MD5KEY.”‘>”;
$def_url .= “<input type=HIDDEN name=’remark1’ value='”.$remark1.”‘>”;
$def_url .= “<input type=submit value=’转到网银支付’>”;
$def_url .= “</form>”;
return $def_url;
}

function callback($data)
{
if (!empty($_GET))
{
$payment = model(‘Payment’)->get_payment($data[‘code’]);

$v_oid = trim($_POST[‘v_oid’]);
$v_pmode = trim($_POST[‘v_pmode’]);
$v_pstatus = trim($_POST[‘v_pstatus’]);
$v_pstring = trim($_POST[‘v_pstring’]);
$v_amount = trim($_POST[‘v_amount’]);
$v_moneytype = trim($_POST[‘v_moneytype’]);
$remark1 = trim($_POST[‘remark1’ ]);
$v_md5str = trim($_POST[‘v_md5str’ ]);

$key= $payment[‘wangyin_key’];
$md5string=strtoupper(md5($v_oid.$v_pstatus.$v_amount.$v_moneytype.$key));

if ($v_md5str==$md5string)
{
if ($v_pstatus == ’20’)
{
if ($remark1 == ‘qingxinzui’)
{
$v_oid = model(‘Payment’)->get_order_id_by_sn($v_oid, “true”);
}
else
{
$v_oid = model(‘Payment’)->get_order_id_by_sn($v_oid);
}
model(‘Payment’)->order_paid($v_oid, 2);
return true;
}
}
else
{
return false;
}
}
else
{
return false;
}

}
public function notify()
{
$this->callback();
}

}

?>

在这里特别鄙视下某些群组,一个简单的方法,硬是没人和你说

事实也证明,自学是最好的能力的象征。

如有不懂的或者支付的开发,请留言

或者邮件至:admin@qingxinzui.com

通过清心醉

Ecshop邮件设置

25端的话没去试,作者使用的是465的SSL

由于ECSHOP对PHP的要求版本在5.3以内,该版本内的PHP里默认是不打开openssl扩展的

需要修改两个文件:

httpd.conf文件打开

mod_ssl.so

php.ini文件打开

extension=php_openssl.dll

 

然后重启apache即可.

 

通过清心醉

ecshop二次开发之模版调用PHP文件的变量

不管你对MVC认识有多少,如果只是修改核心的话,不涉及使用MVC,但如果有别人的插件,是基于MVC模式进行开发的,你要修改就难了。

好了上正题:

在这里我严重鄙视下中国人的开源精神,对这些很基础很简单的问题,没几个人说

给实例::

$id=123456;

$this->assign(‘fenleiid’,$id);

$this->display(‘fenleiid.dwt’);

首先由于有模板库的机制

我们在fenleiid.dwt模版文件里引用模版库

<!– #BeginLibraryItem “/library/catgoodsall.lbi” –><!– #EndLibraryItem –>

这时候,我们之需要在catgoodsall.lbi文件里这么写:

{$fenleiid} 就可以提取变量了 如果是数组,就用for循环吧, 注意模板库里的变量名字$fenleiid

是在$this->assign(‘fenleiid‘,$id);  定义的,就是说,模版生成个变量(可以是数组)名叫fenleiid 他的值是$id(也可以是返回的数组)。

搞定,有不懂的,直接留言。

通过清心醉

Ecshop 手机端ECTouch二次开发实例

最近上班了。没去写Magento二次开发的实例了。

接收了Ecshop的开发,首先就是mobile端的开发。

默认的ECTouch使用的是首页显示所有的产品,没有分类处理、没有产品数量处理,一页循环加载所有产品。

如果有看作者开始写的首次接触Ecshop,我想你能猜到个大概的流程了。

不过这个就有点不一样哦,ECTouch运用了自己的MVC模式,如果没有任何的MVC基础,是难以理解的哦!

正文开始:

由于需要的是修改正文,我们看看URL:

127.0.0.1/mobile/index.php?m=default&c=index&a=index

有3个参数admin/default/install

在mobile/include/apps里可以看到,里面就有了MVC的目录架构,至于admin的话就有V层,因为要编辑嘛

第一个应该是主题的名称/themes/default/

c=index&a=index 控制器和方法了

控制器文件:mobile/include/apps/controller/IndexController.class.php
class IndexController extends CommonController {

public function index()

比如作者要修改index首页的信息,显示一级分类3的最新8个产品:

$this->assign(‘fenlei3’,model(‘Index’)->get_fenlei_id_num(3,8)); #加入这句在
$this->display(‘index.dwt’);  #之前

看,这有个model,系统会自动实例化,model(‘index’),这里面的index参数,就是我们要实例化调用的model模型数据

模型文件:mobile/include/apps/model/IndexModel.class.php

我们在来看我们这的第二个参数,第二个参数是一个方法的返回值:

get_fenlei_id_num(3,8) ,所以IndexModel.class.php文件里加入该方法:

*
* 调用指定分类产品的方法 http://www.qingxinzui.com/
*
*/
function get_fenlei_id_num($cat_id = ”, $num = ”) #提取指定分类的产品 ,需要分类id和提取的数量(默认提取最前面的)
{
/*SQL语句开始*/
$sql =
‘Select g.goods_id, g.cat_id,c.parent_id, g.goods_name, g.goods_name_style,
g.market_price, g.shop_price AS org_price, g.promote_price, ‘ .
“IFNULL(mp.user_price, g.shop_price * ‘$_SESSION[discount]’) AS shop_price, ” .
“promote_start_date, promote_end_date, g.goods_brief, g.goods_thumb, goods_img, ” .
“g.is_best, g.is_new, g.is_hot, g.is_promote ” .
‘FROM ‘ . ‘ecs_goods’ . ‘ AS g ‘ .
‘LEFT JOIN ‘ . ‘ecs_category’  . ‘ AS c ON c.cat_id = g.cat_id ‘ .
“LEFT JOIN ” . ‘ecs_member_price’. ” AS mp ” .
“ON mp.goods_id = g.goods_id AND mp.user_rank = ‘$_SESSION[user_rank]’ ” .
“Where g.is_on_sale = 1 AND g.is_alone_sale = 1 AND g.is_delete = 0 ” .
$sql .= ” AND (c.parent_id =” . $cat_id . ” OR g.cat_id = ” . $cat_id . ” OR g.cat_id ” . db_create_in ( array_unique ( array_merge ( array (
$cat_id
), array_keys ( cat_list ( $cat_id, 0, false ) ) ) ) ) . “)”;
$sql .= ” LIMIT $num”;
/*SQL语句结尾*/
/*
* 由于该手机模板没有使用电脑端的部分函数,所以上面的表名是自己添加的如果表前缀有问题则要修改下
*
* */
$res = $this->query($sql); #提取指定分类的所有数据所有SQL产品数据
$goods = array (); #定义数组接收提取所有的到数组
$o=1; #用于模板后面的判断
foreach ( $res as $idx => $row )
{
$goods [$idx] [‘id’] = $row [‘article_id’];
$goods [$idx] [‘id’] = $row [‘goods_id’];
$goods [$idx] [‘name’] = $row [‘goods_name’];
$goods [$idx] [‘brief’] = $row [‘goods_brief’];
$goods [$idx] [‘brand_name’] = $row [‘brand_name’];
$goods [$idx] [‘goods_style_name’] = add_style ( $row [‘goods_name’], $row [‘goods_name_style’] );
$goods [$idx][‘short_name’] = C(‘goods_name_length’) > 0 ? sub_str($row[‘goods_name’], C(‘goods_name_length’)) : $row[‘goods_name’];
$goods [$idx] [‘short_style_name’] = add_style ( $goods [$idx] [‘short_name’] );
$goods [$idx] [‘market_price’] = price_format ( $row [‘market_price’] );
$goods [$idx] [‘shop_price’] = price_format ( $row [‘shop_price’] );
$goods [$idx][‘thumb’] = get_image_path($row[‘goods_id’], $row[‘goods_thumb’], true);
$goods [$idx][‘goods_img’] = get_image_path($row[‘goods_id’], $row[‘goods_img’]);
$goods [$idx] [‘url’] = build_uri(‘goods/index’, array(‘id’ => $row[‘goods_id’]));
if(!($o&1)) #判断是否为偶数
{
$goods[$idx][‘_number’]=2;  #如果是偶数 每一行的都为2
}
else
{
$goods[$idx][‘_number’]=1; #否则为1
}
$o++;
}
return $goods; #返回数组
}

作者在这里加了_number,后面有用,继续吧

这里会以数组的方式把提取的8个最新的产品数据返回给控制器。

$this->assign(‘fenlei3’,…) 这里因为有了命名了。

好了,我们修改index.dwt 把系统默认显示所有产品的

<!– #BeginLibraryItem “/library/recommend_hot.lbi” –><!– #EndLibraryItem –>

这文件做修改吧

<table width=’100%’ align=’center’ border=”0″ cellspacing=”0″ cellpadding=”0″>
<!–{foreach from=$fenlei3 item=goods}–>
<!–{if $goods._number eq 1}–>
<tr>
<td width=’50%’ align=’center’>
<p><b><a href=”{$goods.url}” title=”{$goods.name|escape:html}” target=”_blank”>{$goods.name}</a></b></p>
<p><a href=”{$goods.url}” target=”_blank”>
<p><img src=”{$goods.goods_img}” alt=”{$goods.name|escape:html}” width=”150px” height=”150px”/></a></p>
<p><div style=”text-indent: 5px;”>市场价<span>{$goods.market_price}</span></p>
<p><div style=”text-indent: 7px;”><span>售  价{$goods.shop_price}</span></div></p>

</td>
<!–{else $goods._number eq 2}–>
<td width=’50%’ align=’center’>
<p><b><a href=”{$goods.url}” title=”{$goods.name|escape:html}” target=”_blank”>{$goods.name}</a></b></p>
<p><a href=”{$goods.url}” target=”_blank”>
<p><img src=”{$goods.goods_img}” alt=”{$goods.name|escape:html}” width=”150px” height=”150px”/></a></p>
<p><div style=”text-indent: 5px;”>市场价<span>{$goods.market_price}</span></p>
<p><div style=”text-indent: 7px;”><span>售  价{$goods.shop_price}</span></div></p>
</td>
</tr>
<tr><td colspan=”2″ height=”10px”></td></tr>
<!–{/if}–>
<!–{/foreach}–>
</table>

前面提到了_number,这是一个判断奇偶的,因为模板里不能很好的用PHP,除非修改核心的过滤代码,可是修改过后就不安全了。

这里作者是要输出table,两列,因为_number是1和2 所以只做两个判断,如果1输出第一个并且带<tr>开始,如果2输出第二个并且带<tr>结束

这里不用怕会出错,因为模型model的方法里,$o是自增长的,然后整除2来判断。

视图效果可能不太友好,毕竟作者主要还是针对PHP后端及服务器。

 

 

 

 

通过清心醉

首次接触Ecshop

上班的公司使用的是Ecshop开发的电子商城,虽然作者一直都是针对Magento的安装维护及开发的学习、工作,也曾想过把公司的Ecshop换成Magento,但由于当前的Ecshop前端效果基本已经做完,只需要实现PHP的功能就好了,前端需要的也就是小改。

一开始开网上说,有PHP基础,很容易操作,我们都知道,PHP二次开发来说,最基本的就是对数据库的增删改查了。

我们来看看Ecshop的代码流程,也算是让刚接触Ecshop的其他新手知道Ecshop的过程是如何实现的。

Ecshop 感觉最麻烦的,就是需要修改什么就得代码里增加,这和Magneto的插件扩展性来说,根本就不是一个级别的。

Ecshop主页通过$smarty->assign()来调用需要的数据,在$smarty->display(‘index.dwt’);前

比如说$smarty->assign()获取最新产品,这里面一般有两个参数

$smarty->assign(‘chanpin’, cat_chanpin(3,4));

这里的意思是调用分类3的产品4个。第二个参数是进行SQL操作的一个方法,你可以改成你需要返回的数组值

第一个参数算是命名方法吧,作者命名为chanpin

这样,视图模板就可以使用了。不过视图模板之前,还有一个叫lib的模板库文件

index.dwt这种dwt后缀的虽然说是显示操作,但其实核心数据还是在当前主题的library文件夹里。

好了,来个代码走势图:

index.php入口

$smarty->assign(‘chanpin’, cat_chanpin(3,4)); #假设cat_chanpin($a,$b)方法已经存在并且返回数据库的数组

$smarty->display(‘index.dwt’); #访问的首页视图

index.dwt开始提取同级目录中的library目录里的需要文件

<!– #BeginLibraryItem “/library/page_header.lbi” –><!– #EndLibraryItem –>

这就是提取/library/page_header.lbi模板库文件里的数据

page_header.bli文件里如果我们需要foreach循环数据,命名方式为:

<!–{foreach from=$fenlei item=goods}–>

这里注意,item是必须的参数,更多的可以参考模板的说明。