苹果内购-后端注意事项

老大要收保护费,我等小弟那也没办法呀。。。是的,我说的就是苹果内购!

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验证

你可能感兴趣的:(php)