1. 程式人生 > >Yii2整合支付寶

Yii2整合支付寶

背景知識:

  1. 本文主要以電腦網站支付為主講解支付寶的應用,官方文件
  2. 事先準備好官方的PHP例子,下載地址:傳送門

1.首先在vendor下新建一個alipay目錄,將下載好的sdk拖入該目錄中:

2.在配置檔案中配置支付相關資訊:

<?php
return [
    'alipay'=>[
        //應用的ID
        'app_id'=>"",

        //商戶私鑰
        'merchant_private_key' => "",

        //非同步通知地址(注意地址不能有get引數)
        //例如:http://blog.w.labyun.com.cn/notify.php
        'notify_url'=>"",

        //同步通知地址(可以有get引數)
        //例如:http://blog.w.labyun.com.cn/index.php?r=pay/return
        'return_url'=>"",

        'charset'=>'UTF-8',

        //簽名方式
        'sign_type'=>'RSA2',

        //支付寶閘道器
        'gatewayUrl' => "https://openapi.alipay.com/gateway.do",

        //支付寶公鑰,檢視地址:https://openhome.alipay.com/platform/keyManage.htm 對應APPID下的支付寶公鑰。
        'alipay_public_key' => "",
    ]
];


關於同步通知和非同步通知:由於同步通知有著不穩定性,例如使用者在支付完成之後關閉了頁面或者伺服器網路抖
動等等都會導致同步回撥的失敗,因此需要非同步回撥來保證通知結果一定傳達到。




3.筆者是在應用目錄下新建來一個services目錄,並新建了一個Pay類:

4.Pay類中的核心程式碼如下:

<?php
namespace app\services;
//引入官方demo中封裝好的類
require '../vendor/alipay/pagepay/service/AlipayTradeService.php';
require '../vendor/alipay/pagepay/buildermodel/AlipayTradePagePayContentBuilder.php';
class Pay{
    
    //發起支付
    public static function alipay(){
        //注意在使用類的時候加上"\",因為是通過require的方式引入的類(在公共空間中)
        //並且本檔案中又聲明瞭app\services名稱空間,因此需要加上\顯示錶明
        //使用公共空間中的類
        $payRequestBuilder = new \AlipayTradePagePayContentBuilder();
        $payRequestBuilder->setBody('描述資訊');
        $payRequestBuilder->setSubject('主題');
        $payRequestBuilder->setTotalAmount('金額');
        $payRequestBuilder->setOutTradeNo('訂單號');
        //載入alipay相關的配置檔案
        $config=\Yii::$app->params['alipay'];
        $aop = new \AlipayTradeService($config);
        $response = $aop->pagePay($payRequestBuilder,$config['return_url'],$config['notify_url']);
        echo $response;
        \Yii::$app->end();
    }
}

5.由於我設定瞭如下回調引數:


'notify_url'=>'http://blog.w.labyun.com.cn/notify.php',

'return_url'=>'http://blog.w.labyun.com.cn/index.php?r=pay/return',

因此當支付成功時,支付寶的同步回撥會呼叫Pay控制器下的return方法,相應的程式碼如下:


//PayController控制器中的方法

//同步回撥(注意是:GET方式)
public function actionReturn(){

    if(\Yii::$app->request->isGet){
        $get = \Yii::$app->request->get();
        Pay::handleReturn($get);
        $this->redirect(['order/my-order']);
        \Yii::$app->end();
        }

}




//services下Pay類新增handleReturn方法

public static function handleReturn($get){
    $config=\Yii::$app->params['alipay'];
    $alipaySevice = new \AlipayTradeService($config);
    try{
        //注意由於同步回撥的地址是http://blog.w.labyun.com.cn/index.php?r=pay/return
        //因此$get陣列中會有'r'=>'pay/return'這一項,但是這一項是多餘的需要刪除
        //否則校驗會一直失敗
        unset($get['r']);
        $result = $alipaySevice->check($get);
        if(!$result){
            \Yii::$app->getSession()->setFlash('Error','驗證失敗');
            return false;
        }

        //這裡可以做自己相應的業務處理 
  
        return true;
        }catch(\Exception $e){
            \Yii::$app->getSession()->setFlash('Error','驗證失敗');
            return false;
        }

    }

由於支付寶的非同步通知地址不能攜帶任何引數,這也是為什麼非同步地址不像同步地址那樣設定成:http://blog.w.labyun.com.cn/index.php?r=pay/notify 而設定成 http://blog.w.labyun.com.cn/notify.php 的原因。

在web目錄下新建notify.php檔案,如下:

編寫如下程式碼:

<?php


$url="http://blog.w.labyun.com.cn/index.php?r=pay/notify";
//獲得支付寶非同步傳遞的資料(注意是post請求,與同步不同)
$post = $_POST;
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);

//將支付寶非同步回撥的資料傳遞給指定的url解析
curl_setopt($ch,CURLOPT_POST,1);
curl_setopt($ch,CURLOPT_POSTFIELDS,$post);
$out=curl_exec($ch);
curl_close($ch);
echo $out;

從上面我們可以看出notify.php相當於是一箇中間件做了一次轉發,接下來是非同步通知的核心程式碼:


//PayController控制器中的方法

//需要關閉yii2預設post方式提交的csrf驗證
public $enableCsrfValidation=false;

//只能返回success或者fail,這是支付寶規定的
//success表示成功響應了非同步通知,之後支付寶就不會再發送非同步通知了
//fail表示未成功響應,支付寶會陸續傳送非同步通知,具體週期可以百度
public function actionNotify(){
    if(\Yii::$app->request->isPost){
        $post=\Yii::$app->request->post();
        if(Pay::handleNotify($post)){
            echo 'success';exit; 
        }else{
            echo 'fail';exit;
        }
    }
}



//services下的Pay類新增如下方法

public static function handleNotify($post){
        $config=\Yii::$app->params['alipay'];
        $alipaySevice = new \AlipayTradeService($config);
        //校驗
        $result = $alipaySevice->check($post);
        if(!$result){
            return false;
        }
        //訂單號
        $out_trade_no = $post['out_trade_no'];
        //交易狀態
        $status = $post['trade_status'];
        //支付寶交易號
        $trade_no = $post['trade_no'];
        //支付金額
        $amount = $post['total_amount'];
        if('TRADE_SUCCESS'===$status||'TRADE_FINISHED'===$status){
            try{

                //自己的業務處理,例如檢查訂單的價格和付款的錢是否一致

            }catch(\Exception $e){
                return false;
            }
        }
        return false;
    }

以上就是Yii2整合支付寶的過程。