thinkphp支付宝手机网站支付开发技巧
首页->学习资料->编程语言->php教程->php技巧 关键词: 发布时间:2015-12-12 09:51:07 浏览次数:1339

很久没搞支付这一块了,这星期搞得头都大了,刚开始在网上到处找资料,很久都没解决,毕意别人出问题的情况可能不一样,最终放弃,一步一步研究支付宝的程序,最终自己解决,记录一下流程:

原文地址: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";//返回给支付宝的值,请不要修改或删除
        }
    }
}
?>

赞:(0)
踩:(0)
相关文章
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进行
centos7.4 64位下swoole安装及配置
laravel页面静态化的方法
navicate连接mycat报1184错误
单点登录sso原理及php实现方式及de
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
标签
rabbitmq mysql备份 elasticsearch golang swoole
我的项目
【github】www.github.com/hurong241
【码云】gitee.com/hu_rong/projects
【docker hub】hub.docker.com/repositories/hurong241
【packagist】packagist.org/users/hurong241/packages
站点信息
建站时间:2011年
文章数:610篇
浏览数:953068
粤ICP备18028092号-1  微信:hurong241