PHP接入苹果支付
Ios苹果支付流程:
- 客户端先从苹果获取内购Id。
- 客户端将内购id,金额、用户id等传给服务端获取一个自己服务端生成的订单号。
- 客户端向苹果发起支付。
- 支付成功后,客户端从本地拿支付凭证、将支付凭证和订单号、用户id等参数传给服务端;服务端拿支付凭证向苹果发起验证订单是否有效,然后将结果反馈给客户端。
- 客户端刷新用户个人信息。
代码
/**
* 服务器二次验证代码
* @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接入苹果支付的更多相关文章
- 在Web应用中接入微信支付的流程之极简清晰版
在Web应用中接入微信支付的流程之极简清晰版 背景: 在Web应用中接入微信支付,我以为只是调用几个API稍作调试即可. 没想到微信的API和官方文档里隐坑无数,致我抱着怀疑人生的心情悲愤踩遍了丫们布 ...
- 在Web应用中接入微信支付的流程之极简清晰版 (转)
在Web应用中接入微信支付的流程之极简清晰版 背景: 在Web应用中接入微信支付,我以为只是调用几个API稍作调试即可. 没想到微信的API和官方文档里隐坑无数,致我抱着怀疑人生的心情悲愤踩遍了丫们布 ...
- TP3.2.3 接入银联支付
TP3.2.3 接入银联支付 项目接入银联支付的过程, 在此记录下,希望能帮助开发盆友平坑. 银联SKD链接:https://open.unionpay.com/ajweb/product/newPr ...
- Idea-Java接入银联支付的Demo
注:本文来源于:< Idea-Java接入银联支付的Demo > 接入银联支付的Demo,希望能给大家节约一点时间 https://github.com/wangfei0904306/un ...
- Android 接入支付宝支付实现
接上篇android接入微信支付文章,这篇我们带你来接入支付宝支付服务 简介 首先要说明的是个人感觉接入支付宝比微信简单多了,很轻松的,所以同学们不要紧张~ 当然还是老规矩啦,上来肯定的贴上官网地址, ...
- Android接入支付宝支付实现
接上篇android接入微信支付文章,这篇我们带你来接入支付宝支付服务 简介 首先要说明的是个人感觉接入支付宝比微信简单多了,很轻松的,所以同学们不要紧张~ 当然还是老规矩啦,上来肯定的贴上官网地址, ...
- 微信App支付接入步骤&支付中前后端交互流程
最近对微信App支付(App端集成微信支付SDK)申请步骤,以及终端在进行微信支付时商户App.商户Server.微信App.微信支付Server的交互流程进行了简单了解.这篇文章应该算是学习笔记,分 ...
- Unity接入微信支付SDK 2022年版安卓篇
最近1年转了UE开发,博客更新的比较少,技术栈宽了不少,以后有空尽量多更新,也方便总结记忆 Unity接入微信支付整个过程坑比较多,网上之前的教程要么比较老,要么比较零碎,只能东拼西凑摸索,跑通后还是 ...
- thinkphp5.0 微信公众号接入支付宝支付
---恢复内容开始--- 真是无力吐槽这个需求了,想骂客户,好端端的非要在微信公众号接入支付宝,都知道微信公众号是拒绝支付宝的,屏蔽了支付宝,所以在微信公众号接入支付宝的话就必须手动复制链接跳出微信内 ...
- php 微信公众号接入支付宝支付
真是无力吐槽这个需求了,好端端的非要在微信公众号接入支付宝,都知道微信公众号是拒绝支付宝的,屏蔽了支付宝,所以在微信公众号接入支付宝的话就必须手动复制链接跳出微信内置浏览器,强制性打开web浏览器完成 ...
随机推荐
- Mybatis的逆向工程(generator)
Tips:Mybatis generator官网 http://www.mybatis.org/generator/configreference/commentGenerator.html Myba ...
- Unity 热更--AssetBundle学习笔记 1.0【AB包资源加载工具类的实现】
工具类封装 通过上文中对AB包加载API的了解和简单使用,对AB包资源加载的几种方法进行封装,将其写入单例类中,如代码展示. 确保每个AB资源包只加载一次: 在LoadAssetBundleManag ...
- go 操作elasticsearch
olivere/elastic 包 github.com/olivere/elastic doc: https://pkg.go.dev/github.com/olivere/elastic?utm_ ...
- SQL Server使用for xml path 多行合并成一行,逗号分隔,拆解分析实现原理
我们写sql脚本处理数据的时候 针对部分数据进行group by 分组,分组后需要将部分数据放入分组后的行里面以逗号分隔. 举一个简单例子: 如上图的数据,需要对学生进行分组,取得学生都参与了哪些学科 ...
- 安装 MySQL ZIP 版本
安装 MySQL 的 ZIP 版本相对于安装包版本稍微复杂一些,因为它需要手动解压和配置.以下是在 Windows 上安装 MySQL ZIP 版本的步骤: 下载 MySQL ZIP 文件: 前往 M ...
- CSS操作——display属性
display可以指定元素的显示模式,它可以把行内元素修改成块状元素,也可以把别的模式的元素改成行内元素.diisplay常用的值有四个. 语法: /* display: block; // 声明当前 ...
- Android 12(S) MultiMedia Learning(六)NuPlayer Decoder
接下来将会从4个角度来记录NuPlayerDecoder部分 相关代码路径: http://aospxref.com/android-12.0.0_r3/xref/frameworks/av/medi ...
- nginx日志缓存open_log_file_cache
nginx日志缓存,提升磁盘性能 将多个日志进行积累,达到一定量级后写入到磁盘,可以减少磁盘旋转,从而降低磁盘i/o,提升nginx能效 语法: access_log path access_log ...
- MySQL学习笔记-SQL实践1
SQL实践1 借着学校的数据库实验,来对之前学习的SQL语言进行实践和总结. 实验环境: macOS 13.2 (22D49) mysql Ver 8.0.32 for macos13.0 on ar ...
- itest(爱测试) 4.5.2 发布,开源BUG 跟踪管理 & 敏捷测试管理软件
itest 简介 itest 开源敏捷测试管理,testOps 践行者,极简的任务管理,测试管理,缺陷管理,测试环境管理4合1,又有丰富的统计分析.可按测试包分配测试用例执行,也可建测试迭代(含任务, ...