二维码支付

未匹配的标注

1 组装请求参数

文档地址:opendocs.alipay.com/apis/api_1/ali...
由支付文档可知必填的参数有哪些,以下是组装好的请求参数:

public function getPayData ()
{
    // 公共参数
    $commonData = [
        'app_id'     => "支付宝分配给开发者的应用ID",      // 应用appid
        'method'     => "alipay.trade.precreate",        // 接口名称
        'charset'    => 'utf-8',                         // 请求使用的编码格式
        'sign_type'  => 'RSA2',                          // 签名算法类型
        'version'    => '1.0',                           // 调用的接口版本
        'notify_url' => "http://your.domain.com/notify", // 支付回调地址
        'timestamp'  => date("Y-m-d H:i:s", time()),     // 发送请求的时间
    ];

    // 非公共参数
    $requestData = [
        'total_amount' => round((100 / 100), 2),      // 订单总金额(元)
        'product_code' => 'FACE_TO_FACE_PAYMENT',     // 销售产品码
        'subject'      => "商品标题",                  // 商品标题
        'out_trade_no' => time(),                     // 订单号
    ];
    $requestData['biz_content'] = json_encode($requestData); // 非公共参数

    // 拼接成字符串
    $postStr = $this->concatenationArray(array_merge($commonData, $requestData));

    // 格式化商户私钥
    $privateKey = $this->formatPrivateKeyInRsa("这里填商户私钥");

    // 签名
    $postData['sign'] = base64_encode($this->signInRsa($postStr, $privateKey));

    return $postData;
}
  • concatenationArray():将数组中拼接成字符串,具体代码见 1.1。
  • formatPrivateKeyInRsa():格式化商户私钥,具体代码见 1.2。
  • signInRsa():对请求参数进行签名,具体代码见 1.3。

1.1 拼接成字符串

public function concatenationArray ($postData)
{
    ksort($postData);
    $str = urldecode(http_build_query($postData)); // 拼接成字符串
    return mb_convert_encoding($str, 'UTF-8');     // 转换成目标字符集
}

1.2 格式化商户私钥

/**
 * 格式化私钥
 *
 * PKCS#1 RSA专用密钥格式:
 * -----BEGIN RSA PRIVATE KEY-----
 * BASE64 ENCODED DATA
 * -----END RSA PRIVATE KEY-----
 */
private function formatPrivateKeyInRsa ($privateKey)
{
    $formatedStr = $privateKey;

    //  字符串没有以标准格式头开始时,认为是非格式化的
    if (false === strpos($formatedStr, '-----BEGIN RSA PRIVATE KEY-----')) {
        $formatedStr = "-----BEGIN RSA PRIVATE KEY-----\n";
        $formatedStr .= wordwrap($privateKey, 64, "\n", true);
        $formatedStr .= "\n-----END RSA PRIVATE KEY-----";
    }
    $key = openssl_get_privatekey($formatedStr);
    return $key;
}

1.3 签名

    /**
     * RSA签名-使用PKCS#1
     *
     * @param string $postStr    要被签名的字符串
     * @param string $privateKey 私钥
     * @return false
     */
    public function signInRsa ($postStr, $privateKey)
    {
        $signature = false;
        openssl_sign($postStr, $signature, $privateKey, OPENSSL_ALGO_SHA256);
        return $signature;
    }

2 生成二维码链接

public function postCurlPrecreate ($postData)
{
    $url    = 'https://openapi.alipay.com/gateway.do?' . http_build_query(mb_convert_encoding($postData, 'UTF-8'));
    $header = ['content-type' => 'application/x-www-form-urlencoded;charset=' . $postData['charset']];

    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HEADER, 0);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($curl, CURLOPT_POST, 1);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
    $output = json_decode(curl_exec($curl), true);

    // 键为:alipay_trade_precreate_response
    $key = str_replace('.', '_', $postData['method']) . '_response';
    if (!isset($output[$key])) return false;

    // 返回生成的二维码链接
    return $output[$key]['code'] == '10000'
        ? $output[$key]['qr_code']
        : $output[$key]['sub_msg'];
}

如果请求成功,返回如下数据:

{
"alipay_trade_precreate_response":{
        "code":"10000",
        "msg":"Success",
        "out_trade_no":"1622970750",
        "qr_code":"https://qr.alipay.com/bax07289bfzueiyhdagp5014"
},       "sign":"OVmnScabnyBadtD3LWl7MjUSXwly+PvWntLgEKR1iRyIwd5E2aREhuFRBcF3OBuFSygNvllDdBk+q3p96HxXMju0NH2X0OOE2bqTeph49p7hqG1XKNlA1+svxJuSrFYl9N39O5a21wC5SWQDgV7v/RT7tvIjakBldiWl3kKZnc4zpBEqULSBH5PZyCM1VxvtXNUVSP8Om2WcyujTozWCpz8rG9tr+ClTtx1/Thx1h+pwWJzZGUILoenppNXbo6FpNQ7h96pZSvdLmn4qXqlkFY77HVl04Vl2Lyt2RWYgepeOHLAVLybE3fqBY+pQTts4eaUQ9oq49E3JhFVdp8NtHg=="
}

3 二维码链接转图片

测试网站:c.runoob.com/front-end/3454

4 支付回调

文档地址:opendocs.alipay.com/open/194/10329...
用户支付完成后,支付宝会通知商户,商户需要在接受数据、处理数据后,返回应答。
回调地址是在步骤1中的notify_url字段填写的。

public function notify()
{
    $signData = request()->post();

    // 检查回调参数是否正确
    if (!isset($signData['sign']) && $signData['trade_status'] !== "TRADE_FINISHED") 
        return "false";

    // 获取回调传来的签名
    $notifySign = base64_decode($signData['sign']);
    unset($signData['sign'], $signData['sign_type']); // 不参与验签的字段

    // 转换成目标字符集
    $str = urldecode(http_build_query($signData));
    $toBeVerified = mb_convert_encoding($str, 'UTF-8');

    // 格式化公钥
    $formatPK  = $this->formatPublicKey("这里填支付宝平台公钥");

    // 验签
    $verify = openssl_verify($toBeVerified, $notifySign, $formatPK, OPENSSL_ALGO_SHA256);
    if (!$verifyRes) return "false";

    // TODO:按照业务更新订单支付状态等等

    return "success";
}
  • formatPublicKey():格式化公钥,具体代码见 4.1。

4.1 格式化公钥

    /**
     * 格式化公钥
     *
     * PKCS#8通用密钥格式:
     * -----BEGIN PUBLIC KEY-----
     * 64字节长度的 base64 内容
     * -----END PUBLIC KEY-----
     */
    private function formatPublicKey($publicKey)
    {
        $formatedStr = $publicKey;

        //  字符串没有以标准格式头开始时,认为是非格式化的
        if (false === strpos($formatedStr, '-----BEGIN PUBLIC KEY-----')) {
            $formatedStr = "-----BEGIN PUBLIC KEY-----\n";
            $formatedStr .= wordwrap($publicKey, 64, "\n", true);
            $formatedStr .= "\n-----END PUBLIC KEY-----";
        }
        $key = openssl_pkey_get_public($formatedStr);
        return $key;
    }

如果文章有帮到你的话,别忘了点赞收藏噢 :smile:

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 查看所有版本


暂无话题~