Yii2整合支付寶
阿新 • • 發佈:2018-11-11
背景知識:
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整合支付寶的過程。