Yii 扩展支付宝快速支付接口

jerry Yii 2016年01月22日 收藏

使用的是官方提供方的php接口:create_direct_pay_by_user-PHP-UTF-8

将lib下的四个文件复制至:yii项目\protected\vendor\下

四个文件分别是:alipay_core.function.php、alipay_md5.function.php、alipay_notify.class.php、alipay_submit.class.php

将CA证书文件:cacert.pem在yii项目\目录和 yii项目\protected\controllers下各复制一份

在main.php的项目配置文件中加入支付宝的相关配置参数:

'params'=>array(
       'alipay_config'=>array(
           'partner' =>'',//必填
           'key'=>'',//必填
           'sign_type'=>strtoupper('MD5'),//必填
           'input_charset'=> strtolower('utf-8'),//必填
           'cacert'=>getcwd().'/cacert.pem',//必填且CA证书文件能有效访问,否则会有sign错误
           'transport'=>'http',//如果你的服务器支持https请填写https
       ),
       'alipay'   =>array(
           'seller_email'=>'',//必填
            'notify_url'=>'http://res.locoy.com/index.php?r=pay/notifyUrl',
           'return_url'=>'http://res.locoy.com/index.php?r=pay/returnUrl',//必填
           'successpage'=>'account/list',//处理成功后的页面
           'errorpage'=>'shopcart/list',//处理失败的页面
       ),
),

然后写一个支付的控制器:

<?php
 class PayController extends Controller {
     public function ActionAlipay($id) {
         $model = Shopcart::model()->findByPk($id);
       header("Content-type:text/html;charset=utf-8");
         Yii::import('application.vendor.*');
         require_once('alipay_core.function.php');
         require_once('alipay_md5.function.php');
         require_once('alipay_notify.class.php');
         require_once('alipay_submit.class.php');
         $alipay_config = Yii::app()->params['alipay_config'];
         $payment_type = "1";
         $notify_url = Yii::app()->params['alipay']['notify_url'];
         //需http://格式的完整路径,不能加?id=123这类自定义参数
         //页面跳转同步通知页面路径
         $return_url = Yii::app()->params['alipay']['return_url'];
         //需http://格式的完整路径,不能加?id=123这类自定义参数,不能写成http://localhost/
         //卖家支付宝帐户
         $seller_email = Yii::app()->params['alipay']['seller_email'];
         //必填
         //商户订单号
         $out_trade_no = $model->trade_id;
         //商户网站订单系统中唯一订单号,必填
         //订单名称
         $subject = $model->trade_name;
         //必填
         //付款金额
         $total_fee = $model->trade_money;
         //必填
         //订单描述
         $body = $model->trade_name.':'.$model->trade_money;
         //商品展示地址
         $show_url = '';
         //需以http://开头的完整路径,例如:http://www.xxx.com/myorder.html
         //防钓鱼时间戳
         $anti_phishing_key = "";
         //若要使用请调用类文件submit中的query_timestamp函数
         //客户端的IP地址
         $exter_invoke_ip = "";
         //非局域网的外网IP地址,如:221.0.0.1
         /************************************************************/
//构造要请求的参数数组,无需改动
         $parameter = array(
             "service" => "create_direct_pay_by_user",
             "partner" => trim($alipay_config['partner']),
             "payment_type"    => $payment_type,
             "notify_url"  => $notify_url,
             "return_url"  => $return_url,
             "seller_email"    => $seller_email,
             "out_trade_no"    => $out_trade_no,
             "subject" => $subject,
             "total_fee"   => $total_fee,
             "body"    => $body,
             "show_url"    => $show_url,
             "anti_phishing_key"   => $anti_phishing_key,
             "exter_invoke_ip" => $exter_invoke_ip,
             "_input_charset"  => trim(strtolower($alipay_config['input_charset']))
         );
 //        print_r($parameter);die;
//建立请求
         $alipaySubmit = new AlipaySubmit($alipay_config);
         $html_text = $alipaySubmit->buildRequestForm($parameter,"get", "确认");
         echo $html_text;
     }
     public function actionNotifyUrl() {
       header("Content-type:text/html;charset=utf-8");
         Yii::import('application.vendor.*');
         require_once('alipay_core.function.php');
         require_once('alipay_md5.function.php');
         require_once('alipay_notify.class.php');
         require_once('alipay_submit.class.php');
         $alipay_config = Yii::app()->params['alipay_config'];
         //计算得出通知验证结果
         $alipayNotify = new AlipayNotify($alipay_config);
         $verify_result = $alipayNotify->verifyNotify();
         if ($verify_result) {//验证成功
             /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
             //请在这里加上商户的业务逻辑程序代
             //——请根据您的业务逻辑来编写程序(以下代码仅作参考)——
             //获取支付宝的通知返回参数,可参考技术文档中服务器异步通知参数列表
             $out_trade_no   = $_POST['out_trade_no'];      //商户订单号
             $trade_no       = $_POST['trade_no'];          //支付宝交易号
             $trade_status   = $_POST['trade_status'];      //交易状态
             $total_fee      = $_POST['total_fee'];         //交易金额
             $notify_id      = $_POST['notify_id'];         //通知校验ID。
             $notify_time    = $_POST['notify_time'];       //通知的发送时间。格式为yyyy-MM-dd HH:mm:ss。
             $buyer_email    = $_POST['buyer_email'];       //买家支付宝帐号;
             $parameter = array(
                 "out_trade_no"     => $out_trade_no, //商户订单编号;
                 "trade_no"     => $trade_no,     //支付宝交易号;
                 "total_fee"     => $total_fee,    //交易金额;
                 "trade_status"     => $trade_status, //交易状态
                 "notify_id"     => $notify_id,    //通知校验ID。
                 "notify_time"   => $notify_time,  //通知的发送时间。
                 "buyer_email"   => $buyer_email,  //买家支付宝帐号;
             );
             if ($_POST['trade_status'] == 'TRADE_FINISHED') {
                 //判断该笔订单是否在商户网站中已经做过处理
                 //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
                 //如果有做过处理,不执行商户的业务程序
                 if(!checkorderstatus($out_trade_no)){
                     orderhandle($parameter);  //进行订单处理,并传送从支付宝返回的参数;
                 }
                 //注意:
                 //该种交易状态只在两种情况下出现
                 //1、开通了普通即时到账,买家付款成功后。
                 //2、开通了高级即时到账,从该笔交易成功时间算起,过了签约时的可退款时限(如:三个月以内可退款、一年以内可退款等)后。
                 //调试用,写文本函数记录程序运行情况是否正常
                // logResult("这里写入想要调试的代码变量值,或其他运行的结果记录");
             } else if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
                 //判断该笔订单是否在商户网站中已经做过处理
                 //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
                 //如果有做过处理,不执行商户的业务程序
                 if(!checkorderstatus($out_trade_no)){
                     orderhandle($parameter);  //进行订单处理,并传送从支付宝返回的参数;
                 }
                 //注意:
                 //该种交易状态只在一种情况下出现——开通了高级即时到账,买家付款成功后。
                 //调试用,写文本函数记录程序运行情况是否正常
                 //logResult("这里写入想要调试的代码变量值,或其他运行的结果记录");
             }
             //——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
             echo "success";        //请不要修改或删除
             /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
         } else {
             //验证失败
             echo "fail";
         }
     }
     public function actionReturnUrl(){
       header("Content-type:text/html;charset=utf-8");
         Yii::import('application.vendor.*');
         require_once('alipay_core.function.php');
         require_once('alipay_md5.function.php');
         require_once('alipay_notify.class.php');
         require_once('alipay_submit.class.php');
         $alipay_config = Yii::app()->params['alipay_config'];
         $alipayNotify = new AlipayNotify($alipay_config);//计算得出通知验证结果
         $verify_result = $alipayNotify->verifyReturn();
         if($verify_result) {
             //验证成功
             //获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表
             $out_trade_no   = $_GET['out_trade_no'];      //商户订单号
             $trade_no       = $_GET['trade_no'];          //支付宝交易号
             $trade_status   = $_GET['trade_status'];      //交易状态
             $total_fee      = $_GET['total_fee'];         //交易金额
             $notify_id      = $_GET['notify_id'];         //通知校验ID。
             $notify_time    = $_GET['notify_time'];       //通知的发送时间。
             $buyer_email    = $_GET['buyer_email'];       //买家支付宝帐号;
             $parameter = array(
                 "out_trade_no"     => $out_trade_no,      //商户订单编号;
                 "trade_no"     => $trade_no,          //支付宝交易号;
                 "total_fee"      => $total_fee,         //交易金额;
                 "trade_status"     => $trade_status,      //交易状态
                 "notify_id"      => $notify_id,         //通知校验ID。
                 "notify_time"    => $notify_time,       //通知的发送时间。
                 "buyer_email"    => $buyer_email,       //买家支付宝帐号
             );
             if($_GET['trade_status'] == 'TRADE_FINISHED' || $_GET['trade_status'] == 'TRADE_SUCCESS') {
                 if(!checkorderstatus($out_trade_no)){
                     orderhandle($parameter);  //进行订单处理,并传送从支付宝返回的参数;
                 }
                 $this->redirect(Yii::app()->createUrl(Yii::app()->params['alipay']['successpage']));//跳转到配置项中配置的支付成功页面;
             }else {
                 echo "trade_status=".$_GET['trade_status'];
                 $this->redirect(Yii::app()->createUrl(Yii::app()->params['alipay']['errorpage']));//跳转到配置项中配置的支付失败页面;
             }
         }else {
             //验证失败
             //如要调试,请看alipay_notify.php页面的verifyReturn函数
             echo "验证失败!";
         }
     }
 }

一下是两个上面控制器中用到的两个处理方法:我是写在了一个可以定义全局方法的functions.php文件中

你可以把这两个方法写在购物车或者其他的模型中进行调用

//在线交易订单支付处理函数
//函数功能:根据支付接口传回的数据判断该订单是否已经支付成功;
//返回值:如果订单已经成功支付,返回true,否则返回false;
function checkorderstatus($ordid){
    $criteria = new CDbCriteria;
    $criteria->addCondition('trade_id = :ordid');
    $criteria->params[':ordid'] = $ordid;
    $criteria->select = 'status';
    $ordstatus = Shopcart::model()->find($criteria);
    if($ordstatus->status == 1){
        return true;
    }else{
        return false;
    }
}
//处理订单函数
//更新订单状态,写入订单支付后返回的数据
function orderhandle($parameter){
    $ordid = $parameter['out_trade_no'];
    $buyer = $parameter['buyer_email'];
    $status = 1;
    $criteria = new CDbCriteria;
    $criteria->addCondition('trade_id = :ordid');
    $criteria->params[':ordid'] = $ordid;
    $model = Shopcart::model()->find($criteria);
    $model->trade_account = $buyer;
    $model->status = $status;
    if($model->update()){
        $income = new Income();
        $income->uid = $model->uid;
        $income->recharge_money = $model->trade_money;
        $income->time = time();
        $income->detail = "你在".$model->trade_paytime.
            " ,充值了".$model->trade_money." 个积分";
        if($income->save()) {
            $user = User::model()->findByPk(Yii::app()->user->id);
            $have = $user->credit;
            $add = $model->trade_money;
            $user->credit = $have + $add;
            if($user->update()){
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    } else {
        return false;
    }

由于yii初始路由方式为index.php?r=XX/XX 所以后面也算是带参的url,在支付成功后会出现验证失败的情况,解决办法是更改alipy_core.function.php中的paraFilter()方法

function paraFilter($para) {
   $para_filter = array();
   while (list ($key, $val) = each ($para)) {
      if($key == "sign" || $key == "sign_type" || $val == "" || $key == 'r')continue;
      else   $para_filter[$key] = $para[$key];
   }
   return $para_filter;
}


下载地址