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. Solution Set - 线段树

    A[洛谷P5787]无向图,每条边有一个出现时段,求每个单位时段图是否是二分图. B[洛谷P5227]无向图,询问删除一个边集后是否连通. C[洛谷P3733]连通无向图,边有权,加边.修改(增加的边 ...

  2. NSThread的main方法内部做了什么?

    NSThread当调用start方法的时候,start方法就会调用main方法.那么这个main方法内部做了什么呢?下面是汇编码: 1 ;Foundation`-[NSThread main]: 2 ...

  3. tomcat(1)- tomcat服务介绍与安装

    目录 1. Tomcat介绍 2. Tomcat安装 2.1 JDK安装 2.2 Tomcat安装 3. Tomcat打开默认的管理页面 1. Tomcat介绍 JVM简介 JAVA应用都是运行在ja ...

  4. 扩展实现Unity协程的完整栈跟踪

    现如今Unity中的协程(Coroutine)方案已显得老旧,Unitask等异步方案可以做到异常捕获等yield关键字处理起来很麻烦的问题, 并且Unity官方也在开发一套异步方案,但对于临时加入到 ...

  5. 【漏洞复现】用友NC-Cloud系统uploadChunk存在任意文件上传漏洞

    阅读须知 花果山的技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站.服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作.利用此 ...

  6. 多线程池Flask实战应用

    多线程池Flask实战应用 import json import time import flask from concurrent.futures import ThreadPoolExecutor ...

  7. Flyway简单迁移失败问题

    因为我是初学者,所以问题 只是一些细节性问题,现在看看V开头创建数据库迁移时的错误 问题一: flyway 命名规则问题这个绝对的细节中的细节问题 问题一解决方案: 命名规则:一定要遵循flyway的 ...

  8. .Net Core 静态类获取注入服务

    由于静态类中无法使用有参构造函数,从而不能使用常规的方式(构造函数获取) 获取服务,我们可以采取通过IApplicationBuilder 获取 1.首先创建一个静态类 using Microsoft ...

  9. SQL必知必会(第5版) 读书笔记

    适用范围 本书涵盖的DBMS一般来说,本书中所讲授的SQL可以应用到任何数据库管理系统(DBMS).但是,各种SQL实现不尽相同,本书介绍的SQL主要适用于以下系统(需要时会给出特殊说明和注释): ❑ ...

  10. CMake官网教程学习

    简介 本文档是根据CMake的官方教程学习的笔记,同时将教程中C++实现的代码更改为C语言实现.当前还未学习完. 教程官网:CMake Tutorial - CMake 3.27.0-rc1 Docu ...