Paypal IPN,更改帐户中的 ipn url 后未获得所有交易响应

Paypal IPN, Not getting all the transactions responses after changing the ipn url in the account

我正在我的项目中实施 ipnlistner。我在我的 paypal 帐户中设置了 ipn url。但是我没有得到所有的交易 ipn 响应 url。但是当我在我的帐户中查看 ipn 历史记录时,它显示所有 ipn 都已发送。例如昨天它显示所有 112 ipn 已发送。但我的数据库中只有 7 个。这是我的 ipn listner 代码。我只在第一行插入我在数据库中获得的所有数据。

<?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

我的 ipn url 是

https://www.myproject.com/api/verify-ipn

Note: previously i created some paypal buttons on this account, i am not getting the ipn responses for that button payments

请帮助或指导为此做什么..

听起来您的代码中可能有错误。需要进一步调试。当我 运行 遇到这样的事情时,我通常会检查错误日志以查看发生了什么。

PayPal 将继续尝试发送请求,直到它收到正文中没有内容的 200 OK HTTP 状态响应。如果 PayPal 显示端点已成功接收,则数据库无法输入数据的位置可能就在您的 header 函数被调用之前。

我的下一步调试是尝试弄清楚我的数据库插入是否由于某种数据完整性而失败 error/warning。

捕获数据库错误并触发某种非传递响应可能会有所帮助,因此 PayPal 会重新发送,直到您找出脚本问题。

还有:

  • 尝试使用 Monologerror_log 之类的方法添加额外的日志记录,以深入了解脚本终止的位置或未按预期工作的地方。

我应该注意到,我现在也在实施 PayPal IPN,而且这个库很难使用。我用订户模式衍生出了自己的模式。它尚未准备好 public,但主要是为了将逻辑与验证分开,以实现更好的测试和可读性。

请在您的控制器中创建以下功能,并在您的 Paypal 帐户中添加 IPN URL 并检查 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: me@mybiz.com";
                // Add your live email address 
                $mail_To = "raghbendra.nayak@systematixindia.com";
                $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: me@mybiz.com";
                $mail_To = "raghbendra.nayak@systematixindia.com";
                $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 侦听器每次触发时向您发送电子邮件。只要它有效,那么您就可以根据您的要求进行管理。试试让我知道。

首先,写一个日志作为web服务的第一行,这样你就知道什么时候收到请求了。

然后,有时您没有设置所有请求参数,所以当找不到参数时,您的 sql 可能会出错。

例如,在我的 paypal 表单中,我发送 invoice_number。然后,当我收到来自 IPN 的请求时,我将检查 invoice_number 到 link 的付款和发票。 但是我也从其他来源获得了同一个 paypal 账户的付款,所以在另一种情况下 invoice_number 没有设置。

您可以写一个日志,其中包含在 IPN 调用中找到的所有参数,以便检查缺少的内容。