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, чтобы вы могли проверить, что отсутствует.