Php/アプリストア連携/返金API/GooglePlayStore/RTDN
提供: 初心者エンジニアの簡易メモ
pub/subを使ってエンドポイント作成
- https://console.cloud.google.com/
- 上部の検索バーで「Pub/Sub」と入力し、「Cloud Pub/Sub」を選択
- 左側メニューで「トピック」をクリック
- 画面上部の「+トピックを作成」ボタンをクリック
- トピックIDに「play-refund-notifications」と入力
- 「作成」ボタンをクリック
- 例:projects/your-project-id/topics/play-refund-notifications のようなトピックが生成されることを確認。
pub/subのサブスクリプション作成
- Google Cloud ConsoleのPub/Subページに戻る
- 左メニューで「サブスクリプション」をクリック
- 画面上部の「+サブスクリプションを作成」ボタンをクリック
- サブスクリプション設定:
サブスクリプションID: play-refund-notifications-sub トピック名: play-refund-notifications (ドロップダウンから選択) 配信タイプ: 「Push」を選択 エンドポイントURL: https://yourdomain.com/notifications # 後で修正可能 確認期限: 60 (秒) 認証 (オプションですが推奨): 「Push認証を構成」を展開 「サービスアカウント」で適切なアカウントを選択
- 「作成」ボタンをクリック
Google Play Consoleでの設定
- Google Play Consoleにログイン
- GooglePlayで収益化する/収益化のセットアップを開く
- リアルタイム デベロッパー通知の、セクションで通知を受け取るエンドポイントのトピック名(例:projects/your-project-id/topics/play-refund-notifications)を設定
php実行準備
Firebase JWTを使用する場合
composer require firebase/php-jwt
phpサンプル
require_once 'vendor/autoload.php'; use phpseclib3\Crypt\PublicKeyLoader; // Google Playの公開鍵を取得(キャッシュ推奨) function getGooglePublicKey($keyId) { $jwksUrl = 'https://www.googleapis.com/oauth2/v3/certs'; // キャッシュの実装(上記と同じ) foreach ($jwks['keys'] as $key) { if ($key['kid'] === $keyId) { return PublicKeyLoader::load($key)->toString('PKCS8'); } } return null; } // JWTの検証 function verifyJwt($jwt) { list($header, $payload, $signature) = explode('.', $jwt); $header = json_decode(base64_decode($header), true); $payload = json_decode(base64_decode($payload), true); // 公開鍵を取得 $publicKey = getGooglePublicKey($header['kid']); if (!$publicKey) { return false; } // 署名検証 $data = "$header.$payload"; $signature = base64_decode(str_replace(['-', '_'], ['+', '/'], $signature)); $result = openssl_verify($data, $signature, $publicKey, 'SHA256'); return $result === 1 ? $payload : false; } // メイン処理 function handleRtdnNotification() { // リクエストボディを取得 $input = file_get_contents('php://input'); $data = json_decode($input, true); if (!$data || !isset($data['message']['data'])) { http_response_code(400); exit; } // JWTをデコード $jwt = base64_decode($data['message']['data']); $payload = verifyJwt($jwt); if (!$payload) { http_response_code(401); exit; } // 通知タイプに応じて処理 $notificationType = $payload['eventType']; $subscriptionId = $payload['subscriptionNotification']['subscriptionId']; $purchaseToken = $payload['subscriptionNotification']['purchaseToken']; switch ($notificationType) { case 'SUBSCRIPTION_CANCELED': // 定期購入がキャンセルされた handleSubscriptionCanceled($subscriptionId, $purchaseToken); break; case 'SUBSCRIPTION_PURCHASED': // 新しい定期購入 handleSubscriptionPurchased($subscriptionId, $purchaseToken); break; case 'SUBSCRIPTION_RENEWED': // 定期購入が更新された handleSubscriptionRenewed($subscriptionId, $purchaseToken); break; case 'SUBSCRIPTION_REVOKED': // 返金または管理者によるキャンセル handleSubscriptionRevoked($subscriptionId, $purchaseToken); break; case 'SUBSCRIPTION_RESTARTED': // ユーザーがキャンセル後に再開 handleSubscriptionRestarted($subscriptionId, $purchaseToken); break; default: // 未知の通知タイプ http_response_code(400); exit; } // 成功レスポンス http_response_code(200); } // 返金処理(SUBSCRIPTION_REVOKED) function handleSubscriptionRevoked($subscriptionId, $purchaseToken) { // 1. Google Play Developer APIを使用して購入情報を取得 $purchaseInfo = getSubscriptionPurchaseInfo($subscriptionId, $purchaseToken); // 2. 返金理由を確認 $revocationReason = $purchaseInfo['revocationReason'] ?? null; // 3. ユーザーアカウントを更新(アクセス権限を削除など) $userId = getUserIdFromPurchaseToken($purchaseToken); revokeUserAccess($userId); // 4. データベースに返金記録を保存 logRefund($userId, $subscriptionId, $purchaseToken, $revocationReason); // 5. 必要に応じてユーザーに通知 sendRefundNotification($userId); } // Google Play Developer APIから購入情報を取得 function getSubscriptionPurchaseInfo($subscriptionId, $purchaseToken) { // 実際にはここでGoogle Play Developer APIを呼び出す // 必要な認証情報などを設定 // 簡易実装(実際にはAPI呼び出しが必要) return [ 'revocationReason' => 1, // 1: 返金, 2: 管理者によるキャンセル // その他の購入情報... ]; } // その他のヘルパー関数... // メイン処理を実行 handleRtdnNotification();