字节跳动小程序支付php sdk

需要申请&开通的内容

1.字节跳动小程序支付(图 1-1)

字节跳动小程序开发者平台 : https://developer.toutiao.com/app/applist

图1-1

2.开通支付宝App支付,并签约:https://openhome.alipay.com/platform/appManage.htm

图1-2

业务流程

1.获取抖音预支付单号

        $this->tt_config = config('toutiaopay');   //抖音配置信息
        $total_amount = $pay_order->pay_price*100;  //抖音是 “ 分 ”作为单位
        $ip = \request()->getClientIp();
        //业务数据
        $biz_content = array(
                'out_order_no' => $pay_order->out_trade_no,    //商户唯一订单号
                'uid' => $ext['tt_openid'],                                      //抖音用户openid
                'merchant_id' => $this->tt_config['merchant_id'],//字节跳动小程序支付中的商户id
                'total_amount' => $total_amount,
                'currency' => 'CNY',
                'subject' => $ext['subject'],
                'body' => $ext['body'],
                'trade_time' => NOW_TIME,
                'valid_time' => '60',
                'notify_url' => $this->tt_config['notify_url'],
                'risk_info' => json_encode(['ip'=>$ip])            // 输出示例: "{\"ip\":\"110.90.28.70\"}",
        );

        $biz_content = json_encode($biz_content);
        //公共请求参数
        $params['app_id'] = $this->tt_config['app_id'];
        $params['biz_content'] = $biz_content;
        $params['method'] = $this->tt_config['method'];    //注意:此处固定值 tp.trade.create
        $params['charset'] = $this->tt_config['charset'];
        $params['sign_type'] = $this->tt_config['sign_type'];
        //$params['format'] = $this->tt_config['format'];      //注意:此参数文档为必填,但可以不填
        $params['timestamp'] = NOW_TIME;
        $params['version'] = $this->tt_config['version'];
        
        //签名(k-v 数组排序,用 “&” 来拼接成链接,中间无符号和空格拼接上 secret, md5加密)
        ksort($params);
        $signstr = '';
        foreach ($params as $key => $value) {
            if ($value == '') {
                continue;
            }
            $signstr .= $key . '=' . $value . '&';
        }
        $signstr = trim($signstr, '&');

        $params['sign'] = md5($signstr.$this->tt_config['secret']);
        ksort($params);
        
        //请求服务端支付接口(这里用的是 GuzzleHttp 对象)
        $res = json_decode($this->httpPost($this->baseUri,$params),true);

        $res = $res['response'];
        if($res['code'] == '10000'){
            $tt_trade_no = $res['trade_no']; //头条预支付单号
        }else{
            return ErrCodeService::get(1000,'支付订单统一下单失败');
        }

2.获取支付宝唤起APP支付链接

        //实例化alipay SDK
        $alipay_config = config('alipay');
        $aop = new AopClient;
        $aop->gatewayUrl = "https://openapi.alipay.com/gateway.do";
        $aop->appId = $alipay_config['app_id'];
        $aop->rsaPrivateKey = $alipay_config['private_key'];//'请填写开发者私钥去头去尾去回车,一行字符串';
        $aop->format = "json";
        $aop->charset = "UTF-8";
        $aop->signType = "RSA2";
        $aop->alipayrsaPublicKey = $alipay_config['ali_public_key'];//'请填写支付宝公钥,一行字符串';

        //【方法一】实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
        $request = new AlipayTradeAppPayRequest();
        //SDK已经封装掉了公共参数,这里只需要传入业务参数

        $body = $ext['body'];
        $subject = $ext['subject'];
        $out_trade_no = $pay_order->out_trade_no;
        $total_amount = $pay_order->pay_price;//单位为元

        $bizcontent = "{\"body\":\"$body\","
                        . "\"subject\": \"$subject\","
                        . "\"out_trade_no\": \"$out_trade_no\","
                        . "\"timeout_express\": \"30m\"," 
                        . "\"total_amount\": \"$total_amount\","
                        . "\"product_code\":\"QUICK_MSECURITY_PAY\""
                        . "}";
        $request->setNotifyUrl($alipay_config['notify_url']);//商户外网可以访问的异步地址
        $request->setBizContent($bizcontent);
        //这里和普通的接口调用不同,使用的是sdkExecute
        $response = $aop->sdkExecute($request);
        return $response;
        -----------------------------分割线---------------------------
       //【方法二 只生成签名串,拼接链接】
        $body = $ext['body'];
        $subject = $ext['subject'];
        $out_trade_no = $pay_order->out_trade_no;
        $total_amount = $pay_order->pay_price;//单位为元

        $ali_data['app_id'] = $alipay_config['app_id'];
        $ali_data['method'] = 'alipay.trade.app.pay';          //固定写死
        $ali_data['charset'] = 'utf-8';                                    //固定写死
        $ali_data['sign_type'] = 'RSA2';                              //固定写死
        $ali_data['timestamp'] = date('Y-m-d H:i:s',NOW_TIME);
        $ali_data['version'] = '1.0';                                      //固定写死
        $ali_data['notify_url'] = $alipay_config['notify_url'];

        $bizcontent = "{\"subject\": \"$subject\","
                        . "\"out_trade_no\": \"$out_trade_no\","        //注意这里为商户唯一订单号
                        . "\"timeout_express\": \"30m\","                                  //固定写死
                        . "\"total_amount\": \"$total_amount\","
                        . "\"product_code\":\"QUICK_MSECURITY_PAY\""    //固定写死
                        . "}";
        $ali_data['biz_content'] = $bizcontent;
        $ali_data['sign'] = $aop->rsaSign($ali_data,'RSA2'); //只调用加密方法
        //注意拼接时候必须要 encode 下,返回url字符串
        foreach ($ali_data as $key => $value) {
            $urls .= $key.'='.urlencode($value).'&';
        }
        $urls = trim($urls,'&');
        return $urls;

3.生成字节跳动小程序支付请求参数

        $total_amount = $pay_order->pay_price*100; //分为单位
        $res = [];
        $res['app_id'] = $this->tt_config['app_id'];
        $res['sign_type'] = $this->tt_config['sign_type'];
        $res['uid'] = $ext['tt_openid'];
        $res['total_amount'] = $total_amount;
        $res['timestamp'] = (string)NOW_TIME;
        $res['trade_no']= $tt_trade_no;      //注意:这里为字节跳动小程序返回的预支付单号(上 1. 中获取)
        $res['merchant_id']= $this->tt_config['merchant_id'];
        $res['params'] = "{\"url\":\"$ali_url\"}";
        
        ksort($res);
        $sign_str = '';
        foreach ($res as $k => $v) {
            $sign_str .=$k.'='.$v.'&';
        }
        $sign_str = trim($sign_str,'&');
        // echo $sign_str.$this->tt_config['secret'];exit;
        $res['sign'] = md5($sign_str.$this->tt_config['secret']);

        $res['method'] = 'tp.trade.confirm'; //注意:这里于获取预支付单号不同,固定为 tp.trade.confirm 
        $res['pay_channel'] = $this->tt_config['pay_channel'];
        $res['pay_type'] = "ALIPAY_APP";
        $res['risk_info']= \request()->getClientIp();
        $res['url'] =$ali_url;

        return $res;

4.小程序端代码

pay:function () {
                //1.请求服务端获取支付调起参数
        let task = tt.request({
                url: app.globalData.url+'/activity-buy',
                data: {    //此处服务端参数自行定义
                    api_token:"xxx",  
                    buy_type:"xxx",
                    pay_type:"xxx",
                    id:xx
                },
                dataType:'json',
                method:'POST',
                header: {
                        'content-type': 'application/json'
                },
                success (res) {
                                        //2.根据服务端参数拼接唤起支付宝请求
                    var js_request = res.data.data.js_request;
                    tt.requestPayment({
                        data: {
                            app_id: js_request.app_id,
                            method: js_request.method,
                            sign: js_request.sign,
                            sign_type: js_request.sign_type,
                            timestamp: js_request.timestamp,
                            trade_no: js_request.trade_no,
                            merchant_id: js_request.merchant_id,
                            uid: js_request.uid,
                            total_amount: js_request.total_amount,
                            pay_channel: js_request.pay_channel,
                            pay_type: js_request.pay_type,
                            params: JSON.stringify({
                                url: js_request.url
                            }),
                            risk_info:"{'ip':'" + js_request.risk_info + "'}"
                        },
                        success (res) {
                            console.log(res);
                        },
                        fail (res) {
                            console.log(res);
                        }
                    })
                },
                fail (res) {
                        console.log(`request调用失败`);
                }
        });
  },

5.会出现的问题

a.优先保证(1.中的获取抖音预支付单号)正常获得
b.可以唤起支付宝后报错【支付宝报错:系统繁忙,请稍后再试。(ALIN10146)】
   b1.支付宝签名错误,请检查sign加密参数是否缺漏或者控制
   b2.支付宝App支付签约未通过
   b3.检查参数比如「应用私钥」是否正确配置
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容