PHP对接支付宝APP支付

PHP对接支付宝APP支付

       这两天接了一个需求,就是对接支付宝的APP支付,看了下支付宝文档,结合之前写的支付宝sign篇,最终决定不用支付宝SDK,在这里跟大家分享下代码,我这里是用thinkphp开发。

       一、支付宝类

       我们先创建一个支付宝的类,命名为AliPay,代码如下

<?php
/**
 * Created by PhpStorm.
 * User: zhangw
 * Date: 2024-03-01
 * Time: 17:22
 */

namespace app\service;

/**
 * 支付宝付款
 * Class AliPay
 * @package app\service
 */
class AliPay
{
    /**
     * 获取支付宝APP支付参数
     * @param string $outOrderSn
     * @param int $totalAmount
     * @param string $notifyUrl 
     * @return string
     */
    function aliPayOrder($outOrderSn = "", $totalAmount = 0, $notifyUrl = "")
    {
        #获取配置参数
        $appId = Config('appConfig.ali_pay_app_id');
        $rsaPrivateKey = Config('appConfig.ali_pay_private_key');
        #获取时间
        $outTime = time() + 2 *60;
        #非公共参数
        $requestData = [
            'total_amount' => $totalAmount,                          // 订单总金额(元)
            'product_code' => 'QUICK_MSECURITY_PAY',                 // 销售产品码
            'subject' => "商品标题",                                 // 商品标题
            'out_trade_no' => $outOrderSn,                           // 订单号
            'time_expire'=> date("Y-m-d H:i:s",$outTime),            // 超时时间
        ];
        #公共参数
        $commonData = array(
            'app_id' => $appId,
            'method' => 'alipay.trade.app.pay',
            'charset' => 'UTF-8',
            'sign_type' => 'RSA2',
            'timestamp' => date('Y-m-d H:i:s', time()),
            'version' => '1.0',
            'notify_url' => $notifyUrl,
            'biz_content' => json_encode($requestData)
        );
        #拼接成字符串
        $signString = self::getSignContent($commonData);
        #待请求字符串加密获取sign
        $sign = self::alonersaSign($signString, $rsaPrivateKey, "RSA2");
        #将sign带入数组
        $commonData["sign"] = $sign;
        #请求链接编码及转换
        $url = self::getSignContentUrlencode($commonData);
        #返回支付链接给前端
        return $url;
    }


    /////////////////////////////////////发起支付公共方法/////////////////////////////////////

    /**
     * 链接拼接
     * @param $params
     * @return string
     */
    function getSignContentUrlEncode($params)
    {
        ksort($params);
        $stringToBeSigned = "";
        $i = 0;
        foreach ($params as $k => $v) {
            if (false === self::checkEmpty($v) && "@" != substr($v, 0, 1)) {

                // 转换成目标字符集
                $v = self::charaCet($v, "UTF-8");

                if ($i == 0) {
                    $stringToBeSigned .= "$k" . "=" . urlencode($v);
                } else {
                    $stringToBeSigned .= "&" . "$k" . "=" . urlencode($v);
                }
                $i++;
            }
        }
        unset ($k, $v);
        return $stringToBeSigned;
    }

    /**
     * 请求参数加密获取sign
     * @param $data
     * @param $privateKey
     * @param string $signType
     * @param bool $keyFromFile
     * @return string
     */
    function aloneRsaSign($data, $privateKey, $signType = "RSA", $keyFromFile = false)
    {
        if (!$keyFromFile) {
            $priKey = $privateKey;
            $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
                wordwrap($priKey, 64, "\n", true) .
                "\n-----END RSA PRIVATE KEY-----";
        } else {
            $priKey = file_get_contents($privateKey);
            $res = openssl_get_privatekey($priKey);
        }

        ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');

        if ("RSA2" == $signType) {
            openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
        } else {
            openssl_sign($data, $sign, $res);
        }

        if ($keyFromFile) {
            openssl_free_key($res);
        }
        $sign = base64_encode($sign);
        return $sign;
    }

    /**
     * 数组转成字符串
     * @param $params
     * @return string
     */
    function getSignContent($params)
    {
        ksort($params);

        $stringToBeSigned = "";
        $i = 0;
        foreach ($params as $k => $v) {
            if (false === self::checkEmpty($v) && "@" != substr($v, 0, 1)) {

                // 转换成目标字符集
                $v = self::charaCet($v, "UTF-8");

                if ($i == 0) {
                    $stringToBeSigned .= "$k" . "=" . "$v";
                } else {
                    $stringToBeSigned .= "&" . "$k" . "=" . "$v";
                }
                $i++;
            }
        }

        unset ($k, $v);
        return $stringToBeSigned;
    }

    /**
     * 判断参数值是否为空
     * @param $value
     * @return bool
     */
    function checkEmpty($value)
    {
        if (!isset($value))
            return true;
        if ($value === null)
            return true;
        if (trim($value) === "")
            return true;

        return false;
    }

    /**
     * 转换成目标字符集
     * @param $data
     * @param $targetCharset
     * @return string
     */
    function charaCet($data, $targetCharset)
    {

        if (!empty($data)) {
            $fileType = "UTF-8";
            if (strcasecmp($fileType, $targetCharset) != 0) {
                $data = mb_convert_encoding($data, $targetCharset, $fileType);
            }
        }


        return $data;
    }

    /**
     * 支付宝回调验签
     * @param $params
     * @param $ali_pay_public_key
     * @param string $sign_type
     * @return bool
     */
    function verifySign($params,$ali_pay_public_key,$sign_type='RSA2')
    {
        $ori_sign=$params['sign'];
        unset($params['sign']);
        unset($params['sign_type']);
        ksort($params);
        $data='';
        foreach($params as $k => $v){
            $data.=$k.'='.$v.'&';
        }
        $data=substr($data,0,-1);
        $public_content="-----BEGIN PUBLIC KEY-----\n" . wordwrap($ali_pay_public_key, 64, "\n", true) . "\n-----END PUBLIC KEY-----";
        $public_key=openssl_get_publickey($public_content);
        if($public_key){
            if($sign_type=='RSA2') {
                $result = (bool)openssl_verify($data, base64_decode($ori_sign), $public_key, OPENSSL_ALGO_SHA256);
            } else {
                $result = (bool)openssl_verify($data, base64_decode($ori_sign), $public_key);
            }
            openssl_free_key($public_key);
            return $result;
        }else{
            return false;
        }
    }

}

       二、新增配置

       我这里是放在thinkphp的config下的appConfig.php文件下,分别是

'ali_pay_app_id' => '支付宝appId',
'ali_pay_private_key' => '支付宝私钥'
'ali_pay_public_key'=>'支付宝平台应用公钥【非自己的的支付宝公钥】'

       三、获取前端需要支付参数

       我们直接在我们的接口直接调用该函数,获取前端所需的支付参数

#初始化支付宝类
$aliPay = new AliPay();
#初始化参数
$order_sn = time();
$total_money = 0.01;
$notify_url = "";
#获取支付参数
$aliPayUrl = $aliPay->aliPayOrder($order_sn,$total_money,$notify_url);

这样我们就可以获得前端所需支付参数。

       四、回调处理

       我们同样新增一个接口来处理回调,代码如下

#获取用户参数
$signData = request()->post();
#记录请求参数
Log::write("支付宝回调",json_encode($signData));
#检查回调参数是否正确
if (!isset($signData['sign']) &&  !isset($signData['trade_status'])){
    echo "false";
    die;
}
#获取配置
$aliPayPublicKey = Config('appConfig.ali_pay_public_key');
#初始化支付宝
$aliPay = new AliPay();
#格式化公钥【支付宝平台公钥】
$verifyRes  = $aliPay->verifySign($signData,$aliPayPublicKey);
#验签
if (!$verifyRes){
   echo "false";
   die;
};
#判断是否是支付成功
if($signData['trade_status']!="TRADE_SUCCESS"){
    echo "false";
    die;
}
#提取参数
$buyerId = isset($signData["buyer_id"])?$signData["buyer_id"]:"";
$tradeNo = isset($signData["trade_no"])?$signData["trade_no"]:NULL;
$outTradeNo =  isset($signData["out_trade_no"])?$signData["out_trade_no"]:"";
$gmtPayment = isset($signData["gmt_payment"])?$signData["gmt_payment"]:time();

以上是部分片段,这部分代码基本可以直接复制,下面的就是各自业务处理逻辑,我这里就不放上去了,仅供大家参考

      以上就是thinkphp不通过支付宝SDK,进行支付宝APP支付以及回调处理。  

0条评论

发表评论