Thinkphp3.2对接银联支付


项目接入银联支付的过程, 在此记录下,希望能帮助开发盆友平坑。

银联SKD链接:https://open.unionpay.com/ajweb/product/newProDetail?proId=1&cataId

本地保存的sdk

yunpay-sdk-ACP.zip


首先下载sdk包导入以后,创建控制器YunpayController.class.php,

直接上代码:


    <?php

    namespace Appapi\Controller;

    

    use Common\Controller\HomebaseController; 

    

    class YunpayController extends HomebaseController {

    

    

        public function Establish(){

            $data = [

                'uid' => I('uid') ?: 'null',

                'changeid' => I('changeid') ?: 'null',

                'coin' => I('coin') ?: 'null',

                'money' => I('money') ?: 'null',

            ];

            die('<h3>'.var_export($data).'<br>请核对打印参数结果,若与提交一致则说明对接成功');

        }

    

        /* 提交订单 */

        public function index()

        {

    

            header ( 'Content-type:text/html;charset=utf-8' );

            Vendor('Yunpay.acp_service');

    

            $frontUrl = "http://".I("server.HTTP_HOST")."/5.php";        //前台通知地址

            $backUrl = "http://".I("server.HTTP_HOST")."/index.php?g=Appapi&m=yunpay&a=notify_yl";        //后台通知地址

            $params = array(

                //以下信息非特殊情况不需要改动

                'version' => \com\unionpay\acp\sdk\SDKConfig::getSDKConfig()->version,          //版本号

                'encoding' => 'utf-8',                                                              //编码方式

                'txnType' => '01',                                                                  //交易类型

                'txnSubType' => '01',                                                              //交易子类

                'bizType' => '000201',                                                              //业务类型

                'frontUrl' =>  $frontUrl,                                                          //前台通知地址

                'backUrl' =>   $backUrl,                                                          //后台通知地址

                'signMethod' => \com\unionpay\acp\sdk\SDKConfig::getSDKConfig()->signMethod,    //签名方法

                'channelType' => '08',                                                             //渠道类型,07-PC,08-手机

                'accessType' => '0',                                                                //接入类型

                'currencyCode' => '156',

                'merId' => \com\unionpay\acp\sdk\SDKConfig::getSDKConfig()->merid,                   //商户号

                'txnTime' => date('YmdHis'),

                'payTimeout' => date('YmdHis', strtotime('+60 minutes'))                   //订单发送时间(超过超时时间调查询接口应答origRespCode不是A6或者00的就可以判断为失败)

            );

    

    

            $uid=I("uid");

            $token=I("token");

            $changeid=I("changeid");

            $coin=I("coin");

            $money=I("money");

    

            if(!$uid || !$token){

                $rs['code']=1001;

                $rs['msg']='身份未验证:uid or token on null!';

                $this->ajaxReturn($rs);

            }

            if(!$changeid || (!is_numeric($changeid))){

                $rs['code']=1002;

                $rs['msg']='商品ID错误:changeid on null or changeid not numeric!';

                $this->ajaxReturn($rs);

            }

            if(!$coin || !$money){

                $rs['code']=1003;

                $rs['msg']='商品信息错误:coin or money on null!';

                $this->ajaxReturn($rs);

            }

    

            if(!$true_token = M('users')->where("id={$uid} and user_type='2'")->order("id DESC")->getField("token")) {

                $rs['code']=1004;

                $rs['msg']='身份验证失败:uid not null!';

                $this->ajaxReturn($rs);

            }

    

            if($true_token != $token){

                $rs['code']=1005;

                $rs['msg']='身份验证失败:token not null!'.$true_token;

                $this->ajaxReturn($rs);

            }

    

            if( !$uid || !$token || checkToken($uid,$token)==700 ){

                $rs['code']=1005;

                $rs['msg']='身份验证失败:token not null!';

                $this->ajaxReturn($rs);

            }

    

            if(!$change_info = M("charge_rules")->where("id='{$changeid}'")->find()) {

                $rs['code']=1006;

                $rs['msg']='商品信息错误:changeid not null!';

                $this->ajaxReturn($rs);

            }

    

            if ($change_info['coin'] != $coin || $change_info['money'] != $money) {

                $rs['code']=1007;

                $rs['msg']='商品信息错误:coin or money untrue!';

                $this->ajaxReturn($rs);

            }

    

            $orderid=$uid.'D'.date('YmdHis').rand(100,999);

    

            $orderinfo=array(

                "uid"=>$uid,

                "touid"=>$uid,

                "money"=>$money,

                "coin"=>$coin,

                "orderno"=>$orderid,

                "coin_give"=>$change_info['give'],

                "type"=>4,

                "status"=>0,

                "addtime"=>time()

            );

            M("users_charge")->create($orderinfo);

            if(M("users_charge")->add($orderinfo)) {

    

                //加入商户参数

    //            $params['txnAmt'] = $money*100;

    //            $params['orderId'] = $orderid;

    //

    //            \com\unionpay\acp\sdk\AcpService::sign ( $params );

    //            $uri = \com\unionpay\acp\sdk\SDKConfig::getSDKConfig()->frontTransUrl;

    //            $html_form = \com\unionpay\acp\sdk\AcpService::createAutoFormHtml( $params, $uri );

    //            echo $html_form;

    //            exit;

                $rs['code']=0;

                $rs['msg']='订单创建成功';

                $rs['orderId']=$orderid;

                $this->ajaxReturn($rs);

            }else{

    

                $rs['code']=1008;

                $rs['msg']='订单创建失败!:orderinfo untrue!';

                $this->ajaxReturn($rs);

            }

    

        }

    

    

    

        /* 异步处理 */

        public function notify_yl()

        {

    

            Vendor('Yunpay.acp_service');

            $logger = \com\unionpay\acp\sdk\LogUtil::getLogger();

            $logger->LogInfo("receive back notify: " . \com\unionpay\acp\sdk\createLinkString ( $_POST, false, true ));

            if (isset ( $_POST ['signature'] )) {

                echo \com\unionpay\acp\sdk\AcpService::validate ( $_POST ) ? '验签成功' : '验签失败';

    

                $respCode = I('post.respCode');

                $orderId = I('post.orderId');         // 商户订单号

                $total_amount = I('post.settleAmt'); //订单金额

                $trade_no = I('post.queryId');         // queryId 银联唯一标识一笔交易

    

                //判断respCode=00、A6后,对涉及资金类的交易,请再发起查询接口查询,确定交易成功后更新数据库。

                if( $respCode=='00' ){

                    $this->unionpay($orderId,$total_amount,$trade_no);

                }else{

                    $res = $this->confirmpay($orderId,'1');

                    if( $res == 'Successful' ){

                        $this->unionpay($orderId,$total_amount,$trade_no);

                    } else {

                        echo '交易失败';

                    }

                }

    

            } else {

                echo '签名为空';

            }

    

        }

    

    

    

        /* 订单处理 */

        public function unionpay($orderId,$total_amount,$trade_no)

        {

            $per = M("users_charge")

                ->where(['orderno'=>$orderId])

                ->order("id desc")

                ->find(); //查找该订单

            if( $per['status']=='1' ){

                echo '已充值';

                return;

            }

    

            $data = array(

                'ambient'=>0,  //支付环境  0沙盒,1生产

                'trade_no'=>$trade_no,                  //银联唯一标识

                'status'=>'1'                              //交易状态

            );

            M("users_charge")

                ->where(['orderno'=>$orderId])

                ->order("id desc")

                ->save($data); // 更新订单

    

            /* 更新会员虚拟币 */

            $coin=$per['coin']+$per['coin_give'];

            M("users")

                ->where(['id'=>$per['touid']])

                ->setInc("coin",$coin);

    

            /*  ...后续继续补充业务需求 */

            echo 'Success';

            return;

        }

    

    

    

        /* 重新验证订单是否交易成功 */

        public function confirmpay($orderId,$L)

        {

            header ( 'Content-type:text/html;charset=utf-8' );

            Vendor('Yunpay.acp_service');

            $params = array(

                //以下信息非特殊情况不需要改动

                'version' => \com\unionpay\acp\sdk\SDKConfig::getSDKConfig()->version,          //版本号

                'encoding' => 'utf-8',          //编码方式

                'signMethod' => \com\unionpay\acp\sdk\SDKConfig::getSDKConfig()->signMethod,          //签名方法

                'txnType' => '00',              //交易类型

                'txnSubType' => '00',          //交易子类

                'bizType' => '000000',          //业务类型

                'accessType' => '0',          //接入类型

                'channelType' => '07',          //渠道类型

                'merId' => \com\unionpay\acp\sdk\SDKConfig::getSDKConfig()->merid,                   //商户号

            );

    

    

            $time = M("users_charge")->where('orderno='.$orderId)->order("id desc")->find()['addtime'];

            $params['orderId'] = $orderId;               //交易的订单号

            $params['txnTime'] = date('YmdHis',$time); //订单发送时间

    

            \com\unionpay\acp\sdk\AcpService::sign ( $params ); // 签名

            $url = \com\unionpay\acp\sdk\SDKConfig::getSDKConfig()->singleQueryUrl;

    

            $result_arr = \com\unionpay\acp\sdk\AcpService::post ( $params, $url);

            if(count($result_arr)<=0) { //没收到200应答的情况

                return 'No200';

            }

            if (!\com\unionpay\acp\sdk\AcpService::validate ($result_arr) ){

                return "应答报文验签失败";

            }

            if ($result_arr["respCode"] == "00"){

                if ($result_arr["origRespCode"] == "00"){

                    //交易成功

                    //TODO

                    return "Successful";

                } else if ($result_arr["origRespCode"] == "03"

                    || $result_arr["origRespCode"] == "04"

                    || $result_arr["origRespCode"] == "05"){

                    //后续需发起交易状态查询交易确定交易状态

                    //TODO

                    return "交易处理中,请稍微查询";

                } else {

                    //其他应答码做以失败处理

                    //TODO

                    return "交易失败:" . $result_arr["origRespMsg"];

                }

            } else if ($result_arr["respCode"] == "03"

                || $result_arr["respCode"] == "04"

                || $result_arr["respCode"] == "05" ){

                //后续需发起交易状态查询交易确定交易状态

                //TODO

                return "处理超时,请稍微查询";

            } else {

                //其他应答码做以失败处理

                //TODO

                return "失败:" . $result_arr["respMsg"];

            }

    

        }

    

   

    }




补充:

  这里第一个方法xxx 中的respCode等于00 就是支付成功 ,如果没有需要根据你生成的订单号在次查询在结果。这里客服说这种失败不好模拟,就不说了,但是这操作方法还是


  建议写下,以防万一 。

  最后说明下几个参数 queryId  银联唯一标识,需要保存, 还有银联支付是按 '分' 做单位的 所以支付跳转前  假如是1元,你得乘以100,它才可以识别为1元,要不然就是0.01元


  然后异步到你的时候,如果你是元的单位在除于100,如果是分就不用了。

  搞定收工!


鼎云博客
  • 最新评论
  • 总共0条评论