当使用cmd = _notify-validate验证IPN时,我偶尔会收到一个既不是'VERIFIED'也不是'INVALID'的隐式响应代码,而是二进制的并且难以理解。但是,此行为无法预测地发生,并且稍后完全相同的对notify-validate的调用将产生有效的响应。这种情况已经间歇性地发生了多年,但我始终无法弄清楚问题出在哪里。是PayPal的问题,代码中的错误还是我没有考虑的其他问题?
由于这种情况是间歇性发生的,并且相同的请求稍后会成功执行,因此,我通过排队并重新验证所有未返回PayPal明确响应的交易来解决此问题。这样做可以解决,但并不是最佳的工作流程,尤其是随着事务数量的增加。
public static function Verify() {
$start = "url=members/ipn&";
$errno = $errstr = null;
$req = 'cmd=_notify-validate';
foreach($_REQUEST as $key => $value) {
if(!is_array($value)) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
}
}
$verified = false;
$fp = fsockopen("ssl://www.paypal.com", 443, $errno, $errstr, 30);
if(!$fp) {
Paypal::Log("ERROR", "Failed connecting to PayPal:$errstr ($errno)\n");
}
else {
if($errno || $errstr) {
Paypal::Log("ERROR", $errno.":".$errstr);
}
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Host:".$host."\r\n";
$header .= "Connection: clost\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: ".strlen($req)."\r\n\r\n";
fputs($fp, $header.$req);
$header = true;
while(!feof($fp)) {
$res = trim(fgets($fp, 4096));
if(strlen($res) == 0) {
$header = false;
continue;
}
if($header) {
continue;
}
if(strcmp($res, "VERIFIED") == 0) {
$verified = true;
break;
}
else {
$verified = false;
break;
}
}
}
fclose($fp);
return $verified;
}
此代码的大多数响应都以纯文本格式(在$ res var中)返回“ VERIFIED”,但有时会失败并返回看起来是二进制字符的内容。我什至不能将响应粘贴到这里,因为它们都是非文本字符并且难以理解。
要注意的另一件事是fsockopen正在运行,并且不会产生任何错误。只是$ res有时其中包含未知数据。
-更新1-
根据建议,我将验证过程切换为使用cURL,并遵循了PayPal的建议准则。
$ch = curl_init('https://ipnpb.paypal.com/cgi-bin/webscr');
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSLVERSION, 6);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . "/cert/cacert.pem");
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'User-Agent: PHP-IPN-Verification-Script',
'Connection: Close',
));
if ( !($res = curl_exec($ch)) ) {
Paypal::Log("cURL Error:", curl_error($ch));
curl_close($ch);
exit;
}
curl_close($ch);
$info = curl_getinfo($ch);
$http_code = $info['http_code'];
if ($http_code != 200) {
Paypal::Log("HTTP Code:", $http_code);
}
Paypal::Log("Response", $res);
if(strcmp($res, "VERIFIED") == 0) {
$verified = true;
}
else {
$verified = false;
}
大多数情况下都可以正常工作,但是间歇性问题仍然存在,偶尔验证尝试会返回不同的响应。
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
</body></html>
在进行完全相同的调用以验证交易时,它可以工作。所以我只是不明白为什么有时会出现此400 Bad Request错误。有什么想法吗?
答案 0 :(得分:0)
在您的代码中显示如何获得$ req-400错误听起来像是您在PayPal不希望(或可能不发送)的某个地方抓了一些垃圾。
几年前(几年),我选择了这个,但它从未失败过。...-也许提到的“问题”就是您所看到的。
// Read POST data
// reading posted data directly from $_POST causes serialization
// issues with array data in POST. Reading raw POST data from input stream instead.
$raw_post_data = file_get_contents('php://input');
$raw_post_array = explode('&', $raw_post_data);
$post = array();
foreach ($raw_post_array as $keyval) {
$keyval = explode('=', $keyval);
if (count($keyval) == 2)
$post[$keyval[0]] = urldecode($keyval[1]);
}
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
foreach ($post as $key => $value) {
$value = urlencode(addslashes($value));
$req .= "&$key=$value";
}
希望这会有所帮助!