支付時拿到票據:
<?php
/**
* POST驗單curl
* @param $post_data 請求參數['key'=>'value','keys'=>'values']
* @param $url 請求地址
* @return mixed
*/
public function post_receipt_data($post_data,$url){
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_POST, 1);
$post_data = $post_data ? json_encode($post_data) : '';
curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
if( !empty($aHeader) ){
curl_setopt($curl, CURLOPT_HTTPHEADER, $aHeader);
}
curl_setopt($curl, CURLOPT_TIMEOUT, 120);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($curl);
$info = curl_getinfo($curl);
$error_no = curl_errno($curl);
$error_str = curl_error($curl);
curl_close($curl);
$result_array = json_decode($result,true);
return $result_array;
}
/**
* 蘋果驗單轉發方法
*
* apple地址:
* https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html
*
* @param $receipt 蘋果票據
* @param int $type 1:普通充值驗單 2:支持傳共享祕鑰驗單(不傳則默認取訂閱配置的祕鑰)
* @param null $url 請求地址
* @param null $pwd 共享祕鑰
* @return mixed
*/
public function apple_validation_url($receipt,$type=1, $url=null, $pwd = null)
{
$post_data['receipt-data'] = $receipt; //驗單票據
//增加共享祕鑰參數
if($type === 2){
$post_data['password'] = !empty($pwd) ? $pwd :$this->my_config['apple_shared_secret_key'];
$post_data['exclude-old-transactions'] = true; //true僅返回最新訂閱信息
}
$url = !empty($url) ? $url : "https://buy.itunes.apple.com/verifyReceipt"; //正式地址
$test_verify_url = "https://sandbox.itunes.apple.com/verifyReceipt"; //測試環境地址
$prod_verify_url = "https://buy.itunes.apple.com/verifyReceipt"; //生產環境地址
$result_validation_info = $this->post_receipt_data($post_data, $url);
switch ($result_validation_info['status']) {
case 0: //正常
break;
case 21006: //訂閱到期返回過期類票據
break;
case 21007: //沙盒模式的票據發送給了生產環境-重新轉發給到測試地址
$result_validation_info = $this->post_receipt_data($post_data, $test_verify_url);
break;
case 21008: //生產模式的票據發送給了測試環境-重新轉發給到正式地址
$result_validation_info = $this->post_receipt_data($post_data, $prod_verify_url);
break;
default: //記錄錯誤日誌
//todo 寫log彈出錯誤;
\Common::response_error_header(403,"verify fail");
}
return $result_validation_info;
}
/**
* 蘋果驗單數據解析(訂閱類型返回結構體)
* @param array $data 數據
* @param int $type 結構體類型 1普通支付驗單結構體 2訂閱首次支付驗單票據返回結構體 3apple訂閱回調票據返回結構體
* @return array
*/
public function apple_data_parsing(array $data = [],$type = 2)
{
if (empty($data)) return $data; //沒有數據
if ($data['status'] != 0 && $data['status'] != 21006) return $data; //status不等於0
$k= []; //返回結構體
switch ($type){
case 1: //普通驗單結構
$ks['status'] = $data['status'];
$ks['receipt'] = $data['receipt'];
unset($ks['receipt']['in_app']);
$ks['receipt']['in_app'][0] = $data['receipt']['in_app'][0];
//取in_app信息
$k = array_merge($ks,$data['receipt']['in_app'][0]);
break;
case 2:
$k['status'] = $data['status'];
$k['receipt'] = $data['receipt'];
unset($k['receipt']['in_app']);
$k['pending_renewal_info'] = $data['pending_renewal_info'];
//票據
if(isset($data['latest_receipt'])){
$k['latest_receipt'] = $data['latest_receipt'];
}
//如果存在值-降序取最新的數據-兼容返回全部訂閱信息
$latest = !empty($data['latest_receipt_info']) ? array_reverse($data['latest_receipt_info']) : [];
//產品id
if (isset($latest[0]['product_id'])) {
$k['product_id'] = $latest[0]['product_id'];
}
//事件id
if (isset($latest[0]['transaction_id'])) {
$k['transaction_id'] = $latest[0]['transaction_id'];
}
//原始事件id
if (isset($latest[0]['original_transaction_id'])) {
$k['original_transaction_id'] = $latest[0]['original_transaction_id'];
}
//到期時間
if (isset($latest[0]['expires_date_ms'])) {
$k['expires_date'] = floor($latest[0]['expires_date_ms'] / 1000); //轉換成時間戳 - 到期時間
}
//訂閱狀態
if (isset($data['pending_renewal_info'][0]['auto_renew_status'])) {
$k['auto_renew_status'] = $data['pending_renewal_info'][0]['auto_renew_status'];
}
break;
case 3:
$k['status'] = $data['status'];
$k['receipt'] = $data['receipt'];
//21006 apple返回到期票據返回結構體
if($data['status'] == 21006 && !empty($data['latest_expired_receipt_info'])){
$latest = $data['latest_expired_receipt_info'];
}else{
$latest = $data['latest_receipt_info'];
}
//票據
if(isset($data['latest_receipt'])){
$k['latest_receipt'] = $data['latest_receipt'];
}
//產品id
if (isset($data['auto_renew_product_id']['product_id'])) {
$k['product_id'] = $data['auto_renew_product_id']['product_id'];
}
//事件id
if (isset($latest['transaction_id'])) {
$k['transaction_id'] = $latest['transaction_id'];
}
//原始事件id
if (isset($latest['original_transaction_id'])) {
$k['original_transaction_id'] = $latest['original_transaction_id'];
}
//到期時間
if (isset($latest['expires_date'])) {
$k['expires_date'] = floor($latest['expires_date'] / 1000); //轉換成時間戳 - 到期時間
}
//訂閱狀態
if (isset($data['auto_renew_status'])) {
$k['auto_renew_status'] = $data['auto_renew_status'];
}
break;
default:
return $data;
}
return $k;
}
?>
回調方法:
/**
* ios訂閱回調
* ios_subscribe_callback
* @annotation 同一個蘋果appleID 購買的同一個商品的時 original_transaction_id 從始至終都是相同的
*/
public function iosSubscribeCallback()
{
$row_data = file_get_contents('php://input');
if($row_data){
$data = json_decode($row_data,true);
switch ($data){
case !empty($data['latest_receipt']): //最新票據
$latest_receipt = $data['latest_receipt'];
break;
case !empty($data['latest_expired_receipt']): //最新過期票據
$latest_receipt = $data['latest_expired_receipt'];
break;
default:
$latest_receipt = $data['latest_receipt'];
}
if(!empty($latest_receipt)){
//使用票據去蘋果驗單
$receipt_info = $this->apple_validation_url($latest_receipt,2);
$paper_a = $this->apple_data_parsing($receipt_info,3);
//返回狀態0 並且到期時間大於當前時間
if($paper_a['status']==0 || $paper_a['status']==21006){
//根據原始事件id查詢沒有關閉訂閱服務的追她用戶信息進行延期等操作
//到期時間大於存儲的到期時間
if($paper_a['expires_date'] > $y['end_time'] && $paper_a['auto_renew_status'] == 1){
//用戶續費成功
//todo 邏輯處理
}else{
//用戶取消訂閱狀態
if($paper_a['auto_renew_status']== 0){
//todo邏輯處理
}
}
}
}else{
\Common::response_error_header(403,'Invalid latest_receipt');
}
}else{
//無效數據
}
\Common::response_success_header(200);
exit;
}
注意:回調時候比較坑的是他放票據的鍵名不是一樣的。要對應取