PHP 蘋果內購訂閱驗單函數,及其訂閱回調處理案例

支付時拿到票據:

<?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;
    }

注意:回調時候比較坑的是他放票據的鍵名不是一樣的。要對應取

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章