Ios苹果支付流程:

  1. 客户端先从苹果获取内购Id。
  2. 客户端将内购id,金额、用户id等传给服务端获取一个自己服务端生成的订单号。
  3. 客户端向苹果发起支付。
  4. 支付成功后,客户端从本地拿支付凭证、将支付凭证和订单号、用户id等参数传给服务端;服务端拿支付凭证向苹果发起验证订单是否有效,然后将结果反馈给客户端。
  5. 客户端刷新用户个人信息。

代码

/**
* 服务器二次验证代码
* @param $receipt
* @param bool $isSandbox
* @return array|void
* @throws \Exception
*/
function getReceiptData($receipt, $isSandbox = false) {
if ($isSandbox) {
$endpoint = 'https://sandbox.itunes.apple.com/verifyReceipt';
} else {
$endpoint = 'https://buy.itunes.apple.com/verifyReceipt';
} //$receipt = str_replace(' ',"+", $receipt);
$postData = json_encode(["receipt-data" => $receipt]);
//$postData = '{"receipt-data":"'. $receipt .'"}';
BLog::pay("苹果支付:postData:$postData"); $ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
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); //判断时候出错,抛出异常
if ($errno != 0) {
return [
'result' => false,
'txtMessage' => $errmsg,
];
} $data = json_decode($response); BLog::pay("苹果支付:response:$response"); //此处是看到先人们的指导,又看到apple的官方说法改的。否则会审核不过貌似是审核也会走沙盒测试者,
//此处先判断一次返回的status是否=21007 这数据是从测试环境,但它发送到生产环境中进行验证。它发送到测试环境来代替。
if ($data->status == 21007) {
$this->getReceiptData($receipt, true);
return;
}
//判断返回的数据是否是对象
if (!is_object($data)) {
throw new \Exception('Invalid response data');
}
//判断购买时候成功
if (!isset($data->status) || $data->status != 0) {
throw new \Exception('Invalid receipt');
} //返回产品的信息
return (array)$data->receipt;
} /**
* ios 支付验证
* @param $allData
* @return array|string
*/
public function iosIAPPay($allData) {
$receiptData = $allData['receiptData'];
//获取 App 发送过来的数据,设置时候是沙盒状态
$receipt = $receiptData;
$isSandbox = true;
if ('server' == APP_ENV) {
$isSandbox = false;
}
//开始执行验证
try {
$info = $this->getReceiptData($receipt, $isSandbox); $package_name = $info['bid'] ?? "";
if (!$package_name) {
$package_name = $info['bundle_id'] ?? "";
}
if (!$package_name) {
return [
'result' => false,
'txtMessage' => 'bid或bundle_id缺失',
];
} $product_id = $info['product_id'] ?? "";
if (!$product_id) {
$product_id = $info['in_app'][0]->product_id ?? "";
}
if (!$product_id) {
return [
'result' => false,
'txtMessage' => 'product_id缺失',
];
} $transaction_id = $info['transaction_id'] ?? "";
if (!$transaction_id) {
$transaction_id = $info['in_app'][0]->transaction_id ?? "";
}
if (!$transaction_id) {
return [
'result' => false,
'txtMessage' => 'transaction_id缺失',
];
} $productInfo = DB::table('ios_payment_config')
->where('package_name', $package_name)
->where('product_id', $product_id)
->first();
if (!$productInfo) {
BLog::pay("苹果支付:无该产品:" . json_encode($info));
return [
'result' => false,
'txtMessage' => '无该产品',
];
}
$user_open_id = $info['download_id'] ?? "";
$res = $this->doPay($allData['userId'], $allData['orderId'], $transaction_id, $user_open_id);
BLog::pay("苹果支付:支付结果:" . json_encode($info) . json_encode($res));
return $res; } catch (\Exception $e) {
return [
'result' => false,
'txtMessage' => $e->getMessage(),
];
}
}

常见错误码

/**
* 21000 App Store不能读取你提供的JSON对象
* 21002 receipt-data域的数据有问题
* 21003 receipt无法通过验证
* 21004 提供的shared secret不匹配你账号中的shared secret
* 21005 receipt服务器当前不可用
* 21006 receipt合法,但是订阅已过期。服务器接收到这个状态码时,receipt数据仍然会解码并一起发送
* 21007 receipt是Sandbox receipt,但却发送至生产系统的验证服务
* 21008 receipt是生产receipt,但却发送至Sandbox环境的验证服务
*/

遇到的坑

回包结构的修改

https://www.cnblogs.com/HappyTeemo/p/17221209.html

新结构:


{
"receipt": {
"receipt_type": "ProductionSandbox",
"adam_id": 0,
"app_item_id": 0,
"bundle_id": "申请苹果支付时的串号 固定的值",
"application_version": "24",
"download_id": 0,
"version_external_identifier": 0,
"receipt_creation_date": "2022-************Etc/GMT",
"receipt_creation_date_ms": "1643************000",
"receipt_creation_date_pst": "2022-0a************/Los_Angeles",
"request_date": "2022-02-2************Etc/GMT",
"request_date_ms": "164************7",
"request_date_pst": "2022-************ngeles",
"original_purchase_date": "201************tc/GMT",
"original_purchase_date_ms": "13************00",
"original_purchase_date_pst": "2013************geles",
"original_application_version": "1.0",
"in_app": [ //变成了数组
{
"quantity": "1",
"product_id": "10000",#产品ID
"transaction_id": "", ##交易单号
"original_transaction_id": "",
"purchase_date": "2022************Etc/GMT",
"purchase_date_ms": "164************0",
"purchase_date_pst": "2022-************les",
"original_purchase_date": "2022************GMT",
"original_purchase_date_ms": "164************0",
"original_purchase_date_pst": "202************les",
"is_trial_period": "false",
"in_app_ownership_type": "PURCHASED"#交易状态
},
{
"quantity": "1",
"product_id": "10000",#产品ID
"transaction_id": "", ##交易单号
"original_transaction_id": "",
"purchase_date": "2022************Etc/GMT",
"purchase_date_ms": "164************0",
"purchase_date_pst": "2022-************les",
"original_purchase_date": "2022************GMT",
"original_purchase_date_ms": "164************0",
"original_purchase_date_pst": "202************les",
"is_trial_period": "false",
"in_app_ownership_type": "PURCHASED"#交易状态
},
]
},
"environment": "Sandbox", //环境
"status": 0
}

老版本是一个一维数组,没有in_app

post请求的坑,报21003

  • 第一种,有空格,使用字符串替换
$receipt = str_replace(' ',"+", $receipt);
  • 第二种,json不对,直接拼字符串,不要json_encode
$postData = '{"receipt-data":"'. $receipt .'"}';
  • 第三种,苹果那边的问题,什么都没改,第一天好的,第二天报错(沙盒报错,线上好的),第三天好了。

PHP接入苹果支付的更多相关文章

  1. 在Web应用中接入微信支付的流程之极简清晰版

    在Web应用中接入微信支付的流程之极简清晰版 背景: 在Web应用中接入微信支付,我以为只是调用几个API稍作调试即可. 没想到微信的API和官方文档里隐坑无数,致我抱着怀疑人生的心情悲愤踩遍了丫们布 ...

  2. 在Web应用中接入微信支付的流程之极简清晰版 (转)

    在Web应用中接入微信支付的流程之极简清晰版 背景: 在Web应用中接入微信支付,我以为只是调用几个API稍作调试即可. 没想到微信的API和官方文档里隐坑无数,致我抱着怀疑人生的心情悲愤踩遍了丫们布 ...

  3. TP3.2.3 接入银联支付

    TP3.2.3 接入银联支付 项目接入银联支付的过程, 在此记录下,希望能帮助开发盆友平坑. 银联SKD链接:https://open.unionpay.com/ajweb/product/newPr ...

  4. Idea-Java接入银联支付的Demo

    注:本文来源于:< Idea-Java接入银联支付的Demo > 接入银联支付的Demo,希望能给大家节约一点时间 https://github.com/wangfei0904306/un ...

  5. Android 接入支付宝支付实现

    接上篇android接入微信支付文章,这篇我们带你来接入支付宝支付服务 简介 首先要说明的是个人感觉接入支付宝比微信简单多了,很轻松的,所以同学们不要紧张~ 当然还是老规矩啦,上来肯定的贴上官网地址, ...

  6. Android接入支付宝支付实现

    接上篇android接入微信支付文章,这篇我们带你来接入支付宝支付服务 简介 首先要说明的是个人感觉接入支付宝比微信简单多了,很轻松的,所以同学们不要紧张~ 当然还是老规矩啦,上来肯定的贴上官网地址, ...

  7. 微信App支付接入步骤&支付中前后端交互流程

    最近对微信App支付(App端集成微信支付SDK)申请步骤,以及终端在进行微信支付时商户App.商户Server.微信App.微信支付Server的交互流程进行了简单了解.这篇文章应该算是学习笔记,分 ...

  8. Unity接入微信支付SDK 2022年版安卓篇

    最近1年转了UE开发,博客更新的比较少,技术栈宽了不少,以后有空尽量多更新,也方便总结记忆 Unity接入微信支付整个过程坑比较多,网上之前的教程要么比较老,要么比较零碎,只能东拼西凑摸索,跑通后还是 ...

  9. thinkphp5.0 微信公众号接入支付宝支付

    ---恢复内容开始--- 真是无力吐槽这个需求了,想骂客户,好端端的非要在微信公众号接入支付宝,都知道微信公众号是拒绝支付宝的,屏蔽了支付宝,所以在微信公众号接入支付宝的话就必须手动复制链接跳出微信内 ...

  10. php 微信公众号接入支付宝支付

    真是无力吐槽这个需求了,好端端的非要在微信公众号接入支付宝,都知道微信公众号是拒绝支付宝的,屏蔽了支付宝,所以在微信公众号接入支付宝的话就必须手动复制链接跳出微信内置浏览器,强制性打开web浏览器完成 ...

随机推荐

  1. .Net 8.0 下的新RPC,IceRPC之试试的新玩法"打洞"

    作者引言 很高兴啊,我们来到了IceRPC之试试的新玩法"打洞",让防火墙哭去吧 试试RPCs的新玩法"打洞" 比较典型的玩法:RPC数据流从客户端流向服务端, ...

  2. java的jdbc插入的时候,遇到null情况报错问题

    分析原因: 在执行SQL时MyBatis会自动通过对象中的属性给SQL中参数赋值,它会自动将Java类型转换成数据库的类型.而一旦传入的是null它就无法准确判断这个类型应该是什么,就有可能将类型转换 ...

  3. 支持4K60帧,高清高帧率远程控制软件

    设计师可以在家远程工作吗?动画制作人员可以远程在家工作吗?视频后期人员可以远程在家工作吗? 相比其他领域,设计.动画.影视视频后期等行业,往往需要高端机运行大型专业软件,一般人家里不具备这个办公条件. ...

  4. Lua热更学习--使用toLua中的协程

    [6] C#访问调table类中的成员变量和函数 访问table中的变量和函数 lua中可以使用table作为class,因此对table中的函数访问调用是必要的根据前面对table访问和functi ...

  5. 撤销 git commit

    目录 文章目录 目录 场景1:撤回 commit,不撤销 git add .,保留代码 场景2:撤回 commit,撤销 git add .,保留代码 场景3:撤销 commit,撤销 git add ...

  6. es部署

    部署单机版es tar xf elasticsearch-7.16.0-linux-x86_64.tar.gz./bin/elasticsearch -dcan not run elasticsear ...

  7. 【C#】爬取百度贴吧帖子 通过贴吧名和搜索关键词

    背景:最近喜欢看百度贴吧,因为其内容大多都是吧友的真实想法表达等等原因.但是通过网页去浏览贴吧,始终觉得不够简介,浏览帖子的效率不高,自己就萌发了通过自己爬取贴吧感兴趣的关键字内容,自己写了个winf ...

  8. Python 爬虫神器 requests 工具

    一.模块安装 pip install requests 二.常用方法 在实际的爬虫中,其实真正用到的只有 GET.POST,像其他的方法基本用不到,比如:DELETE.HEAD.PUT 等. 1.GE ...

  9. NOIP模拟82

    T1 魔法 解题思路 发现选择情况无非就是两种,连续的一段或者间隔为 \(R+B\) 的倍数的一段. 直接对于原序列贪心,每次选择可以消除的部分并将其删掉. 对于合法的情况将操作倒序输出即可. cod ...

  10. 微软官方开源免费的Blazor UI组件库 - Fluent UI Blazor

    前言 今天大姚给大家分享一个由微软官方开源(MIT License).免费的Blazor UI组件库:Fluent UI Blazor. 全面的ASP.NET Core Blazor简介和快速入门 F ...