PHP怎么实现苹果支付自动续费

来源:编程学习作者:头衔:全栈工程师
导读:本期聚焦于小伙伴创作的《PHP怎么实现苹果支付自动续费》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《PHP怎么实现苹果支付自动续费》有用,将其分享出去将是对创作者最好的鼓励。

苹果支付的自动续费功能主要依托App Store的订阅机制实现,开发者需要在后端通过校验用户上传的支付收据,判断订阅的有效状态,同时处理自动续费后的状态更新逻辑。整个流程需要严格遵循苹果的官方校验规范,才能确保订阅状态判断的准确性。

PHP怎么实现苹果支付自动续费

苹果支付自动续费核心流程

实现苹果支付自动续费的核心逻辑可以分为以下几个步骤:

  • 客户端完成订阅支付后,将支付收据上传到开发者后端
  • 后端将收据发送到苹果官方校验接口进行验证
  • 解析苹果返回的校验结果,判断订阅的有效状态
  • 根据订阅的过期时间、自动续费状态等信息,更新用户在本地的订阅权益
  • 定期轮询校验即将过期的订阅,处理自动续费后的状态同步

收据校验接口说明

苹果提供了两个收据校验接口,分别是生产环境和沙盒环境,开发者需要根据实际情况选择对应的接口地址:

环境类型接口地址
生产环境https://buy.itunes.apple.com/verifyReceipt
沙盒环境https://sandbox.itunes.apple.com/verifyReceipt

校验请求需要传递两个核心参数:receipt-data是客户端上传的原始收据字符串,password是开发者在App Store Connect中配置的共享密钥,用于验证订阅类收据的合法性。

PHP实现收据校验代码

以下是PHP实现苹果收据校验的完整代码示例,包含请求发送、结果解析、错误处理等逻辑:

<?php
/**
 * 苹果支付收据校验类
 */
class ApplePayValidator
{
    // 生产环境校验地址
    const PRODUCTION_URL = 'https://buy.itunes.apple.com/verifyReceipt';
    // 沙盒环境校验地址
    const SANDBOX_URL = 'https://sandbox.itunes.apple.com/verifyReceipt';

    // 共享密钥,从App Store Connect获取
    private $sharedSecret;
    // 是否使用沙盒环境
    private $useSandbox;

    public function __construct($sharedSecret, $useSandbox = false)
    {
        $this->sharedSecret = $sharedSecret;
        $this->useSandbox = $useSandbox;
    }

    /**
     * 校验收据
     * @param string $receiptData 客户端上传的原始收据字符串
     * @return array 校验结果数组
     */
    public function validateReceipt($receiptData)
    {
        $url = $this->useSandbox ? self::SANDBOX_URL : self::PRODUCTION_URL;
        // 构造请求参数
        $postData = json_encode([
            'receipt-data' => $receiptData,
            'password' => $this->sharedSecret
        ]);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
        // 设置超时时间
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);

        $response = curl_exec($ch);
        $error = curl_error($ch);
        curl_close($ch);

        if ($error) {
            return [
                'success' => false,
                'message' => '请求苹果接口失败: ' . $error
            ];
        }

        $result = json_decode($response, true);
        // 状态码21007表示收据是沙盒环境的,需要切换到沙盒地址重新校验
        if (isset($result['status']) && $result['status'] == 21007 && !$this->useSandbox) {
            $this->useSandbox = true;
            return $this->validateReceipt($receiptData);
        }

        return $this->parseValidationResult($result);
    }

    /**
     * 解析苹果返回的校验结果
     * @param array $result 苹果返回的校验结果
     * @return array 解析后的订阅状态信息
     */
    private function parseValidationResult($result)
    {
        if (!isset($result['status']) || $result['status'] != 0) {
            return [
                'success' => false,
                'message' => '收据校验失败,状态码: ' . ($result['status'] ?? '未知')
            ];
        }

        $receipt = $result['receipt'] ?? [];
        $latestReceiptInfo = $result['latest_receipt_info'] ?? [];
        // 如果没有订阅信息,说明是普通一次性支付
        if (empty($latestReceiptInfo)) {
            return [
                'success' => true,
                'is_subscription' => false,
                'receipt' => $receipt
            ];
        }

        // 处理订阅信息,取最新的订阅记录
        $latestSubscription = end($latestReceiptInfo);
        $currentTime = time();
        $expiresDate = $latestSubscription['expires_date_ms'] / 1000;
        $isAutoRenew = $result['auto_renew_status'] == 1;

        return [
            'success' => true,
            'is_subscription' => true,
            'subscription_id' => $latestSubscription['product_id'],
            'expires_time' => $expiresDate,
            'is_expired' => $currentTime > $expiresDate,
            'is_auto_renew' => $isAutoRenew,
            'latest_receipt' => $result['latest_receipt'] ?? '',
            'raw_data' => $result
        ];
    }
}

// 使用示例
$sharedSecret = 'your_shared_secret_from_app_store_connect';
$validator = new ApplePayValidator($sharedSecret, true); // 测试阶段使用沙盒环境
$receiptData = $_POST['receipt_data'] ?? ''; // 获取客户端上传的收据
$validationResult = $validator->validateReceipt($receiptData);

if ($validationResult['success']) {
    if ($validationResult['is_subscription']) {
        // 处理订阅逻辑
        $userId = 1; // 当前用户ID
        $expiresTime = $validationResult['expires_time'];
        $isAutoRenew = $validationResult['is_auto_renew'];
        // 这里可以将订阅信息更新到数据库,比如记录用户订阅过期时间、自动续费状态等
        echo '订阅校验成功,过期时间: ' . date('Y-m-d H:i:s', $expiresTime);
    } else {
        echo '普通支付校验成功';
    }
} else {
    echo '校验失败: ' . $validationResult['message'];
}
?>

自动续费状态同步处理

除了用户主动触发收据校验之外,开发者还需要处理苹果自动续费后的状态同步,主要有两种方式:

1. 轮询校验机制

可以在数据库中记录所有订阅用户的过期时间,定期(比如每天)查询即将过期的订阅用户,重新拉取用户的收据进行校验,判断是否已经自动续费。如果校验后发现过期时间延长,说明已经完成了自动续费,更新本地的订阅状态即可。

2. App Store服务器通知

苹果提供了App Store服务器通知功能,开发者可以在App Store Connect中配置通知接收地址,当订阅状态发生变化(比如自动续费成功、用户取消订阅、退款等)时,苹果会主动推送通知到开发者的服务器,开发者接收到通知后可以直接更新对应的订阅状态,这种方式比轮询更高效也更及时。

注意事项

  • 共享密钥需要妥善保管,不要泄露到客户端代码中
  • 收据校验时如果返回21007状态码,需要自动切换到沙盒环境重新校验,避免测试环境的收据校验失败
  • 订阅的过期时间是毫秒级时间戳,解析时需要注意单位转换
  • 自动续费状态可能会被用户手动关闭,需要定期校验确认最新的自动续费状态
  • 沙盒环境的测试订阅会自动快速续费,方便开发者测试自动续费逻辑,生产环境会按照实际的订阅周期续费
苹果支付的校验规则可能会更新,开发过程中建议定期查看苹果官方的订阅校验文档,确保逻辑符合最新的规范要求。

PHP苹果支付自动续费App_Store_Receipt_Validation修改时间:2026-07-06 03:54:30

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。