定制 aporat/store-receipt-validator 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

aporat/store-receipt-validator

Composer 安装命令:

composer require aporat/store-receipt-validator

包简介

PHP receipt validator for Apple App Store and Amazon Appstore

README 文档

README

Latest Stable Version Downloads Codecov GitHub Actions License

A modern PHP library for validating in-app purchase receipts from the Apple App Store (including legacy iTunes) and Amazon Appstore. Supports both production and sandbox environments with detailed response parsing.

✨ Features

  • ✅ Apple App Store Server API (v2) support
  • ✅ Apple iTunes Legacy API support (deprecated by Apple, still available here)
  • ✅ Amazon Appstore receipt validation
  • ✅ App Store Server Notifications v1 & v2 parsing
  • ✅ Strong typing (PHP 8.4+), enums, and modern error handling
  • ✅ PSR-3 compatible logging support
  • ✅ Built-in test suite with 100% coverage

📦 Requirements

  • PHP >= 8.4

📥 Installation

composer require aporat/store-receipt-validator

🚀 Quick Start

📲 Apple App Store Server API

use ReceiptValidator\AppleAppStore\ReceiptUtility;
use ReceiptValidator\AppleAppStore\Validator as AppleValidator;
use ReceiptValidator\Environment;

// Credentials
$signingKey = file_get_contents($root . '/examples/SubscriptionKey_RA9DAYVX3X.p8');
$keyId = 'RA9DAYVX3X';
$issuerId = 'xxxxxx-xxxx-xxxx-xxxx-xxxxxxx';
$bundleId = 'com.myapp';

$receiptBase64Data = '...'; // your app receipt here

// 🔑 Tip: Apple's Server API does not accept the full app receipt.
// Use ReceiptUtility to extract the latest transaction ID.
$transactionId = ReceiptUtility::extractTransactionIdFromAppReceipt($receiptBase64Data);

$validator = new AppleValidator(
    signingKey: $signingKey,
    keyId: $keyId,
    issuerId: $issuerId,
    bundleId: $bundleId,
    environment: Environment::PRODUCTION
);

try {
    $response = $validator->getTransactionHistory($transactionId);
} catch (ValidationException $e) {
    if ($e->getCode() === APIError::INVALID_TRANSACTION_ID) {
        echo "Invalid Transaction ID: {$e->getMessage()}" . PHP_EOL;
    } else {
        echo "Validation failed: {$e->getMessage()}" . PHP_EOL;
    }

    exit(1);
} catch (Exception $e) {
    echo 'Error validating transaction: ' . $e->getMessage() . PHP_EOL;
    exit(1);
}

echo 'Validation successful.' . PHP_EOL;
echo 'Bundle ID: ' . $response->getBundleId() . PHP_EOL;
echo 'App Apple ID: ' . $response->getAppAppleId() . PHP_EOL;

foreach ($response->getTransactions() as $transaction) {
    echo 'Product ID: ' . $transaction->getProductId() . PHP_EOL;
    echo 'Transaction ID: ' . $transaction->getTransactionId() . PHP_EOL;

    if ($transaction->getPurchaseDate() !== null) {
        echo 'Purchase Date: ' . $transaction->getPurchaseDate()->toIso8601String() . PHP_EOL;
    }
}

ℹ️ Validator::validate() is deprecated as of v9. Use getTransactionHistory() for paginated history, or getTransactionInfo() for a single signed transaction.

📚 Other App Store Server API endpoints

The AppleAppStore\Validator now covers Apple's full API surface:

Area Methods
Transactions getTransactionHistory(), getTransactionInfo(), getAppTransactionInfo(), finishTransaction(), setAppAccountToken(), sendConsumptionInformation()
Order / refunds lookUpOrderId(), getRefundHistory()
Subscriptions getAllSubscriptionStatuses(), extendSubscriptionRenewalDate(), extendSubscriptionRenewalDatesForAllActiveSubscribers(), getStatusOfSubscriptionRenewalDateExtensions()
Notifications requestTestNotification(), getTestNotificationStatus(), getNotificationHistory()

Each returns a typed response object (Transaction, AppTransaction, SubscriptionStatusResponse, RefundHistoryResponse, NotificationHistoryResponse, …). See the App Store Server API docs for endpoint semantics.

🍏 Apple iTunes (Legacy API - Deprecated)

use ReceiptValidator\Environment;
use ReceiptValidator\iTunes\Validator as iTunesValidator;

$validator = new ITunesValidator($sharedSecret, Environment::PRODUCTION);

try {
    $response = $validator->setReceiptData('BASE64_RECEIPT')->validate();
} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
    echo $e->getTraceAsString() . PHP_EOL;
    exit;
}

echo 'Bundle ID: ' . $response->getBundleId() . PHP_EOL;
echo 'Original Purchase Date: ' . $response->getOriginalPurchaseDate()?->toIso8601String() . PHP_EOL;

foreach ($response->getTransactions() as $tx) {
    echo 'Product ID: ' . $tx->getProductId() . PHP_EOL;
    echo 'Transaction ID: ' . $tx->getTransactionId() . PHP_EOL;
    echo 'Original Transaction ID: ' . ($tx->getOriginalTransactionId() ?? 'N/A') . PHP_EOL;

    if ($tx->getPurchaseDate() !== null) {
        echo 'Purchase Date: ' . $tx->getPurchaseDate()?->toIso8601String() . PHP_EOL;
    }
    if ($tx->getExpiresDate() !== null) {
        echo 'Expires Date: ' . $tx->getExpiresDate()?->toIso8601String() . PHP_EOL;
    }
}

foreach ($response->getLatestReceiptInfo() as $tx) {
    echo 'Latest — Product ID: ' . $tx->getProductId() . PHP_EOL;
    echo 'Latest — Transaction ID: ' . $tx->getTransactionId() . PHP_EOL;

    if ($tx->getPurchaseDate() !== null) {
        echo 'Latest — Purchase Date: ' . $tx->getPurchaseDate()?->toIso8601String() . PHP_EOL;
    }
    if ($tx->getExpiresDate() !== null) {
        echo 'Latest — Expires Date: ' . $tx->getExpiresDate()?->toIso8601String() . PHP_EOL;
    }
}

🛒 Amazon Appstore

use ReceiptValidator\Amazon\Validator;

$validator = new Validator();

try {
    $response = $validator
        ->setDeveloperSecret('SECRET')
        ->setReceiptId('RECEIPT_ID')
        ->setUserId('USER_ID')
        ->validate();
} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
    echo $e->getTraceAsString() . PHP_EOL;
    exit;
}

echo 'Receipt is valid.' . PHP_EOL;

foreach ($response->getTransactions() as $transaction) {
    echo 'Product ID: ' . $transaction->getProductId() . PHP_EOL;

    if ($transaction->getPurchaseDate() !== null) {
        echo 'Purchase Date: ' . $transaction->getPurchaseDate()->toIso8601String() . PHP_EOL;
    }
}

📋 Logging

All validators support PSR-3 compatible logging via setLogger(). By default, a NullLogger is used so no output is produced unless you inject a logger.

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('receipt-validator');
$logger->pushHandler(new StreamHandler('php://stdout'));

$validator = new AppleValidator($signingKey, $keyId, $issuerId, $bundleId);
$validator->setLogger($logger);

The method returns $this for fluent chaining:

$response = $validator
    ->setLogger($logger)
    ->getTransactionHistory($transactionId);

Log levels

Level Events
DEBUG Outgoing API request details (environment, URI, parameters)
INFO Successful responses; environment retries (e.g. production → sandbox)
WARNING API error responses, unexpected HTTP status codes
ERROR Network/connection failures

📬 Apple App Store Server Notifications

🔔 V2 Notifications (App Store Server API)

use ReceiptValidator\AppleAppStore\ServerNotification;
use ReceiptValidator\Exceptions\ValidationException;

public function subscriptions(Request $request): JsonResponse {
    try {
        $notification = new ServerNotification($request->all());

        echo 'Type: ' . $notification->getNotificationType()->value . PHP_EOL;
        echo 'Subtype: ' . ($notification->getSubtype()?->value ?? 'N/A') . PHP_EOL;
        echo 'Bundle ID: ' . $notification->getBundleId() . PHP_EOL;

        $tx = $notification->getTransaction();
        if ($tx !== null) {
            echo 'Transaction ID: ' . $tx->getTransactionId() . PHP_EOL;
        }

        $renewalInfo = $notification->getRenewalInfo();
        if ($renewalInfo !== null) {
            echo 'Auto-Renew Product ID: ' . $renewalInfo->getAutoRenewProductId() . PHP_EOL;
        }
    } catch (ValidationException $e) {
        echo 'Invalid notification: ' . $e->getMessage() . PHP_EOL;
    }
}

🔔 V1 Notifications (iTunes - Deprecated)

use ReceiptValidator\iTunes\ServerNotification;
use ReceiptValidator\Exceptions\ValidationException;

public function subscriptions(Request $request): JsonResponse {
    $sharedSecret = 'your_shared_secret';

    try {
        $notification = new ServerNotification($request->all(), $sharedSecret);

        echo 'Type: ' . $notification->getNotificationType()->value . PHP_EOL;
        echo 'Bundle ID: ' . $notification->getBundleId() . PHP_EOL;

        $transactions = $notification->getLatestReceipt()->getTransactions();

        foreach ($transactions as $tx) {
            echo 'Transaction ID: ' . $tx->getTransactionId() . PHP_EOL;
        }
    } catch (ValidationException $e) {
        echo 'Invalid notification: ' . $e->getMessage() . PHP_EOL;
    }
}

🧪 Testing

composer test        # Run tests with PHPUnit
composer lint        # Run code style checks with PHP_CodeSniffer
composer analyze     # Run static analysis with PHPStan

🙌 Contributing

Contributions are welcome!
To get started:

  1. Fork this repo
  2. Create a feature branch
  3. Submit a pull request

Found a bug or want a new feature? Open an issue

📄 License

Apache-2.0 License. See LICENSE.

aporat/store-receipt-validator 适用场景与选型建议

aporat/store-receipt-validator 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 3.97M 次下载、GitHub Stars 达 650, 最近一次更新时间为 2014 年 03 月 16 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「php」 「apple」 「itunes」 「Receipt Validation」 「iap」 「In-App Purchase」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 aporat/store-receipt-validator 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 aporat/store-receipt-validator 我们能提供哪些服务?
定制开发 / 二次开发

基于 aporat/store-receipt-validator 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 3.97M
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 653
  • 点击次数: 33
  • 依赖项目数: 8
  • 推荐数: 0

GitHub 信息

  • Stars: 650
  • Watchers: 20
  • Forks: 151
  • 开发语言: PHP

其他信息

  • 授权协议: Apache-2.0
  • 更新时间: 2014-03-16