支付寶單筆轉賬,記錄下使用過程和一些碰到的問題,以便為同樣需求的提供一些參考.
官方的一些文件:單筆轉賬 , SDK,如何生成及配置公鑰證照(視訊),公鑰證照
上面差不多是準備的工作,配置好後把三個證照都下載下來,這裡可能有一些用錯檔案的情況
下載後的檔名稱
<?php
//基礎配置程式碼
namespace App\Services\Alipay;
class AlipayBase{
protected $aop;
private $error;
protected $appCertPath;
protected $rootCertPath;
protected $appId;
protected $rsaPrivateKey;
protected $alipayrsaPublicKey;
protected $rsaPrivateKeyPath;
protected $alipayrsaPublicKeyPath;
protected $payer_name = '支付返利';
public function __construct(){
$this->appId = config('alipay.app_id');//TODO 支付寶應用id
$this->rsaPrivateKey = file_get_contents(storage_path('cert'.DIRECTORY_SEPARATOR.'rsaPrivateKey.txt')); //TODO 使用支付寶開放平臺開發助手生成的應用私鑰
$this->appCertPath = storage_path('cert'.DIRECTORY_SEPARATOR.'appCertPublicKey.crt');//TODO 上傳證照後生成的crt檔案 證照
$this->rootCertPath = storage_path('cert'.DIRECTORY_SEPARATOR.'alipayRootCert.crt');//TODO 上傳證照後生成的crt檔案 支付寶根證照
$this->alipayrsaPublicKeyPath = storage_path('cert'.DIRECTORY_SEPARATOR.'alipayCertPublicKey_RSA2.crt');//TODO 上傳證照後生成的txt檔案 支付寶公鑰證照(不能使用支付寶開放平臺開發助手生成的應用公鑰,這樣子會導致支付回撥驗籤失敗)
require_once(__DIR__.'/../../Libs/Alipay/aop/AopCertClient.php');//SDK的路徑
//1、execute 使用
$aop = new \AopCertClient ();
$aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
$aop->apiVersion = '1.0';
$aop->signType = 'RSA2';
$aop->postCharset = 'utf-8';
$aop->format = 'json';
$aop->isCheckAlipayPublicCert = true;//是否校驗自動下載的支付寶公鑰證照,如果開啟校驗要保證支付寶根證照在有效期內
$aop->appId = $this->appId;
$aop->rsaPrivateKey = $this->rsaPrivateKey;
$aop->alipayrsaPublicKey = $aop->getPublicKey($this->alipayrsaPublicKeyPath);//呼叫getPublicKey從支付寶公鑰證照中提取公鑰
$aop->appCertSN = $aop->getCertSN($this->appCertPath);//呼叫getCertSN獲取證照序列號
$aop->alipayRootCertSN = $aop->getRootCertSN($this->rootCertPath);//呼叫getRootCertSN獲取支付寶根證照序列號
$this->aop = $aop;
}
/**
* 獲取錯誤資訊
* @return mixed
*/
public function getError()
{
return $this->error;
}
/**
* 設定錯誤資訊
* @param mixed $error
*/
public function setError($error = '支付寶服務異常,請重試')
{
$this->error = $error;
return false;
}
}
//轉賬類
<?php
namespace App\Services\Alipay;
use App\Models\Basic\AlipayRecord;
/**
* 轉賬類
* Class Trans
* @package app\models\alipay
*/
class Trans extends AlipayBase {
/**
* 轉賬給支付寶
* @param $data
* @param string $order_title
* @return bool|\SimpleXMLElement
*/
public function transfer($uid,$order_number,$pay_no,$pay_name,$amount,$inviteFlowPayIds,$memo=''){
//判斷是否是本地壞境
$isLocal = app()->environment('local');
if($isLocal){
return ['msg' => '本地壞境不轉賬'];
}
try {
require_once(__DIR__.'/../../Libs/Alipay/aop/request/AlipayFundTransUniTransferRequest.php');
$request = new \AlipayFundTransUniTransferRequest ();
$param = [
'biz_scene' => 'DIRECT_TRANSFER',//業務場景,單筆無密轉賬固定為DIRECT_TRANSFER
'product_code' => 'TRANS_ACCOUNT_NO_PWD',//銷售產品碼,單筆無密轉賬固定為TRANS_ACCOUNT_NO_PWD
'order_title' => $memo,//TODO 轉賬備註
'out_biz_no' => $order_number,//TODO 訂單號
'trans_amount' => $amount,//TODO 金額
'payee_info' => [
'identity_type' => 'ALIPAY_LOGON_ID',
'identity' => $pay_no,//TODO 收款方賬號
'name' => $pay_name,//TODO 姓名
],
'business_params'=>[
'payer_show_name'=>$this->payer_name //付款方賬戶
]
];
$bizcontent = json_encode($param);
$request->setBizContent($bizcontent);
$result = $this->aop->execute($request);
$responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
$resultCode = $result->$responseNode->code;
//驗證sign
$params=[];
foreach ($result->$responseNode as $key=>$value){
$params[$key]= $value;
}
if(!empty($resultCode)&&$resultCode == 10000){
return true;
} else {
if (isset($params['sub_msg'])) {
$msg = $params['sub_msg'];
} else {
$msg = '未知錯誤,請檢視日誌';
}
return ['msg' => $msg];
}
} catch (\Exception $e) {
return $this->setError($e->getMessage());
}
}
/**
* 查詢轉賬訂單
* @param $out_biz_no
* @return bool|\SimpleXMLElement
*/
public function query($out_biz_no,$order_id=''){
try {
require_once(__DIR__.'/../../Libs/Alipay/aop/request/AlipayFundTransOrderQueryRequest.php');
$request = new \AlipayFundTransOrderQueryRequest ();
$param = [
'out_biz_no' => $out_biz_no,//TODO 訂單號
'order_id'=>$order_id,
'biz_scene' => 'DIRECT_TRANSFER',//業務場景,單筆無密轉賬固定為DIRECT_TRANSFER
'product_code' => 'TRANS_ACCOUNT_NO_PWD',//銷售產品碼,單筆無密轉賬固定為TRANS_ACCOUNT_NO_PWD
];
$bizcontent = json_encode($param);
$request->setBizContent($bizcontent);
$result = $this->aop->execute ( $request);
$responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
$resultCode = $result->$responseNode->code;
$res_arr = [];
if(!empty($resultCode)&&$resultCode == 10000){
$res_arr['code'] = '1';
$res_arr['data'] = $result->$responseNode;
} else {
$res_arr['code'] = '-1';
$res_arr['data'] = $result->$responseNode;
}
return $res_arr;
} catch (\Exception $e) {
return $this->setError($e->getMessage());
}
}
}
SDK裡面已經寫了一個例子,這裡貼出來
這裡需要注意兩個地方
使用證照模式本地必須開始SSL
如果出現SSL certificate: unable to get local issuer certificate錯誤資訊
解決辦法:到 curl.haxx.se/ca/cacert.pem 下載pem檔案,並將檔案拷貝到如下路徑(根據自己的實際情況),並在php.ini 增加
curl.cainfo =”E:/wamp64/bin/php/php7.0.10/extras/ssl/cacert.pem”
另外一個就是這個SDK 的alipaySDK中定義的Encrypt()/Decrypt()函式與Laravel中定義的Encrypt()/Decrypt()函式重名了。這裡在檔案中查詢encrypt/decrypt替換為alipayEncrypt/alipayDecrypt即可。
本作品採用《CC 協議》,轉載必須註明作者和本文連結