很久没搞支付这一块了,这星期搞得头都大了,刚开始在网上到处找资料,很久都没解决,毕意别人出问题的情况可能不一样,最终放弃,一步一步研究支付宝的程序,最终自己解决,记录一下流程:
原文地址:http://www.hu-rong.com/Article/view/id/176.html 欢迎转载
1、首先申请“手机网站支付”这一种
2、下载demo:
http://doc.open.alipay.com/doc2/detail.htm?spm=0.0.0.0.77SWb3&treeId=60&articleId=103564&docType=1
由于我用的php开发,解压后选的“alipay.wap.create.direct.pay.by.user-PHP-UTF-8”这个文件夹里面的,如下:
3、由于我把支付集成到thinkphp里面开发的,签名方式选的RSA,下面以thinkphp为例说明,首先按支付宝的说明要先成用户的公私和私钥;先在window环境下生成,各种难搞,生成失败,最终放弃了,用虚拟机装了个ceotos,在里里轻松生成;官方说明:http://doc.open.alipay.com/doc2/detail.htm?spm=0.0.0.0.73TStA&treeId=58&articleId=103242&docType=1
由于采用linux生成,将上面文件夹中多余的文件删除,删除后如下:
将这些文件复制到站点根目录下的thihkphp框架下,具体路径以实际情况为准,我这里是 ThinkPHP3.1.3_fullExtendVendorAlipay
然后在站点的配置文件中加入支付宝的配置,注意那几个key的路径一定要正确,否则会导致支付不了,或者支付后验证失败:
//↓↓↓↓↓↓↓↓↓↓支付宝配置↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
//合作身份者id,以2088开头的16位纯数字
'alipay_partner' => '这里填自己的',
//收款支付宝账号,一般情况下收款账号就是签约账号
'alipay_seller_id' => '填自已的',
//商户的私钥(后缀是.pen)文件相对路径
'alipay_private_key_path' => './ThinkPHP3.1.3_full/Extend/Vendor/Alipay/key/rsa_private_key.pem',
//支付宝公钥(后缀是.pen)文件相对路径
'alipay_ali_public_key_path'=> './ThinkPHP3.1.3_full/Extend/Vendor/Alipay/key/alipay_public_key.pem',
//签名方式 不需修改
'alipay_sign_type' => strtoupper('RSA'),
//字符编码格式 目前支持 gbk 或 utf-8
'alipay_input_charset'=> strtolower('utf-8'),
//ca证书路径地址,用于curl中ssl校验
//请保证cacert.pem文件在当前文件夹目录中
'alipay_cacert' => './ThinkPHP3.1.3_full/Extend/Vendor/Alipay/cacert.pem',
//访问模式,根据自己的服务器是否支持ssl访问,若支持请选择https;若不支持请选择http
'alipay_transport' => 'http',
Linux用户(以Ubuntu为例,我测试的ceotos下也是用的这些命令),先在linux下进入到ThinkPHP3.1.3_full/Extend/Vendor/Alipay这个目录下
开始生成,先将key文件夹下的rsa_private_key.pem和rsa_public_key.pem删除掉,然后自己来生成新的,步骤如下:
$ openssl 进入OpenSSL程序
OpenSSL> genrsa -out rsa_private_key.pem 1024 生成私钥
OpenSSL> rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem 生成公钥
OpenSSL> exit ## 退出OpenSSL程序
生成成功后,会在key文件夹下生成两个新文件,rsa_private_key.pem和rsa_public_key.pem
然后检查一下alipay_public_key.pem看看他是多行显示的,千万不要改成一行,否则支付成功后会验证失败,我在这里吃了大亏,查了好久才查出来的;总之这个文件下载下来后就不要动它,正确的显示如下
4、上传key
查看
http://doc.open.alipay.com/doc2/detail.htm?spm=0.0.0.0.MJnrao&treeId=58&articleId=103546&docType=1 这里看说明,输入支付密码后可以进去进行设置,
上传
http://doc.open.alipay.com/doc2/detail.htm?spm=0.0.0.0.QKOpxa&treeId=58&articleId=103578&docType=1
上传的时候一定保证是一行,不能有空格,最好先在记事本中处理一下
这里上传的是刚生成的rsa_public_key.pem里面的内容,用记事本打开可以看到;
5、如果开发过程中验证签名失败,还有一个问题就是thinkphp会在支付的时候自动加一个/admin/Article到支付宝的参数里面,导致签名为空,处理方法:
找到lib/alipay_notify.class.php,在此函数中删除掉/admin/Article
function getSignVeryfy($para_temp, $sign) {
unset($para_temp['_URL_']);
找到lib/alipay_core.function.php找到
function paraFilter($para) {,修改一下,加上红色部分
if($key == "sign" || $key == "sign_type" || $val == ""|| $key =="_URL_")
6、写程序,大功告成
<?php
header("Content-type:text/html;charset=utf-8");//没这句支付会出错
/*
* 支付类
*/
class PayAction extends Action{
private $alipay_config;
public $notifyUrl;
public $returnUrl;
public $showUrl;
public $orderid;
public $WIDsubject;//订单标题
public $WIDtotal_fee;//总价
public $WIDbody;//订单说明
public $tableChina;
public $tableProduct;
public $tableColor;//颜色表
public $tableSuit;//套装表
/*
* 自动加载支付宝配置信息
*/
public function _initialize(){
//支付宝配置
$alipay_config['partner']=C('alipay_partner');
$alipay_config['seller_id']=C('alipay_seller_id');
$alipay_config['private_key_path']=C('alipay_private_key_path');
$alipay_config['ali_public_key_path']=C('alipay_ali_public_key_path');
$alipay_config['sign_type']=C('alipay_sign_type');
$alipay_config['input_charset']=C('alipay_input_charset');
$alipay_config['cacert']=C('alipay_cacert');
$alipay_config['transport']=C('alipay_transport');
$this->alipay_config=$alipay_config;
//支付宝需要加载的类
require_once("ThinkPHP3.1.3_full/Extend/Vendor/Alipay/lib/alipay_submit.class.php");
require_once("ThinkPHP3.1.3_full/Extend/Vendor/Alipay/lib/alipay_notify.class.php");
require_once("ThinkPHP3.1.3_full/Extend/Vendor/Alipay/lib/alipay_notify.class.php");
//同步及异步通知url
$this->notifyUrl = "http://mall.dynam-rc.cn/Pay/alipay_notify_url.html";//服务器异步通知页面路径,需http://格式的完整路径,不能加?id=123这类自定义参数
$this->returnUrl = "http://mall.dynam-rc.cn/Pay/alipay_return_url.html";//页面跳转同步通知页面路径-支付完成返回的网址,需http://格式的完整路径,不能加?id=123这类自定义参数,不能写成http://localhost/
$this->showUrl = "http://mall.dynam-rc.cn/Order/index.html";
//中国地区
$prefix=C('DB_PREFIX');
$this->tableChina=$prefix.'china';
$this->tableProduct=$prefix.'product';
$this->tableColor=$prefix.'shop_product_color';
$this->tableSuit=$prefix.'shop_product_suit';
}
/*
* 选择支付平台
*/
public function index(){
$type=I('type','','string');
$orderid=I('orderid','','string');
$type?true:$this->error('请选择支付方式');
if($orderid){
$this->orderid=$orderid;
//订单数据
$field="o.*,c1.`name` as `provinceName`,c2.`name` as `cityName`,c3.`name` as `townName`,c4.`name` as `streetName`";
$where="o.`orderid`='$orderid'";
$arr=M('order o')
->join("`$this->tableChina` c1 on o.`province`=c1.`id`")
->join("`$this->tableChina` c2 on o.`city`=c2.`id`")
->join("`$this->tableChina` c3 on o.`town`=c3.`id`")
->join("`$this->tableChina` c4 on o.`street`=c4.`id`")
->field($field)
->where($where)
->find();
//构建订单详细说明
//$field1="op.*,p.`name`,c.`name` as `colorName`,s.`name` as `suitName`";
$field1="op.*,p.`name`";
$where1="op.`orderid`='$orderid'";
$arr1=M('order_product op')
->join("`$this->tableProduct` p on p.`id`=op.`productID`")
//->join("`$this->tableColor` c on c.`id`=op.`colorid`")
//->join("`$this->tableSuit` s on s.`id`=op.`suitid`")
->field($field1)
->where($where1)
->select();
$num=count($arr1);
$str.='订单总金额:'.$arr['money_all'].',其中产品金额:'.$arr['money_pt'].",运费:".$arr['money_freight'].',商品详细信息:<br/>';
for($i=0;$i<$num;$i++){
$str.=$arr1[$i]['name'].'(商品id号:'.$arr1[$i]['productID'];
if($arr1[$i]['colorid']){
$str.=',颜色id:'.$arr1[$i]['colorid'];
}
if($arr1[$i]['suitid']){
$str.=',套装id:'.$arr1[$i]['suitid'];
}
$str.=',单价:'.$arr1[$i]['price'].',数量:'.$arr1[$i]['shuliang'].')<br/>';
}
$this->WIDsubject='来自mall.dynam-rc.cn的订单';
$this->WIDtotal_fee=$arr['money_all'];
$this->WIDbody=$str;
//准备支付
switch ($type){
case 'alipay'://支付宝
self::alipay();
break;
case 'weibin'://微信
self::weixin();
break;
}
}else{
$this->error('参数错误');
}
}
/*
* 支付宝支付请求
*/
public function alipay(){
/* *
* 功能:手机网站支付接口接入页
* 版本:3.3
* 修改日期:2012-07-23
* 说明:
* 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
* 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
*************************注意*************************
* 如果您在接口集成过程中遇到问题,可以按照下面的途径来解决
* 1、商户服务中心(https://b.alipay.com/support/helperApply.htm?action=consultationApply),提交申请集成协助,我们会有专业的技术工程师主动联系您协助解决
* 2、商户帮助中心(http://help.alipay.com/support/232511-16307/0-16307.htm?sh=Y&info_type=9)
* 3、支付宝论坛(http://club.alipay.com/read-htm-tid-8681712.html)
* 如果不想使用扩展功能请把扩展功能参数赋空值。
*/
//require_once("ThinkPHP3.1.3_full/Extend/Vendor/Alipay/lib/alipay_submit.class.php");
/**************************请求参数**************************/
$payment_type = "1";//必填,不可修改,支付类型,仅支持:1(商品购买)。
$notify_url = $this->notifyUrl;//服务器异步通知页面路径,需http://格式的完整路径,不能加?id=123这类自定义参数
$return_url = $this->returnUrl;//页面跳转同步通知页面路径-支付完成返回的网址,需http://格式的完整路径,不能加?id=123这类自定义参数,不能写成http://localhost/
$out_trade_no = $this->orderid;//必填,网站上产生的订单号
$subject = $this->WIDsubject;//必填,商品的标题/交易标题/订单标题/订单关键字等。该参数最长为128个汉字。
$total_fee = $this->WIDtotal_fee;//必填,该笔订单的资金总额,单位为RMB-Yuan。取值范围为[0.01,100000000.00],精确到小数点后两位。
$show_url = $this->showUrl;//选填,商品展示地址,需以http://开头的完整路径,例如:http://www.商户网址.com/myorder.html
$body = $this->WIDbody;//选填,对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。
$parameter = array(
"service" => "alipay.wap.create.direct.pay.by.user",
"partner" => trim($this->alipay_config['partner']),
"seller_id" => trim($this->alipay_config['seller_id']),
"payment_type" => $payment_type,
"notify_url" => $notify_url,
"return_url" => $return_url,
"out_trade_no" => $out_trade_no,
"subject" => $subject,
"total_fee" => $total_fee,
"show_url" => $show_url,
"body" => $body,
"it_b_pay"=>'',
"extern_token"=>'',
"_input_charset" => trim(strtolower($this->alipay_config['input_charset']))
);
//建立请求
$alipaySubmit = new AlipaySubmit($this->alipay_config);
$html_text = $alipaySubmit->buildRequestForm($parameter,"get", "确认");
echo $html_text;
}
/*
* 支付完成后同步通知页面
*/
public function alipay_return_url(){
$alipayNotify = new AlipayNotify($this->alipay_config);
$verify_result = $alipayNotify->verifyReturn();
if($verify_result) {//验证成功,验证消息是否是支付宝发出的合法消息
$body=$_GET['body'];//可空,订单详细描述
$issuccess=$_GET['is_success'];//不可空,表示接口调用是否成功,并不表明业务处理结果。
$notify_id=$_GET['notify_id '];//可空,支付宝通知校验ID,商户可以用这个流水号询问支付宝该条通知的合法性。
$notify_time=$_GET['notify_time'];//可空,通知时间(支付宝时间)。格式为yyyy-MM-dd HH:mm:ss。
$notify_type=$_GET['notify_type'];//可空,返回通知类型。
$out_trade_no = $_GET['out_trade_no'];//可空,网站产生的订单号,必须唯一
$trade_no = $_GET['trade_no'];//可空,支付宝交易号
$trade_status = $_GET['trade_status'];//交易目前所处的状态。成功状态的值只有两个:TRADE_FINISHED(普通即时到账的交易成功状态);TRADE_SUCCESS(开通了高级即时到账或机票分销产品后的交易成功状态)
$total_fee=$_GET['total_fee'];//该笔订单的总金额。请求时对应的参数,原样通知回来。
$seller_id =$_GET['seller_id'];//卖家支付宝账号对应的支付宝唯一用户号。以2088开头的纯16位数字。
$url='http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'?'.$_SERVER['QUERY_STRING'];//请求的整个网址
if($_GET['trade_status'] == 'TRADE_FINISHED' || $_GET['trade_status'] == 'TRADE_SUCCESS') {
//判断该笔订单是否在商户网站中已经做过处理
$arr=M('order')->where(array('orderid'=>$out_trade_no))->find();
if(($arr['money_all']==$total_fee)&&($seller_id==C('alipay_seller_id'))){
if($arr['ispay']==0){//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
$data=array(
'ispay'=>1,
'body'=>$body,
'trade_no'=>$trade_no,
'trade_status'=>$trade_status,
'url_return'=>$url
);
M('order')->data($data)->where(array('orderid'=>$out_trade_no))->save();
}
}
}else {
echo "trade_status=".$_GET['trade_status'];
}
echo "验证成功<br />";
}else {
echo '验证失败';
}
}
/*
* 支付宝异步通知页面
*/
public function alipay_notify_url(){
//计算得出通知验证结果
$alipayNotify = new AlipayNotify($this->alipay_config);
$verify_result = $alipayNotify->verifyNotify();
if($verify_result) {//验证成功
$buyer_email=$_POST['buyer_email'];//可空,买家支付宝帐号
$gmt_create=$_POST['gmt_create'];//可空,该笔交易创建的时间。格式为yyyy-MM-dd HH:mm:ss。
$notify_time=$_POST['notify_time'];//不为空,通知的发送时间。格式为yyyy-MM-dd HH:mm:ss。
$body=$_POST['body'];//可空,订单描述
$gmt_payment=$_POST['gmt_payment'];//买家付款时间
$out_trade_no = $_POST['out_trade_no'];//可空,商户订单号
$trade_no = $_POST['trade_no'];//可空,支付宝交易号
$trade_status = $_POST['trade_status'];//可空,交易状态
$total_fee=$_POST['total_fee'];//该笔订单的总金额。请求时对应的参数,原样通知回来。
$seller_id =$_POST['seller_id'];//卖家支付宝账号对应的支付宝唯一用户号。以2088开头的纯16位数字。
$url='http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'?'.$_SERVER['QUERY_STRING'];//请求的整个网址
if($_POST['trade_status'] == 'TRADE_FINISHED' || $_POST['trade_status'] == 'TRADE_SUCCESS') {
$arr=M('order')->where(array('orderid'=>$out_trade_no))->find();
if(($arr['money_all']==$total_fee)&&($seller_id==C('alipay_seller_id'))){
if($arr['ispay']==0){//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
$data=array(
'ispay'=>1,
'buyer_email'=>$buyer_email,
'body'=>$body,
'trade_no'=>$trade_no,
'trade_status'=>$trade_status,
'url_notify'=>$url
);
if(M('order')->data($data)->where(array('orderid'=>$out_trade_no))->save()){
echo "success";//返回给支付宝的值,请不要修改或删除
}
}
}
}
}else {//验证失败
echo "fail";//返回给支付宝的值,请不要修改或删除
}
}
}
?>
- 相关文章
- phpexcel设置行高及列宽,背景颜色,
- 单点登录sso原理及php实现方式及de
- 在php中用curl请求java接口无法获
- 免费ip地址查询接口
- php,java,android, aes加解密-加密
- 地图上计算两点间的距离
- 关于百度地图的一些技巧
- php中empty,is_null,isset的区别
- windows及linux下composer安装教程
- 一种精妙的数据查询与存储方式
- 热门文章
- win7中将文件拷贝到虚拟机linux下
- phpexcel设置行高及列宽,背景颜色,
- rabbitmq无法启动
- intellij idea不显示git push按钮
- php7中使用mongodb的aggregate进行
- laravel页面静态化的方法
- centos7.4 64位下swoole安装及配置
- navicate连接mycat报1184错误
- curl设置超时不起作用(CURLOPT_TIM
- devops-jenkins容器为pending状态
- 好评文章
- phpexcel设置行高及列宽,背景颜色,
- php7中使用mongodb的aggregate进行
- intellij idea打开文件所在文件夹
- windows下使用MongoDB Compass Com
- win7中将文件拷贝到虚拟机linux下
- laravel 中悲观锁 & 乐观锁的使用
- 单点登录sso原理及php实现方式及de
- navicate连接mycat报1184错误
- rabbitmq无法启动
- laravel整合dingo/api方法步骤:jwt
- 我的项目
- 【github】www.github.com/hurong241
- 【码云】gitee.com/hu_rong/projects
- 【docker hub】hub.docker.com/repositories/hurong241
- 【packagist】packagist.org/users/hurong241/packages
- 站点信息
- 建站时间:2011年
- 文章数:623篇
- 浏览数:1306209