При проверке IPN с использованием cmd = _notify-validate я иногда получаю зашифрованный код ответа, который не является ни «VERIFIED», ни «INVALID», но вместо этого кажется двоичным и неразборчивым. Однако такое поведение происходит непредсказуемо, и точно такой же вызов для уведомления-проверки позже даст действительный ответ. Это происходило с перерывами в течение многих лет, и я никогда не мог понять, где проблема. Это будет что-то с 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), но иногда происходит сбой и возвращает то, что выглядит как двоичные символы. Я даже не могу вставить здесь ответ, потому что это все нетекстовые символы и неразборчиво.
Еще одна вещь, на которую следует обратить внимание, это то, что 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. Есть идеи?