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. 提取jks文件证书和私钥

    提取jks文件证书和私钥 JKS文件由公钥和密钥构成利用Java Keytool 工具生成的文件,它是由公钥和密钥构成的,公钥就是我们平时说的证书(.cer后缀的文件),私钥就是密钥(.key后缀的文 ...

  2. 01.windows 环境设置

    windows下可以安装Git工具, 使用git bash操作 Windows 10 环境下,通过-/.bash_profile 设置 git bash 别名: 打开 git bash,需切换到当前用 ...

  3. ruby执行周期性任务 whenever

    ruby执行周期性任务 下面看看怎么将任务写入cron服务. $ whenever #不带参数的whenever会显示转换程cron任务的代码,不写入cron任务表 $ whenever -w #写入 ...

  4. WEB服务与NGINX(19)- nginx 防盗链功能

    目录 1 nginx防盗链功能 1.1 盗链功能概述 1.2 实现盗链 1.3 实现防盗链 1 nginx防盗链功能 1.1 盗链功能概述 防盗链基于客户端携带的referer实现,referer是记 ...

  5. 详解Python 中可视化数据分析工作流程

    本文分享自华为云社区<Python 可视化数据分析从数据获取到洞见发现的全面指南>,作者:柠檬味拥抱. 在数据科学和分析的领域中,可视化是一种强大的工具,能够帮助我们理解数据.发现模式,并 ...

  6. Flutter 多线程实现

    异步Isolate实现多线程   最近在看Flutter开发相关知识点,对照着Android原生,探究了下多线程实现方式.在Flutter中有 Isolate,隔离,它的实现原理并不是内存共享的,它更 ...

  7. 题解:CF1956A Nene's Game

    这道题其实挺有意思,多测里面还套了个多测. 思路就是用向量模拟删除过程,具体请看代码里的注释. #include <bits/stdc++.h> using namespace std; ...

  8. java学习之旅(day.14)

    可变字符串 StringBuffer:可变长字符串,运行效率慢,线程安全 StringBuilder:可变长字符串,运行效率快,线程不安全 package com.zhang.lei; //Strin ...

  9. 智能勘探 | AIRIOT智慧油田管理解决方案

      石油勘探和开采地处偏远地区,涉及面广且生产规模大.特殊的作业环境下,使得工作人员作业条件艰苦,仅靠人工值守难度很大,不可避免的遇到一系列硬核挑战: 1.设备维护难度较高: 2.采油厂分布地域广.分 ...

  10. CentOS7配置NFS服务并设置客户端自动挂载

    在CentOS7中配置NFS服务并设置客户端自动挂载的步骤如下: NFS服务端配置 安装NFS服务: 首先,你需要在CentOS 7服务器上安装NFS服务.你可以使用yum命令来安装: yum ins ...