需要获取抖音小程序的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了,下面还需要订单同步到抖音,下场如下
这里不需要申请额外的参数,大致分为三步(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);
}