PHP 实现汇聚支付对接支付宝H5(内含汇聚代付分享)


前言

最近各种支付第三方深受老板喜爱,于是乎我也开始了疯狂对接第三方的旅程。

产品还是丰富,我们使用到了 “聚合支付” 微信支付宝网银都可以+代付业务(付款给银行卡)

api文档 | 汇聚支付 - 致力于成为世界一流的科技企业


一、支付

用支付宝来实例一下,其他方式更换下参数通用

/**
 * 汇聚支付
 */
class Joinpay
{
    const MCH_NO = "商户号";       // 商户号                                          

    /**聚合支付 */

    const P0_VERSION         = "2.1";          // 聚合支付接口版本号 固定为:2.1
    const MS5_BOUND_SYMBOL   = "MD5签名密钥";   // 如果是选择的RSA加密就不用这个参数              
    const QA_TRADEMERCHANTNO = "报备商户号";    // 报备商户号 
    const PLAT_PUBLIC_KEY    = "平台公钥";      // 平台公钥    
    const MCH_PRIVATE_KEY    = "商户私钥";      // 商户私钥



     /**
     * 支付宝H5 请求忽略请求头
     * @param   orderNo     订单号
     * @param   payAmount   付款金额
     * @param   orderName   商品名称
     * @return \think\Response
     */
    public function onPayMentByAlipayH5()
    {

        $url       = "https://www.joinpay.com/trade/uniPayApi.action"; // 请求地址              
        $notifyUrl = "https://..";                                     // 回调地址

        $orderNo   = "商家自定义订单号";
        $payAmount = "0.01";            // 单位:元,精确到分,保留两位小数
        $orderName = "测试商品名称";
        $payScenc  = "mall";            // 会原封不动的回调回来,可不传我用来做业务场景区分

        // 请求参数
        $params    = [
            "p0_Version"         => self::P0_VERSION,           // 版本号
            "p1_MerchantNo"      => self::MCH_NO,               // 商户号
            "p2_OrderNo"         => $orderNo,                   // 自定义订单号
            "p3_Amount"          => $payAmount,                 // 支付金额 
            "p4_Cur"             => "1",                        // 币种 默认1:人民币
            "p5_ProductName"     => $orderName,                 // 商品的名称
            "p7_Mp"              => $payScenc,                  // 公用回传参数 
            "p9_NotifyUrl"       => $notifyUrl,                 // 服务器异步通知地址
            "q1_FrpCode"         => "ALIPAY_H5",                // 支付类型 支付宝H5
            "qa_TradeMerchantNo" => self::QA_TRADEMERCHANTNO,   // 报备商户号 
        ];
        // 生成签名
        $hmacVal = $this->hmacRequest($params, self::MS5_BOUND_SYMBOL);
        $params["hmac"]  = $hmacVal;

        $result = $this->postJsonSync($url, $params);  // 发起请求
        $result = json_decode($result, true);          // 返回参数数组化

        // 请求失败
        if ($result["ra_Code"] != 100) {
            // 存储失败请求或者其他业务操作
        }
        // 请求成功:返回参数rc_Result给前端做跳转
        $result = $result["rc_Result"];
        return $result;


        // 贴一下返回示例
        {
           "r1_MerchantNo": "商户号",
           "rd_Pic": "",
           "r6_FrpCode": "ALIPAY_H5",
           "r7_TrxNo": "平台流水号",
           "r0_Version": "2.1",
           "r3_Amount": "0.01",
           "r4_Cur": "1",
           "r2_OrderNo": "商户自定义单号",
           "rb_CodeMsg": "",
           "hmac": "签名串",
           "ra_Code": 100,
           "rc_Result": "
            <html><head><meta http-equiv='Content-Type'content='text/html;     charset=UTF-8'><title></title></head><body><script     type='text/javascript'>location.href='https://qr.alipay.com/***';</script></body></html>"
        }


    }


    // ______________顺道贴一下出款 需要自取

    /**
     * 代付          请求需要请求头
     * @param url   单笔代付接口
     */
    public function singlePay()
    {
        $url        = "https://www.joinpay.com/payment/pay/singlePay"; // 请求地址              
        $notifyUrl  = "https://..";                                    // 回调地址

        $orderNo    = "商户自定义单号";
        $accountNo  = "收款人账号";
        $nameEnc    = "收款人姓名";
        $paidAmount = "0.01";        // 单位:元,精确到分,保留两位小数。

        $params     = [
            "userNo"               => self::MCH_NO,
            "productCode"          => "BANK_PAY_DAILY_ORDER",  // 产品类型:朝夕付5分钟到
            "requestTime"          => date("Y-m-d H:i:s"),     // 交易请求时间
            "merchantOrderNo"      => $orderNo,                // 商户订单号
            "receiverAccountNoEnc" => $accountNo,              // 银行收款账号
            "receiverNameEnc"      => $nameEnc,                // 持卡人姓名
            "receiverAccountType"  => 201,                     // 账户类型 私201 公204
            "paidAmount"           => $paidAmount,             // 交易金额 
            "currency"             => "201",                   // 人民币币种填写:201
            "isChecked"            => "202",                   // 是否复核 是201 否202
            "paidDesc"             => "测试出款",               // 代付用途
            "paidUse"              => "211",                   // 代付用途 211:消费款项
            "callbackUrl"          => $notifyUrl               // 回调地址
        ];
        // 生成签名
        $hmacVal = $this->hmacRequest($params, self::MS5_BOUND_SYMBOL);
        $params["hmac"]  = $hmacVal;

        $result = $this->postJsonSync($url, $params, true);  // 发起请求
        $result = json_decode($result, true);                // 返回参数数组化
        // 受理成功
        return $result["message"];


        // 贴一下返回示例
        {
           "data": {
              "errorCode": "",
              "errorDesc": "",
              "userNo": "商户号",
              "merchantOrderNo": "商户订单号",
              "hmac": "签名串"
           },
           "statusCode": 2001,
           "message": "受理成功"
        }
       
    }



    /**
     * 生成签名
     * @param $params
     * @param $key
     * @param  string $encryptType 签名类型2=RSA 1=MD5
     * @return string
     */
    function hmacRequest($params, $key, $encryptType = "1")
    {
        if ("1" == $encryptType) {
            // MD5:key = md5 签名密钥
            return md5(implode("", $params) . $key);
        } else {
            // RSA:key = 商户私钥
            $str       = chunk_split($key, 64, "\n");
            $key       = "-----BEGIN RSA PRIVATE KEY-----\n$str-----END RSA PRIVATE KEY-----\n";
            $signature = '';
            $params    = implode('', $params);
            openssl_sign($params, $signature, $key, OPENSSL_ALGO_MD5);
            $sign      = base64_encode($signature);
            return  $sign;
        }
    }

    /**
     * POST请求
     * @param url           请求地址
     * @param params        请求数据
     * @param contentType   是否携带请求头
     */
    function postJsonSync($url, $params, $contentType = false)
    {

        if (function_exists("curl_init")) { // curl方式
            $oCurl = curl_init();
            if (stripos($url, "https://") !== FALSE) {
                curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
                curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);
            }
            $string = $params;
            if (is_array($params)) {
                $aPOST = array();
                foreach ($params as $key => $val) {
                    $aPOST[] = $key . "=" . urlencode($val);
                }
                $string = join("&", $aPOST);
            }
            curl_setopt($oCurl, CURLOPT_URL, $url);
            curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($oCurl, CURLOPT_POST, TRUE);
            //$contentType json处理
            if ($contentType) {
                $headers = array(
                    "Content-type: application/json;charset='utf-8'",
                );

                curl_setopt($oCurl, CURLOPT_HTTPHEADER, $headers);
                curl_setopt($oCurl, CURLOPT_POSTFIELDS, json_encode($params));
            } else {
                curl_setopt($oCurl, CURLOPT_POSTFIELDS, $string);
            }
            $response = curl_exec($oCurl);
            curl_close($oCurl);
            return $response;
            //        return json_decode($response, true);
        } elseif (function_exists("stream_context_create")) { // php5.3以上
            $opts = array(
                "http" => array(
                    "method" => "POST",
                    "header" => "Content-type: application/x-www-form-urlencoded",
                    "content" => http_build_query($params),
                )
            );
            $_opts = stream_context_get_params(stream_context_get_default());
            $context = stream_context_create(array_merge_recursive($_opts["options"], $opts));
            return file_get_contents($url, false, $context);
            //        return json_decode(file_get_contents($url, false, $context), true);
        } else {
            return FALSE;
        }
    }
}

二、回调

    /**
     * @method                  汇聚支付回调:GET
     * @param    r2_OrderNo     商户提供的自定义订单号
     * @param    r3_Amount      支付金额
     * @param    r5_Mp          公共响应参数:业务场景
     * @param    r6_Status      支付状态 100:成功 101:失败
     * @param    r7_TrxNo       支付平台生成的交易流水号
     * @param    ra_PayTime     支付时间
     */
    public function JoinPayNotifyUrl()
    {
        $r2_OrderNo = $_GET["r2_OrderNo"];
        $r3_Amount  = $_GET["r3_Amount"];
        $r5_Mp      = $_GET["r5_Mp"];
        $r6_Status  = $_GET["r6_Status"];
        $r7_TrxNo   = $_GET["r7_TrxNo"];
        $ra_PayTime = $_GET["ra_PayTime"];
        $ra_PayTime = urldecode(urldecode($ra_PayTime));

        if ($r6_Status == 100) {
            // 成功
        } else {
            // 失败
        }

        // 返回给汇聚支付
        echo "success";

        // 贴一下回调数据:回调格式需要$_GET获取,时间需要两次urldecode
        
        "https://www.baidu.com?
        r1_MerchantNo=888000000000000
        &r2_OrderNo=2020100000000000000
        &r3_Amount=10.00
        &r4_Cur=1
        &r5_Mp=goods
        &r6_Status=100
        &r7_TrxNo=100220100000000000
        &r8_BankOrderNo=100220100000000000
        &r9_BankTrxNo=4200000000202000000000000000
        &ra_PayTime=2022-08-11%2B16%253A14%253A39
        &rb_DealTime=2022-08-11%2B16%253A14%253A39
        &rc_BankCode=WEIXI";
    }


    // ______________顺道贴一下出款回调 需要自取

     /**
     * 单笔代付回调:POST
     */
    public function singlePayNotify()
    {
        // 获取通知的数据
        $postJsonData = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : file_get_contents("php://input");
        // 转换数组
        $aParams      = json_decode($postJsonData, true);
        if ($aParams["status"] == 205) {
             // 代付成功

        }else{
             // 代付失败
        }

        // 返回给汇聚支付
        $result = [
            "statusCode" => "2001",
            "message"    => "成功"
        ];
        return $result;

        // 贴一下回调数据
         {
            "errorCode":"",
            "errorCodeDesc":"",
            "fee":1,
            "hmac":"签名串",
            "merchantOrderNo":"订单号",
            "paidAmount":0.01,
            "platformSerialNo":"平台流水号",
            "receiverAccountNoEnc":"收款账号",
            "receiverNameEnc":"姓名",
            "status":205,
            "userNo":"商户号"
          }
     }

总结

支付包含了“聚合支付”+“代付业务”,两个方法请求方式需要区分一下是否需要请求头,回调方式也不一样需要区分一下,其他 微信,扫码,公众号支付等根据文档请求调整参数就好

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值