无法理解如何正确使用 Paypal 的 IPN
Can't understand the proper to use Paypal's IPN
正如标题所说,我不明白如何使用 IPN。
本页
https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNImplementation/
说我需要实施我的 IPN 监听器,他们提供了示例。
这是 PHP:
的样本
IPN.php
<?php
class PaypalIPN
{
/** @var bool Indicates if the sandbox endpoint is used. */
private $use_sandbox = false;
/** @var bool Indicates if the local certificates are used. */
private $use_local_certs = true;
/** Production Postback URL */
const VERIFY_URI = 'https://ipnpb.paypal.com/cgi-bin/webscr';
/** Sandbox Postback URL */
const SANDBOX_VERIFY_URI = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr';
/** Response from PayPal indicating validation was successful */
const VALID = 'VERIFIED';
/** Response from PayPal indicating validation failed */
const INVALID = 'INVALID';
/**
* Sets the IPN verification to sandbox mode (for use when testing,
* should not be enabled in production).
* @return void
*/
public function useSandbox()
{
$this->use_sandbox = true;
}
/**
* Sets curl to use php curl's built in certs (may be required in some
* environments).
* @return void
*/
public function usePHPCerts()
{
$this->use_local_certs = false;
}
/**
* Determine endpoint to post the verification data to.
*
* @return string
*/
public function getPaypalUri()
{
if ($this->use_sandbox) {
return self::SANDBOX_VERIFY_URI;
} else {
return self::VERIFY_URI;
}
}
/**
* Verification Function
* Sends the incoming post data back to PayPal using the cURL library.
*
* @return bool
* @throws Exception
*/
public function verifyIPN()
{
if ( ! count($_POST)) {
throw new Exception("Missing POST Data");
}
$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) {
// Since we do not want the plus in the datetime string to be encoded to a space, we manually encode it.
if ($keyval[0] === 'payment_date') {
if (substr_count($keyval[1], '+') === 1) {
$keyval[1] = str_replace('+', '%2B', $keyval[1]);
}
}
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
}
// Build the body of the verification post request, adding the _notify-validate command.
$req = 'cmd=_notify-validate';
$get_magic_quotes_exists = false;
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";
}
// Post the data back to PayPal, using curl. Throw exceptions if errors occur.
$ch = curl_init($this->getPaypalUri());
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);
// This is often required if the server is missing a global cert bundle, or is using an outdated one.
if ($this->use_local_certs) {
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',
));
$res = curl_exec($ch);
if ( ! ($res)) {
$errno = curl_errno($ch);
$errstr = curl_error($ch);
curl_close($ch);
throw new Exception("cURL error: [$errno] $errstr");
}
$info = curl_getinfo($ch);
$http_code = $info['http_code'];
if ($http_code != 200) {
throw new Exception("PayPal responded with http code $http_code");
}
curl_close($ch);
// Check if PayPal verifies the IPN data, and if so, return true.
if ($res == self::VALID) {
return true;
} else {
return false;
}
}
}
?>
他们还提供了一个例子:
Example.php
<?php
namespace Listener;
require('PaypalIPN.php');
use PaypalIPN;
$ipn = new PaypalIPN();
// Use the sandbox endpoint during testing.
$ipn->useSandbox();
$verified = $ipn->verifyIPN();
if ($verified) {
/*
* Process IPN
* A list of variables is available here:
* https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNandPDTVariables/
*/
}
// Reply with an empty 200 response to indicate to paypal the IPN was received correctly.
header("HTTP/1.1 200 OK");
?>
我想做什么:
我将在我的页面上添加 Paypal 按钮,让用户为基于订阅的软件付费(1/3/6/12 个月)。 (他们不订阅,他们只支付 1/3/6/12 个月所需的钱)。
我需要在收到付款后自动更新我的数据库上的订阅到期日期。
我的问题:
- 我不明白我需要编辑什么,IPN.php 是不是要按照提供的方式上传到服务器?
- 它现在安全吗?
- 我应该将通知 URL(在 Paypal 的 IPN 设置上)指向 IPN.php 或我编辑的 Example.php 版本?
- 除此之外,还有什么建议吗?
我想澄清一下,我已经阅读了 paypal 指南中的内容,但我迷失了这么多信息。
1) 您显示的代码正在定义一个 class,因此您可以启动一个连接实例,您可以在其中定义不同的变量。所以你不应该改变它。您应该将其上传到您的服务器并相应地使用它。
2) 嗯...这是一个广泛的问题。比如……锁子甲安全吗?对于用剑攻击你的人来说是安全的:是的。对向你投掷核武器的人来说是安全的:不。而且这还取决于你如何使用锁子甲。
但是如果我应该尝试回答我认为你在问的问题:
该脚本与 PayPal 建立了安全连接,是的。因此,您需要确保在您正在制作的解决方案中,脚本和您的 API-key 不是 stolen/abused;这样人们就可以通过您的解决方案访问 PayPal,做您不希望他们做的事情。
3) 根据documentation that you linked to,则:
When you have completed your listener, push it to your site and specify the listener URL or notification URL in your account settings. See IPN Setup for more information.
...我必须承认我以前没有用过这个。但它看起来像 here 这是一种在您的网站和 Paypal 之间传递通知的方式。所以我假设这是一条路径,Paypal 检查以获取通知,将显示,嗯......某处(?)。很抱歉在这一点上含糊不清的回答。
4) 我的建议是,看看是否有已经集成的解决方案(框架或其他东西)。如果是我,我想我会使用 Laravel 或 WordPress,但这只是因为这是我有信心使用的工具。但是两者都带有解决方案 (Laravel and WordPress),这些解决方案由(希望)知道自己在做什么的人维护。因此,如果 PayPal 推出一个新的 API,弃用您现在使用的那个,- 您不必重新开始查看文档。但是了解一个框架需要相当多的时间(只是提醒一下)。
但是,- 这一切都取决于您想要做什么。所以第四点的 TL;DR 版本:使用框架。
正如标题所说,我不明白如何使用 IPN。
本页 https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNImplementation/ 说我需要实施我的 IPN 监听器,他们提供了示例。 这是 PHP:
的样本IPN.php
<?php
class PaypalIPN
{
/** @var bool Indicates if the sandbox endpoint is used. */
private $use_sandbox = false;
/** @var bool Indicates if the local certificates are used. */
private $use_local_certs = true;
/** Production Postback URL */
const VERIFY_URI = 'https://ipnpb.paypal.com/cgi-bin/webscr';
/** Sandbox Postback URL */
const SANDBOX_VERIFY_URI = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr';
/** Response from PayPal indicating validation was successful */
const VALID = 'VERIFIED';
/** Response from PayPal indicating validation failed */
const INVALID = 'INVALID';
/**
* Sets the IPN verification to sandbox mode (for use when testing,
* should not be enabled in production).
* @return void
*/
public function useSandbox()
{
$this->use_sandbox = true;
}
/**
* Sets curl to use php curl's built in certs (may be required in some
* environments).
* @return void
*/
public function usePHPCerts()
{
$this->use_local_certs = false;
}
/**
* Determine endpoint to post the verification data to.
*
* @return string
*/
public function getPaypalUri()
{
if ($this->use_sandbox) {
return self::SANDBOX_VERIFY_URI;
} else {
return self::VERIFY_URI;
}
}
/**
* Verification Function
* Sends the incoming post data back to PayPal using the cURL library.
*
* @return bool
* @throws Exception
*/
public function verifyIPN()
{
if ( ! count($_POST)) {
throw new Exception("Missing POST Data");
}
$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) {
// Since we do not want the plus in the datetime string to be encoded to a space, we manually encode it.
if ($keyval[0] === 'payment_date') {
if (substr_count($keyval[1], '+') === 1) {
$keyval[1] = str_replace('+', '%2B', $keyval[1]);
}
}
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
}
// Build the body of the verification post request, adding the _notify-validate command.
$req = 'cmd=_notify-validate';
$get_magic_quotes_exists = false;
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";
}
// Post the data back to PayPal, using curl. Throw exceptions if errors occur.
$ch = curl_init($this->getPaypalUri());
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);
// This is often required if the server is missing a global cert bundle, or is using an outdated one.
if ($this->use_local_certs) {
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',
));
$res = curl_exec($ch);
if ( ! ($res)) {
$errno = curl_errno($ch);
$errstr = curl_error($ch);
curl_close($ch);
throw new Exception("cURL error: [$errno] $errstr");
}
$info = curl_getinfo($ch);
$http_code = $info['http_code'];
if ($http_code != 200) {
throw new Exception("PayPal responded with http code $http_code");
}
curl_close($ch);
// Check if PayPal verifies the IPN data, and if so, return true.
if ($res == self::VALID) {
return true;
} else {
return false;
}
}
}
?>
他们还提供了一个例子:
Example.php
<?php
namespace Listener;
require('PaypalIPN.php');
use PaypalIPN;
$ipn = new PaypalIPN();
// Use the sandbox endpoint during testing.
$ipn->useSandbox();
$verified = $ipn->verifyIPN();
if ($verified) {
/*
* Process IPN
* A list of variables is available here:
* https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNandPDTVariables/
*/
}
// Reply with an empty 200 response to indicate to paypal the IPN was received correctly.
header("HTTP/1.1 200 OK");
?>
我想做什么:
我将在我的页面上添加 Paypal 按钮,让用户为基于订阅的软件付费(1/3/6/12 个月)。 (他们不订阅,他们只支付 1/3/6/12 个月所需的钱)。 我需要在收到付款后自动更新我的数据库上的订阅到期日期。
我的问题:
- 我不明白我需要编辑什么,IPN.php 是不是要按照提供的方式上传到服务器?
- 它现在安全吗?
- 我应该将通知 URL(在 Paypal 的 IPN 设置上)指向 IPN.php 或我编辑的 Example.php 版本?
- 除此之外,还有什么建议吗?
我想澄清一下,我已经阅读了 paypal 指南中的内容,但我迷失了这么多信息。
1) 您显示的代码正在定义一个 class,因此您可以启动一个连接实例,您可以在其中定义不同的变量。所以你不应该改变它。您应该将其上传到您的服务器并相应地使用它。
2) 嗯...这是一个广泛的问题。比如……锁子甲安全吗?对于用剑攻击你的人来说是安全的:是的。对向你投掷核武器的人来说是安全的:不。而且这还取决于你如何使用锁子甲。
但是如果我应该尝试回答我认为你在问的问题:
该脚本与 PayPal 建立了安全连接,是的。因此,您需要确保在您正在制作的解决方案中,脚本和您的 API-key 不是 stolen/abused;这样人们就可以通过您的解决方案访问 PayPal,做您不希望他们做的事情。
3) 根据documentation that you linked to,则:
When you have completed your listener, push it to your site and specify the listener URL or notification URL in your account settings. See IPN Setup for more information.
...我必须承认我以前没有用过这个。但它看起来像 here 这是一种在您的网站和 Paypal 之间传递通知的方式。所以我假设这是一条路径,Paypal 检查以获取通知,将显示,嗯......某处(?)。很抱歉在这一点上含糊不清的回答。
4) 我的建议是,看看是否有已经集成的解决方案(框架或其他东西)。如果是我,我想我会使用 Laravel 或 WordPress,但这只是因为这是我有信心使用的工具。但是两者都带有解决方案 (Laravel and WordPress),这些解决方案由(希望)知道自己在做什么的人维护。因此,如果 PayPal 推出一个新的 API,弃用您现在使用的那个,- 您不必重新开始查看文档。但是了解一个框架需要相当多的时间(只是提醒一下)。
但是,- 这一切都取决于您想要做什么。所以第四点的 TL;DR 版本:使用框架。