### 先上代码,以备后用
~~~php
<?php
namespace app\index\controller\v1\ios;
use app\index\controller\Base;
use fast\Random;
use think\Db;
use think\Request;
class Applepay extends Base {
/**
* 获取套餐
* @return \think\response\Json
*/
public function getpackage(){
$t=[
['id'=>1,'money'=>12],
['id'=>2,'money'=>68],
['id'=>3,'money'=>128],
['id'=>4,'money'=>198],
['id'=>5,'money'=>588],
['id'=>6,'money'=>1098],
];
return json(['code'=>'1','message'=>'','data'=>$t]);
}
/**
* 苹果下单
*/
public function setorder(){
$param = $this->ios_data();
if(!isset($param['userid'])){
return json(['code'=>0,'message'=>'请传递用户id']);
}
// $this->checkToken();
// if(!isset($param['num'])){
// json(['code'=>0,'message'=>'请选择结藤币数量'])->send();exit;
// }
if(!isset($param['money'])){
return json(['code'=>0,'message'=>'请传递支付金额']);
}
// if(!isset($param['type'])){//0=微信支付,1=支付宝支付 4=苹果支付
// return json(['code'=>0,'message'=>'请选择支付方式']);
// }
$userinfo = $this->userinfo($param['userid']);
// $jt_member_row = Db::name(self::JT_MEMBER)->where('id',$userinfo['jt_member_id'])->find();
//计算实际支付金额
// $money = $param['num'] * ($jt_member_row['discount']/100);
// $money = $param['num'] * ($jt_member_row['discount']/100);
// if($money!=$param['money']){
// json(['code'=>0,'message'=>'所支付金额不符'])->send();exit;
// }
$order_id=Random::build('alnum',20);
$add_db = [
'order_type' => 4,
'user_id' => $param['userid'],
'fee' => $param['money']*100,//数据库单位为分
'open_id' => $userinfo['open_id'],
'add_time' => time(),
'jt_point' => $param['money'],
'purchase_type'=>8,
'order_status'=>0,
'order_id'=>$order_id
];
$res = Db::table('order')->insert($add_db,false,true);
if(!$res){
return json(['code'=>0,'message'=>'支付订单创建失败']);
}else{
return json(['code'=>1,'message'=>'订单创建成功','data'=>$add_db]);
}
}
/**
* @title 验证支付票据 完成订单接口
*/
public function verifyReceipt()
{
$param = $this->ios_data();
//
// $receipt = Request::instance()->param('receipt'); //票据
// $orderSn = Request::instance()->param('order_id'); //订单号
$receipt=$param['receipt'];
$orderSn=$param['order_id'];
$ck=Db::table('order')->where(array('order_id'=>$orderSn))->find();
if($ck){
if($ck['order_status']==3){
return json(['code'=>0,'message'=>'订单已成功支付,请勿重复发起申请']);
}
}
//判断订单是否存在 检查状态
//写入日志 查看票据格式 记录日志的方法 这个方法不贴出来了
// Tool::callAddLog('request-param',json_encode(['receipt'=>$receipt,'orderSn'=>$orderSn]));
trace('receipt**************************************************');
trace($receipt);
trace('receipt**************************************************');
trace('orderSn&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&');
trace($orderSn);
trace('orderSn&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&');
//password 是验证秘钥
$jsonItem = json_encode(['receipt-data'=>$receipt]);
// $jsonItem = json_encode(['receipt-data'=>$receipt, 'password'=>'XXXXXXXXXXXXXXXX']);
//$url= 'https://buy.itunes.apple.com/verifyReceipt'; //正式
$url= 'https://sandbox.itunes.apple.com/verifyReceipt'; //测试
//模拟post提交 下面会贴出来
$result = $this->http_post_json($jsonItem,$url);
trace('orderS$result$result$result$result$result$result$result$result$result$result$result$result$result$result$result$result');
trace($result);
trace('orderS$result$result$result$result$result$result$result$result$result$result$result$result$result$result$result$result');
if($result['status'] !== 0){
//验证失败 返回app错误状态
return json(['code'=>0,'message'=>'秘钥验证失败']);
}
//验证完成加入日志
// Tool::callAddLog('verifyReceipt_finish',json_encode($result));
trace('success&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&');
trace($result);
trace('success&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&');
//找出时间最大的数组
$receiptitem = $result['receipt']['in_app'];
//这个是排序的方法 下面回帖出来 苹果会把这个会员往期的订单信息全部返回,需要找出来最近的那一组信息
$item = $this->arraySort($receiptitem,'purchase_date','desc');
//判断一下过期时间 延长会员时间
$orderThird = $item['transaction_id']; //本次订阅的订单号
$orderThirdFirst = $item['original_transaction_id']; //这个是原始订单号
$orderinfo=Db::table('order')->where(array('order_id'=>$orderSn))->find();
if($orderThird == $orderThirdFirst){ //首次订阅 两个相等
/*业务逻辑*/
Db::startTrans();
try {
/*更新订单*/
Db::commit();
return json(['code'=>1,'message'=>'支付成功1']);
} catch (Exception $e) {
Db::rollback();
return json(['code'=>0,'message'=>'支付失败1']);
}
}else{
//判断过期时间和当前时间比较 expires_date_ms是毫秒单位
if($item['expires_date_ms']/1000 > time()){
/*业务逻辑*/
Db::startTrans();
try {
/*更新订单*/
Db::commit();
} catch (Exception $e) {
Db::rollback();
}
}else{
//过期处理 票据失效
}
}
// 接下来处理订单业务逻辑,处理订单,修改订单信息,original_transaction_id 把这个单号和存入订单信息,
// 在异步回调的时候根据这个单号来查找订单信息来判断是哪个用户,
// 苹果票据里面也有产品product_id,是app_store的产品id,不是自己业务的产品id,
// 可以在后台把自己的产品ID和 product_id 关联,处理业务逻辑。
}
//模拟post提交
public static function http_post_json($json,$url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); //这两行一定要加,不加会报SSL 错误
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$response = curl_exec($ch);
$errno = curl_errno($ch);
$errmsg = curl_error($ch);
curl_close($ch);
$data = json_decode($response, true);
return $data;
}
//查找最新数据的方法
public static function arraySort($arr,$key,$type='asc')
{
$keyArr = []; // 初始化存放数组将要排序的字段值
foreach ($arr as $k => $v) {
$keyArr[$k] = $v[$key]; // 循环获取到将要排序的字段值
}
if ($type == 'asc') {
asort($keyArr); // 排序方式,将一维数组进行相应排序
} else {
arsort($keyArr);
}
foreach ($keyArr as $k => $v) {
$newArray[$k] = $arr[$k]; // 循环将配置的值放入响应的下标下
}
$newArray = array_merge($newArray); // 重置下标
return $newArray[0]; // 数据返回
}
/**
* 异步回调
*/
public function applePayReceive(){
$str = file_get_contents('php://input');
trace('request-param……………………………………………………………………………………………………');
trace($str);
trace('request-param……………………………………………………………………………………………………');
//写入通知日志
$jsonItem = json_decode($str,true);
if($jsonItem['notification_type'] == 'RENEWAL' || $jsonItem['notification_type'] == 'DID_CHANGE_RENEWAL_STATUS'){
if($jsonItem['notification_type'] == 'DID_CHANGE_RENEWAL_STATUS'){
if($jsonItem['auto_renew_status'] == 'true'){
//第一次够买的时候 不处理通知
die;
}
$expires_date = $jsonItem['latest_receipt_info']['expires_date'];
$expires_date = $expires_date/1000;
// Tool::asynAddLog('request-param',$expires_date.'----'.time());
trace('request-param&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&');
trace($expires_date);
trace('request-param&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&');
if($expires_date > time()){
}else{
//时间不对 不处理
}
}
//处理订阅产品的业务逻辑
echo '完成!';die;
}
}
}
~~~
![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")
返回参数(重头戏):
~~~php
[ log ] array (
'receipt' =>
array (
'receipt_type' => 'ProductionSandbox',
'adam_id' => 0,
'app_item_id' => 0,
'bundle_id' => 'com.spanish.jietengshe',
'application_version' => '1.2',
'download_id' => 0,
'version_external_identifier' => 0,
'receipt_creation_date' => '2020-06-02 09:03:31 Etc/GMT',
'receipt_creation_date_ms' => '1591088611000',
'receipt_creation_date_pst' => '2020-06-02 02:03:31 America/Los_Angeles',
'request_date' => '2020-06-02 09:03:40 Etc/GMT',
'request_date_ms' => '1591088620543',
'request_date_pst' => '2020-06-02 02:03:40 America/Los_Angeles',
'original_purchase_date' => '2013-08-01 07:00:00 Etc/GMT',
'original_purchase_date_ms' => '1375340400000',
'original_purchase_date_pst' => '2013-08-01 00:00:00 America/Los_Angeles',
'original_application_version' => '1.0',
'in_app' =>
array (
0 =>
array (
'quantity' => '1',
'product_id' => '1',
'transaction_id' => '1000000673581721',
'original_transaction_id' => '1000000673581721',
'purchase_date' => '2020-06-02 08:56:34 Etc/GMT',
'purchase_date_ms' => '1591088194000',
'purchase_date_pst' => '2020-06-02 01:56:34 America/Los_Angeles',
'original_purchase_date' => '2020-06-02 08:56:34 Etc/GMT',
'original_purchase_date_ms' => '1591088194000',
'original_purchase_date_pst' => '2020-06-02 01:56:34 America/Los_Angeles',
'is_trial_period' => 'false',
),
1 =>
array (
'quantity' => '1',
'product_id' => '2',
'transaction_id' => '1000000673586536',
'original_transaction_id' => '1000000673586536',
'purchase_date' => '2020-06-02 09:03:31 Etc/GMT',
'purchase_date_ms' => '1591088611000',
'purchase_date_pst' => '2020-06-02 02:03:31 America/Los_Angeles',
'original_purchase_date' => '2020-06-02 09:03:31 Etc/GMT',
'original_purchase_date_ms' => '1591088611000',
'original_purchase_date_pst' => '2020-06-02 02:03:31 America/Los_Angeles',
'is_trial_period' => 'false',
),
),
),
'status' => 0,
'environment' => 'Sandbox',
)
~~~
![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")
完成业务逻辑,结束,注意异步回调,才是解决掉单的关键,另外还有查单接口需要调试
参考地址:
[苹果支付的坑 - 简书](https://www.jianshu.com/p/25d64699e20e "苹果支付的坑 - 简书")
[PHP服务端 苹果支付(IAP)处理\_山水天元的博客-CSDN博客\_苹果支付php](https://blog.csdn.net/u013358222/article/details/100540180 "PHP服务端 苹果支付(IAP)处理_山水天元的博客-CSDN博客_苹果支付php")
[大专栏](https://www.dazhuanlan.com/2019/12/16/5df6e8505f861/?__cf_chl_jschl_tk__=6b2be0bc60331884beca64b941e0b8c9c526853a-1590029597-0-AZBVHWlSXDdMvlJDbxikNOyVJuxSdOsBjHjo1qURz5pGZwXm8hnEo9CxpbkwMA-RZGliiymKxNF92kPyfcR_fQQoZIbfVEI4896pKojh2lOPoZQtJUTmP0Wz8ojIb8RSYkpgM-EXgdEunjLG8o697rD8QjdauJvXeGCZ6KR7yQOSyRk5ssLoNb3BUd8WJVnSKClfY_U_Kz3McPUXLcHvKtgxJ8Zd1Mc2LuiHtYn99Wz47itf5MWePE0e1mNU-4HUL4SMcpV43kqmp3HDaKRw2HEqUCK-cQWyt2qvWF7tDzA5qV7UzyoeFf0wwNV5d1bgSA "大专栏")
- 支付宝身份验证接口踩坑实录-PHP(基于ThinkPHP5)(第二版更新中)
- 抖音小程序开发之授权登录+支付宝支付+微信支付(ThinkPHP5-第三版修订中)
- TP5小知识点锦集(长期更新)
- PHP 二维码生成+识别
- 高德地图点聚合点击事件以及内容渲染
- ThinkPhP5使用phpexcle 导出数据(复制粘贴就可使用)
- Fastadmin微信小程序授权登录+获取手机号插件
- PHP -AES-128-CBC位加密解密
- PHP-Rsa分段加密解密(ThinkPHP5)
- PHP大转盘抽奖代码片段
- Fastadmin 项目上线关闭调试模式注意事项(记一次require-table.js修改事件)
- ThinkPHP5条件查询FIND_IN_SET正反使用
- ThinkPhP5整合微信小程序订阅消息
- think-queue处理延时任务事件
- ThinkPHP5 生成二维码
- Python3定时监控指定文件内容变换-(增加多行,遍历每行进行逻辑分析处理)
- Python3开发声光报警器监控触发报警
- ThinkPHP5下载文件流到本地
- 百度鹰眼抽轨迹集合稀算法&缩放比例调整显示静态图(ThinkPHP5)
- PHP 导出Excle
- Fastadmin 自定义Tab选项卡(B表的条件查询A表的数据,在A表里面加B表的参数作为选项卡)
- Fastadmin 修改url组件跳转为复制功能
- 微信H5分享好友跟朋友圈-基于Easywechat
- Python3抓取监控日志文件关键词跟内容变化修正版
- ThinkPHP5上传图片压缩处理-(解决IOS拍照上传旋转90度问题)最近更新2021年12月9日11:35:07
- 二维数组根据‘key’分组为新的三维数组
- ThinkPHP5 成功部署Workerman 运行示例
- Fastadmin框架TOKEN的使用
- ThinkPHP5 -微信小程序订阅消息开发-插件(插件基于fastadmin开发)
- ThinkPHP5-文本转义emoji表情
- ThinkPHP5 自定义命令行处理 监听Redis key失效触发回调事件,实现延迟任务 实现自动取消订单,自动完成订单
- Fastadmin插件Shopro商城里面短信插件修改为腾讯云短信插件步骤
- Fastadmin框架自定义搜索操作流程
- ThinkPHP5 处理 微信小程序内容安全审核
- Fastadmin自定义快捷搜索之模糊搜索关联他表
- php根据年月获取指定月份天数及日期数组的方法
- PHP构造函数使用校验token
- 基于ThinkPHP5&Redis腾讯云短信验证码注册登录基础业务逻辑代码整合
- ThinkPHP 解决跨域问题
- 支付宝沙箱环境测试支付(好久没做都忘了,写个博客比较省事)
- ThinkPHP5生成抖音小程序带参数二维码
- ThinkPHP5导入Excle-简单丝滑
- PHP生成带参数的小程序二维码
- ThinkPHP5成功调通IOS苹果支付
- swoole写聊天室,简单粗暴
- 微信小程序内容安全鉴别的时候,不成功因为没有转码
- Fastadmin 后台Excle文件上传(更新新增功能)
- Lnmp 配置thinkphp5 Nginx基础设置,包含http+https配置
- 通过经纬度获取数据库信息自动计算地址距离远近
- 二维数组根据某个字段排序
- PHP二维数组去重,最简单的方法
- TP5微信redis列队群发模板消息Sendmsg
- PHP检测是否关注公众号,亲测可用
- 小程序推广分享带参数二维码生成
- 基于ThinkPHP5微信H5授权登录获取用户信息(改进版)
- php过滤微信昵称中的表情
- Socket.io