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
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

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