PHP实现PayPal IPN返回INVALID问题求助
解决PayPal IPN监听器的连接与验证问题
嘿,我来帮你搞定这个IPN的问题!从你的描述来看,核心问题主要出在沙箱环境的端点地址使用错误以及fsockopen的调用方式上,咱们一步步来修正:
首先明确正确的PayPal IPN端点
PayPal在2018年后确实更新了IPN的端点,现在沙箱和生产环境的正确地址是:
- 沙箱环境:
ipnpb.sandbox.paypal.com(端口443,SSL加密) - 生产环境:
ipnpb.paypal.com(端口443,SSL加密)
你之前的错误在于:
- 用
https://www.sandbox.paypal.com或者带完整路径的URL作为fsockopen的主机参数——fsockopen只需要主机名,不能带协议前缀(https://)或路径 - 混淆了沙箱和生产环境的地址,用生产地址
www.paypal.com测试沙箱IPN,自然会返回INVALID
修正后的fsockopen代码实现
这里给你调整好的沙箱环境IPN验证代码,注释里标注了生产环境的切换方式:
<?php // 发送200响应,避免PayPal重复发送通知 header('HTTP/1.1 200 OK'); // 构造验证请求参数 $resp = 'cmd=_notify-validate'; foreach ($_POST as $parm => $var) { $var = urlencode(stripslashes($var)); $resp .= "&$parm=$var"; } // 沙箱环境配置(生产环境把主机换成ipnpb.paypal.com即可) $host = 'ssl://ipnpb.sandbox.paypal.com'; $port = 443; $errno = ''; $errstr = ''; // 建立SSL连接 $fh = fsockopen($host, $port, $errno, $errstr, 30); if (!$fh) { // 连接失败,记录错误信息到日志 error_log("IPN连接失败: $errstr ($errno)"); } else { // 构造HTTP请求头 $httphead = "POST /cgi-bin/webscr HTTP/1.1\r\n"; $httphead .= "Host: ipnpb.sandbox.paypal.com\r\n"; // 生产环境换成ipnpb.paypal.com $httphead .= "Content-Type: application/x-www-form-urlencoded\r\n"; $httphead .= "Content-Length: " . strlen($resp) . "\r\n"; $httphead .= "Connection: Close\r\n\r\n"; // 发送验证请求 fputs($fh, $httphead . $resp); // 读取PayPal响应 while (!feof($fh)) { $readresp = fgets($fh, 1024); $trimmedResp = trim($readresp); if ($trimmedResp === "VERIFIED") { // IPN验证通过,处理业务逻辑(比如更新订单状态) error_log("IPN验证成功"); } elseif ($trimmedResp === "INVALID") { // IPN验证失败,记录日志并排查原因 error_log("IPN验证失败"); } } fclose($fh); } ?>
额外的排查建议
- 强制使用沙箱环境:测试时确保所有配置(包括IPN模拟器、你的代码端点)都指向沙箱,不要和生产环境混着用
- 改用cURL替代fsockopen:有些服务器会禁用fsockopen,cURL的兼容性更好,这里给你简化的cURL版本:
<?php header('HTTP/1.1 200 OK'); $resp = 'cmd=_notify-validate' . '&' . file_get_contents('php://input'); $ch = curl_init('https://ipnpb.sandbox.paypal.com/cgi-bin/webscr'); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $resp); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_FORBID_REUSE, true); $response = curl_exec($ch); if (trim($response) === 'VERIFIED') { // 验证通过 } else { // 验证失败 } curl_close($ch); ?> - 检查服务器日志:连接失败时,把
$errno和$errstr的值记录到日志,能帮你快速定位是防火墙、SSL配置还是网络问题 - 验证IPN模拟器的参数:确保模拟器里填写的回调URL是公开可访问的,并且能接收POST请求
内容的提问来源于stack exchange,提问作者Parapluie
相关产品推荐
相关产品推荐

