我知道这已经被问过几次了,但是没有一个解决方案对我有效。我正在使用paypal (https://developer.paypal.com/webapps/developer/applications/ipn_simulator)的即时支付通知(IPN)模拟器,但我总是收到: PayPal异常响应:HTTP/1.1 400 Bad Request
<?php
//Open a socket for the acknowledgement request
$fp = fsockopen (ssl://www.sandbox.paypal.com, 443, $errno, $errstr, 30);
if (!$fp) {
// fsockopen error
throw new Exception("An error occured while using fsockopen(): [$errno] $errstr");
}
//Set up the acknowledgement request headers
$header .= "POST /cgi-bin/webscr HTTP/1.1rn";
$header .= "Host: ssl://www.sandbox.paypal.comrn";
$header .= "Content-Type: application/x-www-form-urlencodedrn";
$header .= "Content-Length: ".strlen($data)."rn";
$header .= "Connection: Closernrn";
// Post request back to PayPal for validation
fputs ($fp, $header . $data);
while (!feof($fp)) { // While not EOF
$res = fgets ($fp, 1024); // Get the acknowledgement response
if (strcmp ($res, "VERIFIED") == 0) { // Response is VERIFIED
$response = 'verified';
}
else if (strcmp ($res, "INVALID") == 0) { // Response is INVALID
$response = 'invalid';
}
else {
throw new Exception("Unexpected response from PayPal: $res");
}
}
编辑:后改变
$header .= "Host: ssl://www.sandbox.paypal.comrn";
$header .= "Host: www.sandbox.paypal.comrn";
我现在收到一个HTTP/1.1 200 OK响应。另一个问题是,我的if()部分不工作,它总是跳到最后一个
else {
throw new Exception("Unexpected response from PayPal: $res");
}
if (strcmp ($res, "VERIFIED") == 0)
有什么问题吗?
这是我的完整代码。也许有人能发现错误:
class Paypal {
protected $sandbox = false;
protected $data = null;
const SANDBOX_URL = 'www.sandbox.paypal.com';
const PAYPAL_URL = 'www.paypal.com';
public function __construct($sandbox = false) {
$this->sandbox = $sandbox;
}
public function receiveData() {
if (empty($_POST)) {
throw new Exception('No $_POST data found');
}
$this->data = $_POST;
// Read the notification from PayPal and create the acknowledgement response
$req = 'cmd=_notify-validate'; // add 'cmd' to beginning of the acknowledgement you send back to PayPal
foreach ($_POST as $key => $value) { // Loop through the notification NV pairs
$value = urlencode(stripslashes($value)); // Encode the values
$req .= "&$key=$value"; // Add the NV pairs to the acknowledgement
}
if ($this->fsock($req))
return true;
else
return false;
}
public function getData() {
return $this->data;
}
private function fsock($data) {
//Open a socket for the acknowledgement request
$fp = fsockopen ('ssl://'.$this->getURL(), 443, $errno, $errstr, 30);
if (!$fp) {
// fsockopen error
throw new Exception("An error occured while using fsockopen(): [$errno] $errstr");
}
//Set up the acknowledgement request headers
$header .= "POST /cgi-bin/webscr HTTP/1.1rn";
$header .= "Host: ".$this->getURL()."rn";
$header .= "Content-Type: application/x-www-form-urlencodedrn";
$header .= "Content-Length: ".strlen($data)."rn";
$header .= "Connection: Closernrn";
// Post request back to PayPal for validation
fputs ($fp, $header . $data);
while (!feof($fp)) { // While not EOF
$res = fgets ($fp, 1024); // Get the acknowledgement response
if (strcmp ($res, "VERIFIED") == 0) { // Response is VERIFIED
$response = 'verified';
// Notification protocol is complete, OK to process notification contents
// Possible processing steps for a payment might include the following:
// Check that the payment_status is Completed
// Check that receiver_email is your Primary PayPal email
// Check that payment_amount/payment_currency are correct
// Process payment
}
else if (strcmp ($res, "INVALID") == 0) { // Response is INVALID
$response = 'invalid';
}
else {
throw new Exception("Unexpected response from PayPal: $res");
}
}
fclose ($fp); //close file pointer
if ($response == 'verified')
return true;
else
return false;
}
private function getURL() {
if ($this->sandbox)
return self::SANDBOX_URL;
else
return self::PAYPAL_URL;
}
}
$paypal = new Paypal(true);
try {
if ($paypal->receiveData()) {
// success
}
else {
// fail
}
}
catch (Exception $e) {
// exception
echo 'Exception: ', $e->getMessage(), "n";
}
您的脚本似乎存在许多问题。例如,$data没有初始化,因此您没有发布任何内容。但你得到400错误的原因是头美元。= "主持人:ssl://www.sandbox.paypal.com r n";
应为
头美元。= "主持人:www.sandbox.paypal.com r n";
我维护一些当前的IPN程序,在我看来,您读取数据的方法不太可能从PayPal获得完整的响应。TCP数据是以包的形式发送的,PayPal的响应不是作为一个缓冲区发送的,所以实际上一次读取不太可能包含尽可能多的字节,达到请求的1024字节。
为了在您自己的代码中实现,您必须循环并附加到您读取的变量,直到到达EOF。
你也可以看看下面的PHP示例代码:
https://www.x.com/developers/PayPal/documentation-tools/code-sample/216623 我想我现在明白你的错误了。您的fgets语句一次只读取响应的一行,因为当到达长度或到达换行符时,它会停止读取,以先到的为准。您要查找的行是在Pay Pal的响应正文中,而不是在前几行(标题等)中。然而,else语句包含在循环中。因此,一旦从PayPal收到标题的第一行,就总是执行else语句。我建议做两个改变。将失败代码移到循环之后,因为在达到EOF之前,实际上无法确定是否发生了失败。
我建议的另一个更改是使用strpos而不是strcmp。虽然paypal响应体只包含一个单词验证,有一个很好的机会,CR或LF或两者将是该行的一部分,忘记读取。因此,紧缩政策将会失败。您可以使用条件strpos ($res, "VERIFIED") !== false
来代替您现有的条件(并使用相同的更改来检查是否收到了INVALID)。
这是一些可能的可能工作的代码(我无法在您的情况下测试此代码,并且未经测试的代码永远无法确保工作)。请将这段代码作为建议,而不是字面上的答案:
// Post request back to PayPal for validation
fputs ($fp, $header . $data);
while (!feof($fp)) { // While not EOF
$res = fgets ($fp, 1024); // Get the acknowledgement response
if (strpos ($res, "VERIFIED") !== false) { // Response is VERIFIED
$response = 'verified';
// Notification protocol is complete, OK to process notification contents
// Possible processing steps for a payment might include the following:
// Check that the payment_status is Completed
// Check that receiver_email is your Primary PayPal email
// Check that payment_amount/payment_currency are correct
// Process payment
break;
}
else if (strpos ($res, "INVALID") !== false) { // Response is INVALID
$response = 'invalid';
break;
}
}
fclose ($fp); //close file pointer
if ($response == 'verified')
return true;
else if ($response == 'invalid') {
return false;
}
else { // no else statement is actually needed here,
// since the previous conditions both return
throw new Exception("Unexpected response from PayPal: $res");
return false;
}
你的If语句是正确的,所有你需要做的就是打印你正在检查的值针对头/尾字符的"VERIFIED":复制下面的代码到else块中:
var_dump($res) ; die;
所以你可以看到你得到了什么:)
套接字级HTTP通信使您的代码非常容易出错。我建议你使用像cURL这样的HTTP客户端库,它将为你处理请求/响应周期,跟踪潜在的重定向和读写头/尾。
请清理浏览器缓存或重新启动浏览器。