php thinkphp 抖音支付,订单同步接口分享

news2024/9/25 15:28:12

1. 抖音支付

需要获取抖音小程序的AppID,AppSecret,需要配置回调地址,Token获取SALT
官方地址:支付,订单同步
在这里插入图片描述
以下干货仅针对于有一定开发基础的精英,0基础的止步。

  public function DouyinPay($openId='',$id='',$body = '抖音担保支付'){

        $order=db('order')->where(['id'=>$id,'status'=>1])->find();//获取订单信息

        $outOrderNo = $order['orderno'];//开发者侧的订单号
        $totalAmount = $order['price'];//支付价格; 接口中参数支付金额单位为[分]
        $subject = "订单号:".$order['orderno']; //商品描述也就是标题
        $body = $body;
        $validTimestamp = 60 * 60;//订单过期时间(秒);
        $notifyUrl = "https://***/notify"; //这里可以忽略,走字节跳动小程序 -支付 -担保配置-设置回调地址
        //创建订单
        $response = $this->createOrder($outOrderNo, $totalAmount, $subject, $body, $validTimestamp, $notifyUrl);

        $this->success('成功',$response);
    }
        /**
     *	创建订单
     */
    public function CreateOrder($outOrderNo, $totalAmount, $subject, $body, $validTimestamp, $notifyUrl)
    {
        $params = [
            'app_id'       => '******',//小程序appid
            'out_order_no' => $outOrderNo,
            'total_amount' => $totalAmount * 100,
            'subject'      => $subject,
            'body'         => $body,
            'valid_time'   => $validTimestamp,
           'notify_url'   => $notifyUrl,
      
        ];

        $params = array_filter($params);
        $params['sign'] = $this->sign($params);

        $res = $this->posts(
            'https://developer.toutiao.com/api/apps/ecpay/v1/create_order',
            $params
        );
        return $res;
    }
    /**
     *	获取签名
     */
    public  function sign($map) {
        $rList = [];
        foreach($map as $k =>$v) {
            if ($k == "other_settle_params" || $k == "app_id" || $k == "sign" || $k == "thirdparty_id")
                continue;

            $value = trim(strval($v));
            if (is_array($v)) {
                $value = $this->arrayToStr($v);
            }

            $len = strlen($value);
            if ($len > 1 && substr($value, 0,1)=="\"" && substr($value, $len-1)=="\"")
                $value = substr($value,1, $len-1);
            $value = trim($value);
            if ($value == "" || $value == "null")
                continue;
            $rList[] = $value;
        }
        $rList[] = "*****";//这里是SALT
        sort($rList, SORT_STRING);
        return md5(implode('&', $rList));
    }
    // **************** 以下方法 是字节小程序支付 签名处理方式

    public function callbackSign($data) {
		//***这里的是配置salt的时候填写的Token令牌
        $array = array(

            '***',(string)$data['timestamp'],(string)$data['nonce'],		(string)htmlspecialchars_decode($data['msg'])

        );

        sort($array,SORT_STRING);

        $join_str = implode('',$array);

        return sha1($join_str);

    }


    public function arrayToStr($map) {
        $isMap =  $this->isArrMap($map);

        $result = "";
        if ($isMap){
            $result = "map[";
        }

        $keyArr = array_keys($map);
        if ($isMap) {
            sort($keyArr);
        }

        $paramsArr = array();
        foreach($keyArr as  $k) {
            $v = $map[$k];
            if ($isMap) {
                if (is_array($v)) {
                    $paramsArr[] = sprintf("%s:%s", $k, arrayToStr($v));
                } else  {
                    $paramsArr[] = sprintf("%s:%s", $k, trim(strval($v)));
                }
            } else {
                if (is_array($v)) {
                    $paramsArr[] = arrayToStr($v);
                } else  {
                    $paramsArr[] = trim(strval($v));
                }
            }
        }

        $result = sprintf("%s%s", $result, join(" ", $paramsArr));
        if (!$isMap) {
            $result = sprintf("[%s]", $result);
        } else {
            $result = sprintf("%s]", $result);
        }

        return $result;
    }

  public  function isArrMap($map) {
        foreach($map as $k =>$v) {
            if (is_string($k)){
                return true;
            }
        }

        return false;
    }
    // **************** 以下方法 是回调


    public function notify()
    {
        $notify = \request()->param();
    //  验签
        if ($notify['msg_signature'] !== $this->callbackSign($notify)) {
           return false;

        } else {
            //获取订单信息
            $order=(string)htmlspecialchars_decode($notify['msg']);
            $order = json_decode($order, true);
            //处理订单,获取订单号
       
            $sn =  $order['cp_orderno'];
            $do2='订单的处理';
            if($do2){
              
                $data = ['err_no' => '0', 'err_tips' => 'success'];
                return json($data);
            }else{
                db()->rollback();
                return false;
            }
           // Log::info('抖音担保支付效验成功');
        }

    }
      public function posts(string $url, array $params = [], array $headers = [])
    {
        $headers[] = 'Content-type: application/json';

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $output = curl_exec($ch);
        curl_close($ch);

        return json_decode($output, true);
    }

不要单纯以为只要支付完成就OK了,下面还需要订单同步到抖音,下场如下

在这里插入图片描述

2.订单同步

这里不需要申请额外的参数,大致分为三步(1.获取token,2.组装商品,3.组装订单)
代码如下:

     /**
     * 订单推送到抖音
     * @param $data array 订单数据
     * @note order_status 与 status须保持一致,但类型不同
     * @return array
     */
    public  function pushOrder($id=''){
        $data=[];//获取订单信息
        $api = "https://developer.toutiao.com/api/apps/order/v2/push";
        $openid ='';//获取下单用户openid
  		//组装商品
        $item_list = [['item_code' => '购买会员卡','img'=>'https://***/logo.jpg',
            'title'=>'会员服务','amount'=>1,'price'=>(int)($data['price']*100)]];//参数对应请查看官方文档,注意字段类型
           // 组装订单
        $detail = [
            'order_id'=>$data['orderno'],'create_time'=>strtotime($data['add_time'])*1000,'status'=>"已支付",'amount'=>1,
            'total_price'=>(int)($data['price']*100),'detail_url'=>"pages/me/vip/vip",'item_list'=>$item_list];
              dump($detail);
              
        $param = ['access_token'=>$this->getAccessTokens(),'app_name'=>"douyin",
            'open_id'=>$openid,'update_time'=>$this->getMillisecond(),'order_detail'=>json_encode($detail),'order_type'=>0,'order_status'=>1,'payment_order_no'=>$data['orderno']];
     
        $result =$this->posts($api,$param);//请求
      
    }
     /**
     * 获取AccessToken
     */
    public  function getAccessTokens(){
        $api = "https://developer.toutiao.com/api/apps/v2/token";
			  $param = ['appid'=>'***','secret'=>'***','grant_type'=>"client_credential"];
        $access_token = Cache::get('dy_accessToken');
        if(empty($access_token)){
            $data = $this->posts($api,$param);
         //   dump($result);die;
         //   $data = json_decode($result,true);
            if($data['err_no'] == 0){
                $access_token = $data['data']['access_token'];
                Cache::set('dy_accessToken',$access_token,$data['data']['expires_in']);
            }
        }
        return $access_token;
    }
       public  function getMillisecond() {
        list($t1, $t2) = explode(' ', microtime());
        return (float)sprintf('%.0f',(floatval($t1)+floatval($t2))*1000);
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/921816.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微服务中间件--分布式搜索ES

分布式搜索ES 11.分布式搜索 ESa.介绍ESb.IK分词器c.索引库操作 (类似于MYSQL的Table)d.查看、删除、修改 索引库e.文档操作 (类似MYSQL的数据)1) 添加文档2) 查看文档3) 删除文档4) 修改文档 f.RestClient操作索引库1) 创建索引库2) 删除索引库/判断索引库 g.RestClient操作文…

用户端Web自动化测试_L3

目录: 浏览器复用Cookie 复用pageobject设计模式异常自动截图测试用例流程设计电子商务产品实战 1.浏览器复用 复用浏览器简介 为什么要学习复用浏览器? 自动化测试过程中,存在人为介入场景提高调试UI自动化测试脚本效率 复用已有浏览…

13. Docker实战之安装MySQL

目录 1、前言 2、部署MySQL 2.1、Docker仓库查看镜像 2.2、拉取MySQL镜像 2.3、创建持久化目录 2.4、启动MySQL容器 2.5、查看宿主机上的MySQL目录 2.6、本地MySQL测试 2.7、新建MySQL用户,配置远程访问 2.8、本地Navicat连接测试 3、为什么数据库不适合D…

长胜证券:a股交易时间是几点到几点?

股票商场是一个高速工作的场所,关于新手出资者来说,他们可能不知道A股买卖的时刻是什么时分开始和完毕,这将给他们在买卖过程中带来一些麻烦。本文将从不同的角度来分析A股买卖时刻,帮助读者更好地了解A股买卖时刻的相关规定。 A股…

Talk | 香港中文大学张懿元:由MetaTransformer探索统一的多模态学习

本期为TechBeat人工智能社区第524期线上Talk! 北京时间8月23日(周三)20:00,香港中文大学博士生—张懿元的Talk已准时在TechBeat人工智能社区开播! 他与大家分享的主题是: “探索模态通用感知”,介绍了多模态学习和发展统一的多模态…

espidf vscode 安装出错ERROR_INVALID_PIP

解决链接:https://www.cnblogs.com/xiaohuzaixue/p/17558731.html 注意 不要使用win11的右键打开终端,在文件管理器上方输入cmd打开终端才有用。

数据结构——栈和队列OJ题

栈和队列小提升! 前言一、用队列实现栈队列接口实现(1)栈的接口定义(2)栈的初始化(3)入栈函数的定义(4)出栈函数的定义(5)查找栈顶元素&#xff0…

数据清洗——气温历史数据

import pandas as pd import numpy as np import matplotlib.pyplot as plt from pylab import mpl mpl.rcParams["font.sans-serif"] ["HarmonyOS Sans SC"] %matplotlib inline读取数据 data pd.read_excel("气温历史数据.xlsx") data.head…

【golang】for语句和switch语句

使用携带range子句的for语句时需要注意哪些细节? numbers1 : []int{1, 2, 3, 4, 5, 6} for i : range numbers1 {if i 3 {numbers1[i] | i} } fmt.Println(numbers1)这段代码执行后会打印出什么内容? 答案:[1 2 3 7 5 6] 当for语句被执行…

【面试题系列】(一)

Redis有哪些数据结构?其底层是怎么实现的? Redis 系列(一):深入了解 Redis 数据类型和底层数据结构 字符串(String): 用于存储文本或二进制数据。可以执行字符串的基本操作&#xf…

只需五分钟,了解kafka的环境搭建

〇、前言 在Kafka系列的上一篇文章中,我们介绍了Kafka的体系结构,那么本篇文章呢,我们就着手来把Kafka的运行环境搭建起来。 此处 ,我们采用线上环境普遍使用的ZooKeeper作为管理存储和管理kafka集群元数据,或者辅助…

更高效稳定 | 基于ACM32 MCU的编程直流电源应用方案

随着电子设备的多样化发展,面对不同的应用场景,需要采用特定的供电电源。因此,在电子产品的开发测试过程中,必不可少使用编程直流电源来提供测试电压,协助完成初步的开发测试过程。 编程直流电源概述 编程直流电源结构…

收单外包服务机构(第三方支付公司服务商)是什么?

收单外包服务机构(第三方支付公司服务商)是什么? 伴随着电子商务的迅速发展,越来越多的企业开始认识到收单外包服务机构的重要性。 收单外包是一个重要的服务机构,可以帮助企业解决许多与支付相关的问题。 收单外包服务…

行式存储与列式存储

1.概述 数据处理大致可分为两大类,联机事务处理OLTP(on-line transaction processing) 和联机分析处理OLAP(on-line analytical processing)。 OLTP是传统关系型数据库的主要应用,用来执行一些基本的、日常的事务处理,比如数据库记录的增、删…

漏洞复现 || Franklin Fueling Systems tsaupload.cgi 任意文件读取

漏洞描述 Franklin Electric Franklin Fueling Systems是美国Franklin Electric公司的一个加油系统,Franklin Fueling Systems tsaupload.cgi 存在任意文件读取漏洞,攻击者通过漏洞可以获取服务器敏感文件。 免责声明 技术文章仅供参考,任…

SpringMVC中Controller层获取前端请求参数的几种方式

SpringMVC中Controller层获取前端请求参数的几种方式 1、SpringMVC自动绑定2、使用RequestParam 注解进行接收3、RequestBody注解(1) 使用实体来接收JSON(2)使用 Map 集合接收JSON(3) 使用 List集合接收JSO…

C语言暑假刷题冲刺篇——day4

目录 一、选择题 二、编程题 🎈个人主页:库库的里昂 🎐CSDN新晋作者 🎉欢迎 👍点赞✍评论⭐收藏✨收录专栏:C语言每日一练 ✨其他专栏:代码小游戏C语言初阶🤝希望作者的文章能对你…

iOS逆向初探:揭开iOS App的神秘面纱

逆向是一种分析和还原应用程序的过程,它能够揭示应用程序内部的工作原理和代码结构。接下来我们将全面介绍iOS上的逆向,包括其概念、常用工具和具体实例。 1. 什么是iOS逆向? iOS平台逆向是将应用程序的二进制代码(通常是经过编…

无涯教程-Python - Numbers(数字)

数字数据类型存储数值,它们是不可变的数据类型,这意味着更改数字数据类型的值将导致新分配的对象。 数字对象是在您为其分配值时创建的。例如- var11 var210 您也可以使用 del 语句删除对数字对象的引用。 del语句的语法是- del var1[,var2[,var3[..…

基于XML实现SpringIoC配置

目录 SpringIoc创建与使用的大致步骤 一.基于xml配置SpringIoc 二.基于xml配置DI 三.创建IoC容器并获取组件 SpringIoc创建与使用的大致步骤 SpringIoC的创建与使用过程分为3步 1.编写配置信息(编写XML,注解、Java类) 2.创建IoC容器&…