ecshop重新安装之后,配置邮件服务器时,提示”ecshop Access is denied”,一开始以为端口被封了,又不想给服务器安装TELNET来测试连接.经过一番的测试,发现是SELINUX的安全机制的影响.
关闭SELINUX服务即可:
vi /etc/selinux/config
#SELINUX=enforcing修改为SELINUX=disabled
然后reboot即可.
ecshop重新安装之后,配置邮件服务器时,提示”ecshop Access is denied”,一开始以为端口被封了,又不想给服务器安装TELNET来测试连接.经过一番的测试,发现是SELINUX的安全机制的影响.
关闭SELINUX服务即可:
vi /etc/selinux/config
#SELINUX=enforcing修改为SELINUX=disabled
然后reboot即可.
为什么一定要使用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环境配置完成。
连续折腾了3天,被腾讯的API接口搞的半条命了。最后还是被迫修改官方的SDK;
居然是二维码,自然要生成带短链接的URL图片。
大概流程
1:根据订单,公众号,商户号,KEY–》请求接口获取详细配置参数
2:通过第一次请求获取的参数,根据产品名称,价格(注意单位为分,记得要*100计算,订单号,随机数等,再次请求接口获取短链接
3:把短链接生成二维码;
4:为了实现页面跳转,实现AJAX请求判断是否支付成功。
有需要的用户直接到
购买
注:如果您的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端使用了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>”;
}
}
}
默认的用户登陆,都是在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里的积分规则又是如何呢?
在数据库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使用产品自身价格来做积分获取,不管使用了多少积分都是如此。
如果用户下了订单,不付款,积分会一直扣住不返回,这时候只需要用户自行登陆取消订单,或者后台管理人员对久未付款的订单进行无效的时候,积分进行返回!
其实正确的来说应该是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);
就还原出来了.
为什么这么写?其实很多人都会拉
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_;
由于网银在线已经被京东收购,网银支付被改名为京东钱包。然后注册为商家。
注册收款服务挺麻烦的,在这作者来给需要的朋友进行详细点的说明。可以加快注册成功!
由于公司里的已经注册成功,所以文字进行说明。
1:申请的时候,请确保网站上有包含公司的名称。(比如页面TITLE/和公司介绍);
2:页脚必须包含ICP备案号;
3:选择的类型为“线下商超”,等申请通过之后一样会提示为网上商城;
4:企业代表人是否和商家帐号是同一人,如果是,资料填写一样的,如果不是,需要写授权书,被授权人需要在申请单上填写自己的身份信息。
5:其实只要1和2的过了,后面的都会有红色字体的提示修改的;
如果以上的都已经通过了。那么会生成一份合同,这时候,已经可以去设置网银支付了。
设置以前,我们在京东企业版-安全中心-密钥设置-网关支付密钥管理
设置15位数的MD5密钥。记住改数值,要写入ECSHOP后台的。
至于后台还有个商户ID:这个不是用户的商户号。
在网关支付密钥管理那里,有这么一个:
黑色被涂改过的就是商户编号了。(格式其实就是商户ID号+3位数的数字)
电脑端的打开了产品的页面,产品的图片默认是很模糊的,没有去认真的追踪源码里的获取参数.不过应该就是缩略图强制放大.
解决的方法很简单.修改goods.dwt产品模板
搜索 $goods.goods_img 这是默认显示的第一张图片
如果需要查看图片的位置可以追溯下源代码,看SQL进行处理的时候返回的路径
代码先不管了,修改$goods.goods_img为$goods.original_img,就可以解决问题.
因为每个人使用的主题不一样,代码位置都不一样,但$goods.good_img一般都会继续使用,除非部分主题开发者修改了别的命名.
其实很简单,$size的值修改下
系统有判断是否为数字等等,如果不是强制转化为10
直接修改$size=12就可以了。
搜索显示数量修改文件/search.php 245行
分类显示数量修改文件/category.php 49行
首先把作者修改好了的贡献出来,需要的朋友请自行下载(放心没写后门)
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”;
到此搜索自定义属性的产品开发完毕。
首先作者提醒下,邮箱关系倒不到,不过考虑到后期肯定也要做个邮箱验证。
而手机是必须要有验证的,否则的话建议在模板里关闭手机注册/修改功能,否则上线之后手机号重复是个很严肃的问题。
言归正转:
修改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默认的购物流程是先增加到购物车,然后再执行结算生成订单,如果客户看到了产品想直接购买,就会多个无趣的购物车过程。
修改方法网上也有,但可能说的不是很明细。而且该方法也会有争议的地方。
比如用户直接购买但未完成,然后返回主页什么的,购物车是否要清空重新计算,这个得看个人的需求。作者默认是不修改购物车的内容。
好了。直接说开发过程。
产品详细页在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的结构,这时候我们一样可以借鉴。
如果是针对电脑端的,系统默认已经封装了很多的方法可以使用。
针对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
25端的话没去试,作者使用的是465的SSL
由于ECSHOP对PHP的要求版本在5.3以内,该版本内的PHP里默认是不打开openssl扩展的
需要修改两个文件:
httpd.conf文件打开
mod_ssl.so
php.ini文件打开
extension=php_openssl.dll
然后重启apache即可.
不管你对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(也可以是返回的数组)。
搞定,有不懂的,直接留言。
最近上班了。没去写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开发的电子商城,虽然作者一直都是针对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是必须的参数,更多的可以参考模板的说明。