php 支付宝 SDK 单笔转账

支付宝单笔转账,记录下使用过程和一些碰到的问题,以便为同样需求的提供一些参考.

官方的一些文档:单笔转账 , SDK,如何生成及配置公钥证书(视频),公钥证书

上面差不多是准备的工作,配置好后把三个证书都下载下来,这里可能有一些用错文件的情况

php 支付宝 SDK 单笔转账

下载后的文件名称

php 支付宝 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里面已经写了一个例子,这里贴出来

php 支付宝 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”

php 支付宝 SDK 单笔转账
另外一个就是这个SDK 的alipaySDK中定义的Encrypt()/Decrypt()函数与Laravel中定义的Encrypt()/Decrypt()函数重名了。这里在文件中查找encrypt/decrypt替换为alipayEncrypt/alipayDecrypt即可。

php 支付宝 SDK 单笔转账

php 支付宝 SDK 单笔转账

本作品采用《CC 协议》,转载必须注明作者和本文链接
Make PHP Great Again
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!