无法在 Codeigniter 中接收 PayPal IPN 响应
Unable to Receive PayPal IPN Response in Code Igniter
我已经用了 3 天了,但仍然无法正常工作。
我想做的是从 IPN 侦听器获取 PayPal 响应,以便我可以相应地修改我的数据库,但无论我做什么,它都行不通。我已经在我的 PayPal 沙盒帐户中完成了以下操作:
已启用自动 Return
设置自动 Return URL ('paypal/success')
- 启用支付数据传输 (PDT)
- 已启用 IPN 消息接收
- 设置 IPN URL ('paypal/ipn')
重定向到自动 Return URL 工作正常,我在成功页面收到付款数据,但 IPN 不会处理我以外的原因。快速查看我的 PayPal 个人资料上的 IPN 历史记录显示消息正在发送,但我没有收到它们。
这是我当前的 IPN 侦听器:Paypal/ipn
public function ipn() {
//Build the data to post back to Paypal
$postback = 'cmd=_notify-validate';
// go through each of the posted vars and add them to the postback variable
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$postback .= "&$key=$value";
}
// build the header string to post back to PayPal system to validate
$header = "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Host: www.sandbox.paypal.com\r\n";//or www.sandbox.paypal.com
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($postback) . "\r\n\r\n";
// Send to paypal or the sandbox depending on whether you're live or developing
// comment out one of the following lines
$fp = fsockopen ('www.sandbox.paypal.com', 443, $errno, $errstr, 30);//open the connection
//$fp = fsockopen ('www.paypal.com', 80, $errno, $errstr, 30);
// or use port 443 for an SSL connection
//$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
if ( ! $fp ) {
// HTTP ERROR Failed to connect
$message = 'HTTP ERROR Failed to connect!';
$this->email_me($message);
} else { // if we've connected OK
fputs ($fp, $header . $postback); //post the data back
while ( ! feof($fp) ) {
$response = fgets ($fp, 1024);
if (strcmp (trim($response), "VERIFIED") == 0) { //It's verified
//read the payment details and the account holder
$payment_status = $_POST['payment_status'];
$receiver_email = urldecode($_POST['receiver_email']);
// further checks
if( ($payment_status == 'Completed') && ($receiver_email == $this->business_email) ) {
$message = 'IPN verified successfully!';
$this->email_me($message);
// Insert the transaction data in the database
$this->product_model->insert_transaction_details($_POST);
} else {
$message = 'Payment could not be verified!';
$this->email_me($message);
}
} else {
$message = 'IPN invalid!';
$this->email_me($message);
}
}
}
}
有人能给我指出正确的方向吗?
另外,我是否可以在 chrome 调试器或我的 PayPal 沙盒仪表板上检查 IPN 响应("VERIFIED" 或 "INVALID")?我可以在我的仪表板中看到交付状态,但它不会在任何地方显示 'Verified' 或 'Invalid'。
使用 php://input 而不是 $_POST
这里详细描述了原因:PHP "php://input" vs $_POST
paypal 也有实现 IPN Listener 的文档,它也在 php
Paypal tutorial
我找到了解决办法!我在控制器中编写了 IPN 处理程序,允许访问以管理员身份登录的用户。显然,IPN 方法拒绝访问 PayPal 以验证交易。我弄清楚了这一点,并在不同的控制器中编写了 IPN 方法,一切都运行良好。
我也将我的 IPN 处理程序更改为这段代码(虽然原来的可能仍然有效......我没有尝试过):
class Paypal_ipn extends MY_Controller {
public function __construct() {
parent::__construct();
$this->load->model('product_model');
$this->sandbox = $this->config->item('sandbox');
$this->paypal_host = $this->config->item('paypal_host');
$this->paypal_url = $this->config->item('paypal_url');
$this->business_email = $this->config->item('business');
}
public function ipn() {
// STEP 1: Read POST data
// reading posted data from 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);
$myPost = array();
foreach ($raw_post_array as $keyval) {
$keyval = explode ('=', $keyval);
if (count($keyval) == 2)
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
if(function_exists('get_magic_quotes_gpc')) {
$get_magic_quotes_exists = true;
}
foreach ($myPost as $key => $value) {
if($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) {
$value = urlencode(stripslashes($value));
} else {
$value = urlencode($value);
}
$req .= "&$key=$value";
}
// STEP 2: Post IPN data back to paypal to validate
$ch = curl_init($this->paypal_url);
$headers = array(
'POST /cgi-bin/webscr HTTP/1.1',
'Host: ' . $this->paypal_host,
'Content-Type: application/x-www-form-urlencoded; charset=utf-8',
'Content-Length: ' . strlen($req),
'User-Agent: PayPal-IPN-VerificationScript',
'Connection: Close'
);
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_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
if( !($res = curl_exec($ch)) ) {
curl_close($ch);
exit;
}
curl_close($ch);
// STEP 3: Inspect IPN validation result and act accordingly
if (strcmp ($res, "VERIFIED") == 0) {
// check whether 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
// assign posted variables 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 = urldecode($_POST['receiver_email']);
$payer_email = $_POST['payer_email'];
$school_id = $_POST['custom'];
// further checks
if($payment_status == 'Completed') {
$message = 'IPN verified successfully!';
$this->email_developer($message);
// Insert the transaction data in the database
$this->product_model->insert_transaction_details($_POST);
} else {
$message = 'Payment could not be verified!';
$this->email_developer($message);
}
} else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
$message = 'IPN Invalid!';
$this->email_developer($message);
}
}
}
对于那些可能遇到我的困境的人,请确保您也执行以下操作:
- 如果您启用了跨站请求伪造 (CSRF),请确保 IPN listener/handler 已列入白名单,否则 IPN 消息将失败(PayPal IPN 历史记录中的错误 403)。
- 为确保您的 IPN 侦听器运行良好,运行 将其作为 URL 并查看响应。如果有任何错误,它将不起作用。对于响应,尝试回显 "Verified" 或 "Invalid".
- 使用PayPal IPN Simulator测试进程。包括一个在成功时将信息提交到数据库的过程。
希望对大家有所帮助。
我已经用了 3 天了,但仍然无法正常工作。
我想做的是从 IPN 侦听器获取 PayPal 响应,以便我可以相应地修改我的数据库,但无论我做什么,它都行不通。我已经在我的 PayPal 沙盒帐户中完成了以下操作:
已启用自动 Return
设置自动 Return URL ('paypal/success')
- 启用支付数据传输 (PDT)
- 已启用 IPN 消息接收
- 设置 IPN URL ('paypal/ipn')
重定向到自动 Return URL 工作正常,我在成功页面收到付款数据,但 IPN 不会处理我以外的原因。快速查看我的 PayPal 个人资料上的 IPN 历史记录显示消息正在发送,但我没有收到它们。
这是我当前的 IPN 侦听器:Paypal/ipn
public function ipn() {
//Build the data to post back to Paypal
$postback = 'cmd=_notify-validate';
// go through each of the posted vars and add them to the postback variable
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$postback .= "&$key=$value";
}
// build the header string to post back to PayPal system to validate
$header = "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Host: www.sandbox.paypal.com\r\n";//or www.sandbox.paypal.com
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($postback) . "\r\n\r\n";
// Send to paypal or the sandbox depending on whether you're live or developing
// comment out one of the following lines
$fp = fsockopen ('www.sandbox.paypal.com', 443, $errno, $errstr, 30);//open the connection
//$fp = fsockopen ('www.paypal.com', 80, $errno, $errstr, 30);
// or use port 443 for an SSL connection
//$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
if ( ! $fp ) {
// HTTP ERROR Failed to connect
$message = 'HTTP ERROR Failed to connect!';
$this->email_me($message);
} else { // if we've connected OK
fputs ($fp, $header . $postback); //post the data back
while ( ! feof($fp) ) {
$response = fgets ($fp, 1024);
if (strcmp (trim($response), "VERIFIED") == 0) { //It's verified
//read the payment details and the account holder
$payment_status = $_POST['payment_status'];
$receiver_email = urldecode($_POST['receiver_email']);
// further checks
if( ($payment_status == 'Completed') && ($receiver_email == $this->business_email) ) {
$message = 'IPN verified successfully!';
$this->email_me($message);
// Insert the transaction data in the database
$this->product_model->insert_transaction_details($_POST);
} else {
$message = 'Payment could not be verified!';
$this->email_me($message);
}
} else {
$message = 'IPN invalid!';
$this->email_me($message);
}
}
}
}
有人能给我指出正确的方向吗? 另外,我是否可以在 chrome 调试器或我的 PayPal 沙盒仪表板上检查 IPN 响应("VERIFIED" 或 "INVALID")?我可以在我的仪表板中看到交付状态,但它不会在任何地方显示 'Verified' 或 'Invalid'。
使用 php://input 而不是 $_POST
这里详细描述了原因:PHP "php://input" vs $_POST
paypal 也有实现 IPN Listener 的文档,它也在 php Paypal tutorial
我找到了解决办法!我在控制器中编写了 IPN 处理程序,允许访问以管理员身份登录的用户。显然,IPN 方法拒绝访问 PayPal 以验证交易。我弄清楚了这一点,并在不同的控制器中编写了 IPN 方法,一切都运行良好。
我也将我的 IPN 处理程序更改为这段代码(虽然原来的可能仍然有效......我没有尝试过):
class Paypal_ipn extends MY_Controller {
public function __construct() {
parent::__construct();
$this->load->model('product_model');
$this->sandbox = $this->config->item('sandbox');
$this->paypal_host = $this->config->item('paypal_host');
$this->paypal_url = $this->config->item('paypal_url');
$this->business_email = $this->config->item('business');
}
public function ipn() {
// STEP 1: Read POST data
// reading posted data from 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);
$myPost = array();
foreach ($raw_post_array as $keyval) {
$keyval = explode ('=', $keyval);
if (count($keyval) == 2)
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
if(function_exists('get_magic_quotes_gpc')) {
$get_magic_quotes_exists = true;
}
foreach ($myPost as $key => $value) {
if($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) {
$value = urlencode(stripslashes($value));
} else {
$value = urlencode($value);
}
$req .= "&$key=$value";
}
// STEP 2: Post IPN data back to paypal to validate
$ch = curl_init($this->paypal_url);
$headers = array(
'POST /cgi-bin/webscr HTTP/1.1',
'Host: ' . $this->paypal_host,
'Content-Type: application/x-www-form-urlencoded; charset=utf-8',
'Content-Length: ' . strlen($req),
'User-Agent: PayPal-IPN-VerificationScript',
'Connection: Close'
);
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_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
if( !($res = curl_exec($ch)) ) {
curl_close($ch);
exit;
}
curl_close($ch);
// STEP 3: Inspect IPN validation result and act accordingly
if (strcmp ($res, "VERIFIED") == 0) {
// check whether 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
// assign posted variables 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 = urldecode($_POST['receiver_email']);
$payer_email = $_POST['payer_email'];
$school_id = $_POST['custom'];
// further checks
if($payment_status == 'Completed') {
$message = 'IPN verified successfully!';
$this->email_developer($message);
// Insert the transaction data in the database
$this->product_model->insert_transaction_details($_POST);
} else {
$message = 'Payment could not be verified!';
$this->email_developer($message);
}
} else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
$message = 'IPN Invalid!';
$this->email_developer($message);
}
}
}
对于那些可能遇到我的困境的人,请确保您也执行以下操作:
- 如果您启用了跨站请求伪造 (CSRF),请确保 IPN listener/handler 已列入白名单,否则 IPN 消息将失败(PayPal IPN 历史记录中的错误 403)。
- 为确保您的 IPN 侦听器运行良好,运行 将其作为 URL 并查看响应。如果有任何错误,它将不起作用。对于响应,尝试回显 "Verified" 或 "Invalid".
- 使用PayPal IPN Simulator测试进程。包括一个在成功时将信息提交到数据库的过程。
希望对大家有所帮助。