У меня есть скрипт, в основном созданный из нескольких примеров вызовов PayPal IPN, которые я смог найти.Когда я запускаю его через симулятор, он говорит, что рукопожатие получено, и все хорошо.Но на основании данных, отправленных мне обратно, IPN всегда возвращается как недействительный.Не знаю, что не так, и я в затруднительном положении.Пожалуйста помоги!Код ниже.
Страница слушателя:
<?php
namespace Listener;
// Set this to true to use the sandbox endpoint during testing:
$enable_sandbox = true;
// Use this to specify all of the email addresses that you have attached to paypal:
$my_email_addresses = array("payment@mysite.com", "payment@mysite.com");
// Set this to true to send a confirmation email:
$send_confirmation_email = true;
$confirmation_email_address = "payment@mysite.com";
$from_email_address = "payment@mysite.com";
// Set this to true to save a log file:
$save_log_file = true;
$log_file_dir = __DIR__ . "/logs";
// Here is some information on how to configure sendmail:
// http://php.net/manual/en/function.mail.php#118210
require('PaypalIPN.php');
use PaypalIPN;
$ipn = new PaypalIPN();
if ($enable_sandbox) {
$ipn->useSandbox();
}
$verified = $ipn->verifyIPN();
$data_text = "";
foreach ($_POST as $key => $value) {
$data_text .= $key . " = " . $value . "\r\n";
}
$test_text = "";
if ($_POST["test_ipn"] == 1) {
$test_text = "Test ";
}
// Check the receiver email to see if it matches your list of paypal email addresses
$receiver_email_found = false;
foreach ($my_email_addresses as $a) {
if (strtolower($_POST["receiver_email"]) == strtolower($a)) {
$receiver_email_found = true;
break;
}
}
date_default_timezone_set("America/Chicago");
list($year, $month, $day, $hour, $minute, $second, $timezone) = explode(":", date("Y:m:d:H:i:s:T"));
$date = $year . "-" . $month . "-" . $day;
$timestamp = $date . " " . $hour . ":" . $minute . ":" . $second . " " . $timezone;
$dated_log_file_dir = $log_file_dir . "/" . $year . "/" . $month;
$paypal_ipn_status = "VERIFICATION FAILED";
if ($verified) {
$paypal_ipn_status = "RECEIVER EMAIL MISMATCH";
if ($receiver_email_found) {
$paypal_ipn_status = "Completed Successfully";
// Process IPN
// A list of variables are available here:
// https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNandPDTVariables/
}
} elseif ($enable_sandbox) {
if ($_POST["test_ipn"] != 1) {
$paypal_ipn_status = "RECEIVED FROM LIVE WHILE SANDBOXED";
}
} elseif ($_POST["test_ipn"] == 1) {
$paypal_ipn_status = "RECEIVED FROM SANDBOX WHILE LIVE";
}
if ($save_log_file) {
// Create log file directory
if (!is_dir($dated_log_file_dir)) {
if (!file_exists($dated_log_file_dir)) {
mkdir($dated_log_file_dir, 0777, true);
if (!is_dir($dated_log_file_dir)) {
$save_log_file = false;
}
} else {
$save_log_file = false;
}
}
// Restrict web access to files in the log file directory
$htaccess_body = "RewriteEngine On" . "\r\n" . "RewriteRule .* - [L,R=404]";
if ($save_log_file && (!is_file($log_file_dir . "/.htaccess") || file_get_contents($log_file_dir . "/.htaccess") !== $htaccess_body)) {
if (!is_dir($log_file_dir . "/.htaccess")) {
file_put_contents($log_file_dir . "/.htaccess", $htaccess_body);
if (!is_file($log_file_dir . "/.htaccess") || file_get_contents($log_file_dir . "/.htaccess") !== $htaccess_body) {
$save_log_file = false;
}
} else {
$save_log_file = false;
}
}
if ($save_log_file) {
// Save data to text file
file_put_contents($dated_log_file_dir . "/" . $test_text . "paypal_ipn_" . $date . ".txt", "paypal_ipn_status = " . $paypal_ipn_status . "\r\n" . "paypal_ipn_date = " . $timestamp . "\r\n" . $data_text . "\r\n", FILE_APPEND);
}
}
if ($send_confirmation_email) {
// Send confirmation email
mail($confirmation_email_address, $test_text . "PayPal IPN : " . $paypal_ipn_status, "paypal_ipn_status = " . $paypal_ipn_status . "\r\n" . "paypal_ipn_date = " . $timestamp . "\r\n" . $data_text, "From: " . $from_email_address);
}
// Reply with an empty 200 response to indicate to paypal the IPN was received correctly
header("HTTP/1.1 200 OK");
?>
И класс PayPalINP:
<?php
class PaypalIPN
{
/** @var bool Indicates if the sandbox endpoint is used. */
private $use_sandbox = true;
/** @var bool Indicates if the local certificates are used. */
private $use_local_certs = false;
/** 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]] = $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 = stripslashes($value);
} else {
$value = $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;
}
}
}