PHP抖音小程序下单支付及订单推送DEMO

PHP抖音小程序下单支付及订单推送

最近开发了一个抖音小程序,在订单推送到抖音订单中心接口对接过程中折腾了半天,最终在朋友的协助下找到了问题。为了避免再次走弯路,特将本次集成的抖音小程服务器端API对接文件记录一下。

抖音小程序服务器端API对接源码:

  1. <?php
  2. namespace app\api\logic;
  3. use think\facade\Db;
  4. use think\facade\Cache;
  5. use service\HttpService;
  6. /**
  7.  * PaymentLogic.php
  8.  * Created by 繁华如梦.
  9.  * Email: [email protected]
  10.  * DateTime: 2022/3/3 10:09
  11.  */
  12. class PaymentLogic{
  13.     public static $salt = "VTGViUk3************aujxZ7uQp";
  14.     public static $merch_id = "7044*********7650";
  15.     public static $appid = "ttd76d********aa01";
  16.     public static $secret = "8e09bac***********1ef758d9d";
  17.     public static $token = "EfFyTSwvRj************bWfYELduNb";  //开放平台设置
  18.     public static $notify = "https://************ment/dy_notify"; //默认回调通知
  19.     public static $url = "https://developer.toutiao.com/api/apps/ecpay/v1/";
  20.     /**
  21.      * 抖音下单
  22.      * @param $data array 订单信息
  23.      * $data=['out_order_no'=>$this->order_number(),'total_amount'=>1,//单位:分'subject'=>'测试商111品','body'=>'测试详情','valid_time'=>7200,];
  24.      */
  25.     public static function order($data){
  26.         $result = self::post('create_order',$data);
  27.         return $result;
  28.     }
  29.     /**
  30.      * 抖音订单查询
  31.      * @param $out_trade_no string 交易单号
  32.      * @return mixed
  33.      */
  34.     public static function query($out_trade_no){
  35.         $data = ['out_order_no'=>$out_trade_no];
  36.         $result = self::post('query_order',$data,false);
  37.         return $result;
  38.     }
  39.     /**
  40.      * 订单退款
  41.      * @param $data array 订单信息
  42.      * $data=['out_order_no'=>'2021110118351347832','out_refund_no'=>$this->order_number(),'reason'=>'退款原因','refund_amount'=>1,];
  43.      */
  44.     public static function refund($data){
  45.         $result = self::post('create_refund',$data);
  46.         return $result;
  47.     }
  48.     /**
  49.      * 订单分账
  50.      * @param $data array 订单信息
  51.      *
  52.      */
  53.     public static function settle($data){
  54.         /**
  55.             $data=[
  56.                 'out_order_no'=>'2021110118301265990',
  57.                 'out_settle_no'=>$this->order_number(),
  58.                 'settle_desc'=>'分账描述',
  59.                 'settle_params'=>json_encode([]),//分润方参数 如[['merchant_uid'=>'商户号','amount'=>'10']]  可以有多个分账商户
  60.             ];
  61.          */
  62.         $result = self::post('settle',$data);
  63.         return $result;
  64.     }
  65.     /**
  66.      * 订单推送到抖音
  67.      * @param $data array 订单数据
  68.      * @note order_status 与 status须保持一致,但类型不同
  69.      * @return array
  70.      */
  71.     public static function pushOrder($data){
  72.         $api = "https://developer.toutiao.com/api/apps/order/v2/push";
  73.         $openid = Db::name('dy_user')->where(['id'=>$data['uid']])->value('openid');
  74.         $product = Db::name('product')->where(['id'=>$data['product_id']])->field('id,cover_img')->find();
  75.         $course = Db::name('course')->where(['id'=>$data['course_id']])->value('name');
  76.         $item_list = [['img'=>$product['cover_img'],
  77.             'title'=>$course,'sub_title'=>$course,'amount'=>1,'price'=>$data['price']*100]];
  78.         $detail = [
  79.             'order_id'=>(string)$data['id'],'create_time'=>$data['create_time']*1000,'status'=>"已支付",'amount'=>1,
  80.             'total_price'=>$data['amount']*100,'detail_url'=>"pages/course/course",'item_list'=>$item_list];
  81.         $param = ['access_token'=>self::getAccessToken(),'app_name'=>"douyin",
  82.             'open_id'=>$openid,'update_time'=>self::getMillisecond(),'order_detail'=>json_encode($detail),'order_type'=>0,'order_status'=>1,'payment_order_no'=>emptyempty($data['third_order_num'])?$data['sn']:$data['third_order_num']];
  83.         $result = HttpService::post($api,json_encode($param),30,['Content-Type: application/json']);
  84.         $data = json_decode($result,true);
  85.         if($data['err_code'] == 0){
  86.             return ['code'=>200,'msg'=>$data['err_msg'],'data'=>$result];
  87.         }else{
  88.             return ['code'=>500,'msg'=>'err_code:'.$data['err_code'].'msg:'.$data['err_msg'],'data'=>[]];
  89.         }
  90.     }
  91.     /**
  92.      * 获取AccessToken
  93.      */
  94.     private static function getAccessToken(){
  95.         $api = "https://developer.toutiao.com/api/apps/v2/token";
  96.         $param = ['appid'=>self::$appid,'secret'=>self::$secret,'grant_type'=>"client_credential"];
  97.         $access_token = Cache::get('dy_accessToken');
  98.         if(emptyempty($access_token)){
  99.             $result = HttpService::post($api,json_encode($param),30,['Content-Type: application/json']);
  100.             $data = json_decode($result,true);
  101.             if($data['err_no'] == 0){
  102.                 $access_token = $data['data']['access_token'];
  103.                 Cache::set('dy_accessToken',$access_token,$data['data']['expires_in']);
  104.             }
  105.         }
  106.         return $access_token;
  107.     }
  108.     /**
  109.      * 请求小程序平台服务端
  110.      * @param string $url 接口地址
  111.      * @param array $data 参数内容
  112.      * @param boolean $notify 是否有回调
  113.      * @return array
  114.      */
  115.     private static function post($method,$data,$notify=true){
  116.         $data['app_id']=self::$appid;
  117.         if(!emptyempty($notify)){
  118.             $data['notify_url']= self::$notify;
  119.         }
  120.         $data['sign']= self::sign($data);
  121.         $url=self::$url.$method;
  122.         $res = HttpService::post($url,json_encode($data),30,['Content-Type: application/json']);
  123.         return json_decode($res,true);
  124.     }
  125.     /**
  126.      * 签名算法
  127.      * @param $map
  128.      * @return string
  129.      */
  130.     private static function sign($map) {
  131.         $rList = array();
  132.         foreach($map as $k =>$v) {
  133.             if ($k == "other_settle_params" || $k == "app_id" || $k == "sign" || $k == "thirdparty_id")
  134.                 continue;
  135.             $value = trim(strval($v));
  136.             $len = strlen($value);
  137.             if ($len > 1 && substr($value, 0,1)=="\"" && substr($value,$len$len-1)=="\"")
  138.                 $value = substr($value,1, $len-1);
  139.             $value = trim($value);
  140.             if ($value == "" || $value == "null")
  141.                 continue;
  142.             array_push($rList$value);
  143.         }
  144.         array_push($rList,self::$salt);
  145.         sort($rList, 2);
  146.         return md5(implode('&', $rList));
  147.     }
  148.     /**
  149.      * 回调验签
  150.      * @param array $map 验签参数
  151.      * @return stirng
  152.      */
  153.     public static function handler($map){
  154.         $rList = array();
  155.         array_push($rList, self::$token);
  156.         foreach($map as $k =>$v) {
  157.             if ( $k == "type" || $k=='msg_signature')
  158.                 continue;
  159.             $value = trim(strval($v));
  160.             if ($value == "" || $value == "null")
  161.                 continue;
  162.             array_push($rList$value);
  163.         }
  164.         sort($rList,2);
  165.         return sha1(implode($rList));
  166.     }
  167.     /**
  168.      * 成功返回
  169.      */
  170.     public static function success(){
  171.         return json_encode(['err_no'=>0,'err_tips'=>"success"]);
  172.     }
  173.     /**
  174.      * 写日志
  175.      * @param string $path 日志路径
  176.      * @param string $content 内容
  177.      */
  178.     public static function log($path$content){
  179.         $file = fopen($path,  "a");
  180.         fwrite($filedate('Y-m-d H:i:s').'-----'.$content."\n");
  181.         fclose($file);
  182.     }
  183.     private static function getMillisecond() {
  184.         list($t1$t2) = explode(' ', microtime());
  185.         return (float)sprintf('%.0f',(floatval($t1)+floatval($t2))*1000);
  186.     }
  187. }

温馨提示:

1、上述代码中用到的HttpService是基于curl对get和post的二次封装,源码详见https://gitee.com/zkii_admin/Tp-admin中“/extend/service/HttpService.php”。

2、推送系统订单到抖音订单中心的方法,传入系统内订单数据,在重新组合后,发起请求即可。注意order_detail的数据格式。这里一不小心很容易出错。调试的时候,可以在curl上获取响应头以便查看具体的错误信息。上述代码已经过测试。

3、以上代码基于Thinkphp6编写,在其他框架使用时需要自行修改。

你想把广告放到这里吗?

发表评论

您必须 登录 才能发表留言!