Paypal IPN, не получая все ответы на транзакции после изменения URL-адреса ipn в учетной записи
Я реализую ipnlistner внутри своего проекта. Я установил URL-адрес ipn внутри моей учетной записи PayPal. Но я не получаю все транзакции ipn-ответов на этот URL-адрес. Но когда я проверяю историю ipn в своей учетной записи, он показывает, что все ipn отправлено. Например, вчера он показывает все 112 ipn отправлено. но я получаю только 7 в своем db. Вот мой код для ipn listner. Я вставляю все данные, которые я получаю в db только в первой строке.
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Response;
class PaypalIPN extends Controller {
private $use_sandbox = null;
const VALID = 'VERIFIED';
const INVALID = 'INVALID';
public function useSandbox() {
$this->use_sandbox = env( 'USE_SANDBOX' );
}
public function getPaypalUri() {
if ( $this->use_sandbox ) {
return env( 'SANDBOX_VERIFY_URI' );
} else {
return env( 'VERIFY_URI' );
}
}
public function verifyIPN() {
try {
DB::table( 'ipn_response' )->insert( [ 'data' => json_encode( $_POST, true ) ] );
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";
}
// Use the sandbox endpoint during testing.
$this->useSandbox();
// 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 );
curl_setopt( $ch, CURLOPT_FORBID_REUSE, 1 );
curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 30 );
curl_setopt( $ch, CURLOPT_HTTPHEADER, array( '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 ) {
DB::table( 'ipn_response' )->insert( [ 'data' => json_encode( $res, true ) ] );
} else {
DB::table( 'ipn_response' )->insert( [ 'data' => json_encode( $res, true ) ] );
}
// Reply with an empty 200 response to indicate to paypal the IPN was received correctly.
header( "HTTP/1.1 200 OK" );
}catch (\Exception $e){
DB::table( 'ipn_response' )->insert( [ 'data' => json_encode( ["Exception"=>$e->getMessage()]) ] );
}
}
}
Я очень люблю IPN на этом URL
https://ipnpb.paypal.com/cgi-bin/webscr
и мой URL-адрес ipn
https://www.myproject.com/api/verify-ipn
Примечание: ранее я создал несколько кнопок PayPal в этой учетной записи, я не получаю ответы ipn для этой кнопки.
Пожалуйста, помогите или подскажите, что делать для этого..
Ответы
Ответ 1
Похоже, в вашем коде может быть ошибка. Необходима дальнейшая отладка. Когда я сталкиваюсь с чем-то вроде этого, я обычно проверяю журналы ошибок, чтобы узнать, что происходит.
PayPal будет продолжать отправлять запросы до получения ответа статуса HTTP 200 OK
без содержимого в теле. Если PayPal показывает успешную квитанцию конечной точкой, то место, где база данных не вводит данные, вероятно, непосредственно перед тем, как будет вызываться функция header
.
Следующим моим шагом для отладки было бы попытаться выяснить, не вступили ли мои вставки базы данных из-за какой-либо ошибки/предупреждения целостности данных.
Возможно, было бы полезно поймать ошибки БД и вызвать какой-то не проходящий ответ, так что PayPal отправляется до тех пор, пока не выяснит проблему с сценарием.
также:
- Попробуйте добавить дополнительное ведение журнала, используя что-то вроде
Monolog
или даже просто error_log
, чтобы добраться до конца, где заканчивается ваш script или что не работает должным образом.
Я должен отметить, что сейчас я внедряю IP-адрес PayPal, и эту библиотеку сложно использовать. Я выделил свой собственный шаблон подписчика. Он еще не готов публично публиковать, но в основном это отделить логику от проверки для лучшего тестирования и удобочитаемости.
Ответ 2
Создайте ниже функцию в своем контроллере и в своей учетной записи Paypal добавьте URL-адрес IPN и проверьте каждый хит IPN.
<?php
function paymentIpnlistener(){
$req = 'cmd=_notify-validate';
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
}
// post back to PayPal system to validate
$header = "POST /cgi-bin/webscr HTTP/1.0\r\n";
// If testing on Sandbox use:
$header .= "Host: www.sandbox.paypal.com:443\r\n";
//$header .= "Host: ipnpb.paypal.com:443\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
if (strpos('ssl://www.sandbox.paypal.com', 'sandbox') !== FALSE && function_exists('openssl_open')) {
$fp = fsockopen('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
}
else{
// The old "normal" way of validating an IPN.
$fp = fsockopen('ssl://www.sandbox.paypal.com', 80, $errno, $errstr, 30);
}
// If testing on Sandbox use:
//$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
//$fp = fsockopen ('ssl://ipnpb.paypal.com', 443, $errno, $errstr, 30);
// 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 = $_POST['receiver_email'];
$payer_email = $_POST['payer_email'];
if (!$fp) {
// HTTP ERROR
} else {
fputs ($fp, $header . $req);
while (!feof($fp)) {
$res = fgets ($fp, 1024);
if (strcmp ($res, "VERIFIED") == 0) {
// check 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
// Add your live email address
$mail_From = "From: [email protected]";
// Add your live email address
$mail_To = "[email protected]";
$mail_Subject = "VERIFIED IPN";
$mail_Body = $req;
foreach ($_POST as $key => $value){
$emailtext .= $key . " = " .$value ."\n\n";
}
mail($mail_To, $mail_Subject, $emailtext . "\n\n" . $mail_Body, $mail_From);
}
else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
$mail_From = "From: [email protected]";
$mail_To = "[email protected]";
$mail_Subject = "INVALID IPN";
$mail_Body = $req;
foreach ($_POST as $key => $value){
$emailtext .= $key . " = " .$value ."\n\n";
}
mail($mail_To, $mail_Subject, $emailtext . "\n\n" . $mail_Body, $mail_From);
}
} // while end
fclose ($fp);
}
}
?>
Выше функция отправит вам письмо по электронной почте каждый раз, когда запускается прослушиватель IPN. Просто, если вы работаете, вы можете управлять им в соответствии с вашим требованием. Попробуйте и дайте мне знать.
Ответ 3
Прежде всего, напишите журнал как первую строку веб-службы, поэтому вы знаете, когда получите запрос.
Затем, когда у вас нет всех параметров запроса, возможно, ваш sql по ошибке, если параметры не будут найдены.
В моей paypal форме, например, я посылаю invoice_number. Затем, когда я получаю запрос от IPN, я проверю на invoice_number, чтобы связать платеж со счетом-фактурой.
Но я получаю оплату на той же платежной учетной записи также из другого источника, поэтому в другом случае номер счета-фактуры не установлен.
Вы можете написать журнал со всем параметром, найденным в вызове IPN, чтобы вы могли проверить, что отсутствует.