如何关联PayPal WebHook与用户?PHP SDK订阅场景技术问询
嘿,看你描述的情况,应该是卡在跳转页面的EC Token和WebHook事件的关联上了吧?你已经走通了核心流程:通过PayPal PHP SDK生成计费协议,用户授权后跳回你的/paypal-success?success=true&token=EC-3K353628LH3197445页面,还配置了BILLING.SUBSCRIPTION.CREATED(你给的JSON里事件类型写的是BILLING.SUBSCRIPTIO,应该是手滑打漏了)的WebHook,但总觉得漏了个简单细节——我给你梳理几个关键点:
1. 先把WebHook事件类型补对
你提供的WebHook JSON里event_type字段不完整,正确的订阅创建事件类型是BILLING.SUBSCRIPTION.CREATED,先确认WebHook配置里的事件类型是不是选对了,不然可能收不到正确的推送。
2. 用EC Token关联WebHook里的订阅协议
当用户跳回你的paypal-success页面时,你手里的EC-XXX token是关键——用它调用PayPal SDK的协议详情接口,就能拿到完整的Agreement对象,和WebHook推送的资源关联起来:
// 基于PayPal PHP SDK的示例代码 $apiContext = new \PayPal\Rest\ApiContext( new \PayPal\Auth\OAuthTokenCredential( '你的客户端ID', '你的客户端密钥' ) ); $agreement = new \PayPal\Api\Agreement(); try { // 用跳转URL里的token获取协议详情 $agreement->get($_GET['token'], $apiContext); // 拿到协议ID,后续和WebHook的resource.id对应 $agreementId = $agreement->getId(); // 顺便确认协议状态,比如是否是APPROVED/ACTIVE $agreementStatus = $agreement->getStatus(); } catch (\PayPal\Exception\PayPalConnectionException $ex) { // 处理请求异常,比如打印错误信息 error_log($ex->getData()); }
拿到这个agreementId,就能和WebHook推送过来的resource.id匹配上,这样你就能把用户跳转回来的请求和WebHook事件关联,更新自己系统里的用户订阅记录。
3. 跳转页面的兜底校验不能少
别光等着WebHook推送,因为WebHook可能有延迟甚至丢失的情况。在paypal-success页面,你得:
- 先校验
success=true的合法性,别接收到恶意请求 - 调用上面的接口确认协议状态是正常的(比如
APPROVED),确保订阅真的创建成功 - 把协议信息同步到自己的数据库,作为订阅生效的兜底依据
4. WebHook的签名验证必须做
收到WebHook推送的JSON后,第一时间要验证签名,确保是PayPal官方发的,别被伪造事件坑了:
// WebHook签名验证的示例代码 $rawPostData = file_get_contents('php://input'); $transmissionId = $_SERVER['HTTP_PAYPAL_TRANSMISSION_ID']; $transmissionTime = $_SERVER['HTTP_PAYPAL_TRANSMISSION_TIME']; $transmissionSig = $_SERVER['HTTP_PAYPAL_TRANSMISSION_SIG']; $webhookId = $_SERVER['HTTP_PAYPAL_WEBHOOK_ID']; try { $webhookEvent = \PayPal\Api\WebhookEvent::validateAndGetReceivedEvent( $rawPostData, $transmissionId, $transmissionTime, $transmissionSig, $webhookId, $apiContext ); // 验证通过后再处理事件 $subscriptionResource = $webhookEvent->getResource(); $subscriptionId = $subscriptionResource->getId(); // 这里可以根据subscriptionId更新自己的订阅记录 } catch (\PayPal\Exception\PayPalInvalidCredentialException $ex) { // 签名验证失败,记录日志并忽略请求 error_log('WebHook签名验证失败: ' . $ex->getMessage()); }
你说的“遗漏极其简单的细节”,大概率就是没把跳转时的EC Token和WebHook里的订阅ID做关联,或者没在跳转页面主动校验协议状态——试试上面的步骤,应该能解决你的问题。
内容的提问来源于stack exchange,提问作者Mr J

