老大要收保护费,我等小弟那也没办法呀。。。是的,我说的就是苹果内购!
1.先上php验证函数:
/**
* 验证AppStore内付
* @param string $receipt_data 付款后凭证
* @return array 验证是否成功
*/
function validate_apple_pay($receipt_data)
{
/**
* 0 receipt provided is valid.
* 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环境的验证服务
*/
function acurl($receipt_data, $sandbox = 0)
{
//小票信息
$POSTFIELDS = array("receipt-data" => $receipt_data);
$POSTFIELDS = json_encode($POSTFIELDS);
//正式购买地址 沙盒购买地址
$url_buy = "https://buy.itunes.apple.com/verifyReceipt";
$url_sandbox = "https://sandbox.itunes.apple.com/verifyReceipt";
$url = $sandbox ? $url_sandbox : $url_buy;
//简单的curl
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $POSTFIELDS);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
// 验证参数
if (strlen($receipt_data) < 20) {
$result = array(
'status' => false,
'message' => '非法参数'
);
return $result;
}
// 请求验证
$html = acurl($receipt_data);
$data = json_decode($html, true);
// 如果是沙盒数据 则验证沙盒模式
if ($data['status'] == '21007') {
// 请求验证
$html = acurl($receipt_data, 1);
$data = json_decode($html, true);
$data['sandbox'] = '1';
}
if (isset($_GET['debug'])) {
exit(json_encode($data));
}
// 判断是否购买成功
if (intval($data['status']) === 0) {
$order = $data['receipt']['in_app'];//所有的订单的信息
$k = count($order) - 1;
$need = $order[$k];//需要的那个订单
$result = array(
'status' => true,
'message' => '购买成功',
'product_id' => substr($need['product_id'], 19), //商品价格
'transaction_id' => $need['transaction_id'] //苹果订单号
);
} else {
$result = array(
'status' => false,
'message' => '购买失败 status:' . $data['status']
);
}
return $result;
}
2.IOS发过来的支付凭证作为参数传入validate_apple_pay()函数即可;支付凭证的json格式如下:
{
“status”:0,
“environment”: “Sandbox”,
“receipt”: {
“receipt_type”:“ProductionSandbox”,
“adam_id”: 0,
“app_item_id”: 0,
“bundle_id”: “com . christ . diandeng”,
“application_version”: “1”,
“download_id”: 0,
“version_external_identifier”: 0,
“receipt_creation_date”: “2018 - 05 - 07 10:54:48 Etc / GMT”,
“receipt_creation_date_ms”: “1525690488000”,
“receipt_creation_date_pst”: “2018 - 05 - 07 03:54:48 America / Los_Angeles”,
“request_date”: “2018 - 05 - 07 13:22:40 Etc / GMT”,
“request_date_ms”: “1525699360048”,
“request_date_pst”: “2018 - 05 - 07 06:22: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”: [
{
“quantity”:“1”,
“product_id”: “com . christ . diandeng6”,
“transaction_id”: “1000000396341988”,
“original_transaction_id”: “1000000396341988”,
“purchase_date”: “2018 - 05 - 07 10:53:05 Etc / GMT”,
“purchase_date_ms”: “1525690385000”,
“purchase_date_pst”: “2018 - 05 - 07 03:53:05 America / Los_Angeles”,
“original_purchase_date”: “2018 - 05 - 07 10:53:05 Etc / GMT”,
“original_purchase_date_ms”: “1525690385000”,
“original_purchase_date_pst”: “2018 - 05 - 07 03:53:05 America / Los_Angeles”,
“is_trial_period”: “false”
},
{
“quantity”:“1”,
“product_id”: “com . christ . diandeng208”,
“transaction_id”: “1000000396342867”,
“original_transaction_id”: “1000000396342867”,
“purchase_date”: “2018 - 05 - 07 10:54:29 Etc / GMT”,
“purchase_date_ms”: “1525690469000”,
“purchase_date_pst”: “2018 - 05 - 07 03:54:29 America / Los_Angeles”,
“original_purchase_date”: “2018 - 05 - 07 10:54:29 Etc / GMT”,
“original_purchase_date_ms”: “1525690469000”,
“original_purchase_date_pst”: “2018 - 05 - 07 03:54:29 America / Los_Angeles”,
“is_trial_period”: “false”
}
]
}
}
3.然后写我们自己的接口,如下:
// paypal 苹果支付回调接口
public function paypal_app(){
try {
//苹果内购的验证收据
$receipt_data = I('post.apple_receipt');
$user_id = I('post.user_id');
// 1.验证支付状态
$result = validate_apple_pay($receipt_data);
if ($result['status']) {
// 2.验证通过 此处可以是修改数据库订单状态等操作
$PayLogic = new PayLogic();
$this->data = $recharge= $PayLogic->getSaveRecharge($user_id,$result['product_id'],$result['transaction_id']);
$this->data['status'] = 1;
$this->data['message'] = $result['message'];
} else {
// 3.验证不通过
$this->data['status'] = 0;
$this->data['message'] = $result['message'];
}
} catch (\Exception $e) {
$this->error_code = $e->getCode();
$this->error_msg = $e->getMessage();
}
return $this->getReturnJson($this->error_code, $this->error_msg, $this->data);
}
至此,整个php后端的验证就结束了,这里有几个坑(其实还有没发现的坑):
1.ios传过来的支付凭证,最好是已经加密了(如base64加密),这样安全些,后端这边负责接收即可; 2.价格不需要ios传过来,后端自己从验证函数获取即可; 3.注意in_app,里面可能会有多个未结束的订单,如何避免重复插入订单数据呢?这里就用到了苹果 那边的订单号:transaction_id,我们再插入之前便要判断数据表中是否已有,如果有了,便不插入;如果没有再插入。 4.至于ios每次调用,我们该插入in_app里的哪一条呢?我这里用的是最新的那一条,不过也可以使用遍历。 参考其他相关材料: 1:苹果应用内购买(IAP),服务器端开发处理流程 2:php苹果内购订单验证 3.注意的坑:iOS In-App Purchase(IAP)内购服务端二次验证注意事项 4.在tp中的应用:thinkphp整合系列之苹果AppStore内购付款的服务器端php验证