更新:2016 年 1 月 7 日
我注意到以下内容对于 tls://www.sandbox.paypal.com 非常有效,但是当您上线 tls://www.paypal.com 时,连接被拒绝!(它不起作用)我发现问题出在标题中,沙箱和生产级别的 live paypal 需要不同的标题!这是一个错误,但要让它在生产级别和沙箱中工作,请分别使用这些标头:
生产级别(实时 PayPal 标头):
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
沙盒 PayPal 标头:
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Host: www.paypal.com\r\n";
$header .= "Accept: */*\r\n";
$header .= "Connection: Close\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "\r\n";
* 下面的代码是相同的,它工作正常,只需分别替换标题。*
这是其余的代码(和答案):
我在这里和那里检查了所有答案,以使其在 2016 年 1 月 5 日生效。他们都有优点,但不适用于整体情况。
所以首先,这是实际工作的完整代码,然后我将通过它:
<?php
// =========================================================================
// PayPal Official PHP Codes and Tutorial:
// https://developer.paypal.com/webapps/developer/docs/classic/ipn/gs_IPN/
// =========================================================================
// Send an empty HTTP 200 OK response to acknowledge receipt of the notification
header('HTTP/1.1 200 OK');
// Assign payment notification values to local variables
$item_name = $_POST['item_name'];
$item_number = $_POST['item_number'];
$payment_status = $_POST['payment_status'];
$payment_amount = $_POST['mc_gross'];
$payment_currency = $_POST['mc_currency'];
$txn_id = $_POST['txn_id'];
$receiver_email = $_POST['receiver_email'];
$payer_email = $_POST['payer_email'];
// Build the required acknowledgement message out of the notification just received
$req = 'cmd=_notify-validate'; // Add 'cmd=_notify-validate' to beginning of the acknowledgement
foreach ($_POST as $key => $value) {
// Loop through the notification NV pairs
$value = urlencode(stripslashes($value)); // Encode these values
$req .= "&$key=$value"; // Add the NV pairs to the acknowledgement
}
// Set up the acknowledgement request headers
// HTTP POST request
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Host: www.sanbox.paypal.com\r\n";
$header .= "Accept: */*\r\n";
$header .= "Connection: Close\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "\r\n";
// Open a socket for the acknowledgement request
$fp = fsockopen('tls://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
// Send the HTTP POST request back to PayPal for validation
fputs($fp, $header . $req);
// Log the transaction:
file_put_contents("paypal_post.txt", date('Y-m-d H:i:s')."\n".file_get_contents("php://input")."\n\n", FILE_APPEND);
// While not EOF
while (!feof($fp)) {
// Get the acknowledgement response
// $res = fgets($fp, 1024);
$res = stream_get_contents($fp, 1024);
$responses = explode("\r\n", $res);
foreach ($responses as $response) {
if (strcmp ($response, "VERIFIED") == 0) {
// Response contains VERIFIED - process notification
// Authentication protocol is complete - OK to process notification contents
// Possible processing steps for a payment include the following:
// Check that the payment_status is Completed
// Check that txn_id has not been previously processed
// Check that receiver_email is your Primary PayPal email
// Check that payment_amount/payment_currency are correct
// Process payment
} else if (strcmp ($response, "INVALID") == 0) {
// Response contains INVALID - reject notification
// Authentication protocol is complete - begin error handling
}
}
}
// Close the file
fclose($fp);
?>
好的,现在您有了用于侦听 PayPal IPN的代码,重新编译并将其发送回 PayPal进行验证,接收回标头,逐行处理标头以查找VERIFIED验证。
这应该由 PayPal 一体化软件包在工作状态下提供,但他们的教程缺少非常关键的部分,它对我和这个线程上的许多人都不起作用。
那么现在使它工作的关键部分是什么:首先,paypal 提供的标题不起作用,我发现 @jp_eagle 的标题工作完美。
贝宝错了 $res = fgets($fp, 1024); 还有……
但是你不需要 $res = stream_get_contents($fp, 2048); 正如@jp_eagle 建议的那样, $res = stream_get_contents($fp, 1024); 很好。
while (!feof($fp)) {} 循环应该留在那里以使其工作!是的,即使从 fgets() 切换到 stream_get_contents() 它也应该留在那里!
@richbai90 删除它的建议是错误的。换个方法试试,不行。。。
获得 VALIDATION 的最关键部分是这个循环:
$res = stream_get_contents($fp, 1024);
$responses = explode("\r\n", $res);
foreach ($responses as $response) {}
现在您可以在此处的每一行中查找 VALIDATION :
if (strcmp ($response, "VERIFIED") == 0) {}
在其他任何事情之前,还记录了初始完整的传入 POST 请求表单 paypal:
// 记录交易:file_put_contents("paypal_post.txt", date('Ymd H:i:s')."\n".file_get_contents("php://input")."\n\n", FILE_APPEND );
而已。现在去这里用你的贝宝登录看看它是否有效:
https ://developer.paypal.com/developer/ipnSimulator/
例如,给您的网址选择“购物车结帐”并发送测试 IPN。如果一切正常,请继续从上面的 paypal URL 中删除 .sandbox,从 www.sandbox.paypal.com 到 www.paypal.com,您就可以上线了。
使用您的数据库操作填写 if-else 语句中的 VERIFIED 和 INVALID 部分,然后就完成了。