欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【苹果内购】PHP支付结果验证

程序员文章站 2022-07-11 14:58:47
...

开发前推荐仔细看一下官方文档:

https://developer.apple.com/documentation/storekit/in-app_purchase

https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW2

支付的流程基本是客户端完成的,客户端完成支付后将支付凭证传给服务端,用作服务端向appStore服务端做支付结果校验用。

代码如下:

public function validateInAppStore(Request $request)
{
        try {
            $input = $this->validate($request, [
                'order_no'      => 'required|integer|min:1',
                'apple_receipt' => 'required|string',
                'transaction_id'=> 'required|integer|min:1',
                'is_sandbox'    => 'required|bool',
                'user_id'       => 'required|integer|min:1'
            ]);
        } catch (Exception $e) {
            return $this->failed();
        }

        $appleReceipt = [
            'receipt-data'  => $input['apple_receipt'],
        ];
        $model = new Apple();
        $res = $model->validateInAppStore($input['order_no'], $appleReceipt, $input['transaction_id'], $input['is_sandbox']);

        //验证通过或不通过后的业务代码
}
class Apple
{
    public function validateInAppStore($orderNo, $appleReceipt, $transactionId, $isSandbox=0)
    {

        if ($isSandbox){
            $url = config('apple.sandbox_url');
        }else{
            $url = config('apple.buy_url');
        }
        $res = json_decode(Func::curlPost($url, json_encode($appleReceipt)), true);

        if (0 == $res['status']){
            // 校验bundle_id
            if ($res['receipt']['bundle_id'] != config('apple.bundle_id')){
                return ["flag"=>false, "msg"=>"bundle ID不匹配"];
            }
            //校验订单
            $orderM = new OrderApi();
            $oRet = $orderM->appleProductId($orderNo);
            if (empty($oRet['rtdata']) || empty($oRet['rtdata']['apple_product_id'])){
                return ["flag"=>false, "msg"=>"订单信息不匹配"];
            }

            $productId = 0;
            foreach ($res['receipt']['in_app'] as $k=>$v){
                if ($transactionId == $v['transaction_id']){
                    $productId = $v['product_id'];
                }
            }
            //校验商品
            if ($oRet['rtdata']['apple_product_id'] != $productId){
                return ["flag"=>false, "msg"=>"商品ID不符"];
            }
        }else{
            switch ($res['status']){
                case 21000:
                    return ['flag'=>false, "msg"=>"App Store无法读取您提供的JSON对象。"];
                case 21002:
                    return ['flag'=>false, "msg"=>"receipt-data格式错误"];
                case 21003:
                    return ['flag'=>false, "msg"=>"验证失败"];
                case 21004:
                    return ['flag'=>false, "msg"=>"The shared secret you provided does not match the shared secret on file for your account."];
                case 21005:
                    return ['flag'=>false, "msg"=>"The receipt server is not currently available."];
                case 21007: {//This receipt is from the test environment
                    return self::validateInAppStore($orderNo, $appleReceipt, $transactionId, 1);
                }
                case 21008:{//This receipt is from the production environment
                    return self::validateInAppStore($orderNo, $appleReceipt, $transactionId, 0);
                }
                default:
                    return ['flag'=>false, "msg"=>"Internal data access error."];
            }
        }
        return [
            "flag"=>true,
            "msg"=>"支付成功"
        ];
    }