简体   繁体   English

PHP Paypal IPN侦听器失败,只有多个项目失败,而不是单个项目失败

[英]PHP Paypal IPN listener failing with multiple items only not individual items

I'm getting a very weird problem with my IPN listener when processing multiple items in Sandbox mode. 在沙盒模式下处理多个项目时,我的IPN侦听器遇到一个非常奇怪的问题。

I've tested with the IPN simulator and it works fine, and also with the cart it will be used for adding one product and it works fine, but as soon as I add two or more different products into the cart and process, the IPN listener fails without any errors in the log. 我已经使用IPN模拟器进行了测试,它可以正常工作,也可以与购物车一起使用,它可以用于添加一种产品,并且可以正常工作,但是一旦我将两种或更多种不同的产品添加到购物车和流程中,IPN侦听器失败,日志中没有任何错误。

Paypal is receiving and sending back all the correct data, as I can see the transaction details in the test Sandbox accounts and also the debug data in the script. Paypal正在接收和发送所有正确的数据,因为我可以在测试沙箱帐户中看到交易详细信息,并在脚本中看到调试数据。

It's based on the official IPN Paypal script, but with the addition of email notifiers that are sent out. 它基于官方IPN Paypal脚本,但添加了发送的电子邮件通知程序。

    <?php
    // CONFIG: Enable debug mode. This means we'll log requests into 'ipn.log' in the same directory.
    // Especially useful if you encounter network errors or other intermittent problems with IPN (validation).
    // Set this to 0 once you go live or don't require logging.
    define("DEBUG", 1);

    // Set to 0 once you're ready to go live
    define("USE_SANDBOX", 1);


    define("LOG_FILE", "./ipn.log");

    $mail = new PHPMailer;

    $mail->isSMTP();                                      // Set mailer to use SMTP
    $mail->Host = 'localhost';  // Specify main and backup server
    $mail->SMTPAuth = true;                               // Enable SMTP authentication
    $mail->Username = 'XXXXX';                            // SMTP username
    $mail->Password = 'XXXXX';                           // SMTP password

    $mail->From = 'XXXXX';
    $mail->FromName = 'XXXXX';
    $mail->addAddress('XXXXX', 'XXXXX');  // Add a recipient

    $mail->WordWrap = 50;                                 // Set word wrap to 50 characters
    $mail->isHTML(true);                                  // Set email format to HTML


    // PayPal IPN posts transaction info to this script
    // Read POST data
    // reading posted data directly from $_POST causes serialization
    // issues with array data in POST. Reading raw POST data from input stream instead.
    $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)
                    $myPost[$keyval[0]] = urldecode($keyval[1]);
    }

    // read the post from PayPal system and add 'cmd'
    $req = 'cmd=_notify-validate';
    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 IPN data back to PayPal to validate the IPN data is genuine
    // Without this step anyone can fake IPN data

    if(USE_SANDBOX == true) {
            $paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr";
    } else {
            $paypal_url = "https://www.paypal.com/cgi-bin/webscr";
    }

    $ch = curl_init($paypal_url);
    if ($ch == FALSE) {
            return FALSE;
    }
    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_SSL_VERIFYPEER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);

    if(DEBUG == true) {
            curl_setopt($ch, CURLOPT_HEADER, 1);
            curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
    }
    // CONFIG: Optional proxy configuration
    //curl_setopt($ch, CURLOPT_PROXY, $proxy);
    //curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);

    // Set TCP timeout to 30 seconds
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));

    // CONFIG: Please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set the directory path
    // of the certificate as shown below. Ensure the file is readable by the webserver.
    // This is mandatory for some environments.

    //$cert = __DIR__ . "./cacert.pem";
    //curl_setopt($ch, CURLOPT_CAINFO, $cert);

    $res = curl_exec($ch);
    if (curl_errno($ch) != 0) // cURL error
            {
            if(DEBUG == true) {        
                    error_log(date('[Y-m-d H:i e] '). "Can't connect to PayPal to validate IPN message: " . curl_error($ch) . PHP_EOL, 3, LOG_FILE);
            }
            curl_close($ch);
            exit;

    } else {
                    // Log the entire HTTP response if debug is switched on.
                    if(DEBUG == true) {
                            error_log(date('[Y-m-d H:i e] '). "HTTP request of validation request:". curl_getinfo($ch, CURLINFO_HEADER_OUT) ." for IPN payload: $req" . PHP_EOL, 3, LOG_FILE);
                            error_log(date('[Y-m-d H:i e] '). "HTTP response of validation request: $res" . PHP_EOL, 3, LOG_FILE);

                            // Split response headers and payload
                            list($headers, $res) = explode("\r\n\r\n", $res, 2);
                    }
                    curl_close($ch);
    }

    // Inspect IPN validation result and act accordingly

    if (strcmp ($res, "VERIFIED") == 0) {
            // check whether the payment_status is Completed
            // check that txn_id has not been previously processed
            // check that receiver_email is your PayPal email
            // check that payment_amount/payment_currency are correct
            // process payment and mark item as paid.

            // assign posted variables to local variables        
            $first_name = $_POST['first_name']; 
            $last_name = $_POST['last_name']; 
            $address_street = $_POST['address_street']; 
            $address_city = $_POST['address_city'];
            $address_zip = $_POST['address_zip'];
            $payment_status = $_POST['payment_status'];
            $payment_amount = $_POST['mc_gross'];
            $payment_currency = $_POST['mc_currency'];
            $payer_email = urldecode ( $_POST['payer_email'] );
            $shipping = $_POST['mc_shipping'];
            $payment_date = $_POST['payment_date'];
            $num_cart_items = $_POST['num_cart_items'];

            //Redundant variables
            //$item_name = $_POST['item_name1'];
            //$item_number = $_POST['item_number'];
            //$item_name1 = $_POST['item_name1'];
            //$item_number1 = $_POST['item_number1'];
            //$item_cost1 = $_POST['mc_gross1'];
            //$quantity1 = $_POST['quantity1'];        

            /*
     * Deduct VAT from a gross price
     * Using 20 VAT
     */
    $gross = $payment_amount;
    $nett = $gross - (($gross*1)/6);
    $nett = number_format($nett,2);
    // gives 0.XX due to rounding


    $table = "<table>
      <tr >
        <th colspan='2' scope='row' style='padding:0 30px'>
        <h1 style='color:#333366'>INVOICE </h1>
        <p style='color:#000'>Date added: $payment_date</p>
        <p style='color:#000'>&nbsp;</p>
        <h3 style='color:#333366'>Payment Details</h3>
        <p style='color:#000'>Name: $first_name $last_name</p>
       <p style='color:#000'>Address: $address_street, $address_city, $address_zip</p> 
       <p style='color:#000'>Payer email: $payer_email</p> 
       <p style='color:#000'>&nbsp;</p>
        <h3 style='color:#333366'>Product Details</h3>";
    for ($i = 1; $i <= $_POST['num_cart_items']; $i++) {
     $table .= "<p>".$_POST['item_name' + $i]."</p>";
     $table .= "<p>".$_POST['item_number' + $i]."</p>";
     $table .= "<p>".$_POST['quantity' + $i]."</p>";
     $table .= "<p>".$_POST['mc_gross_' + $i]."</p>";
    }       
    $table .= "<p style='color:#000'>Delivery cost: £$shipping</p>
        <p style='color:#000'>Net price: £$nett</p>
        <p style='color:#000'>Gross price: £$payment_amount</p>
        <p style='color:#000;font-size:11px'>VAT calculated at 20%  </p>
    </th>
      </tr>
    </table>";

    $mail->Subject = 'Your Order';
    $mail->Body   = $table;
    $mail->addAddress($payer_email, $first_name.' '.$last_name); 
    if(!$mail->send()) {
       echo 'Message could not be sent.';
       echo 'Mailer Error: ' . $mail->ErrorInfo;
       exit;
    }


            if(DEBUG == true) {
                    error_log(date('[Y-m-d H:i e] '). "Verified IPN: $req ". PHP_EOL, 3, LOG_FILE);
            }
    } else if (strcmp ($res, "INVALID") == 0) {
            // log for manual investigation
            // Add business logic here which deals with invalid IPN messages


            $mail->Subject = 'Invalid';
    $mail->Body   = $table;
    if(!$mail->send()) {
       echo 'Message could not be sent.';
       echo 'Mailer Error: ' . $mail->ErrorInfo;
       exit;
    }


            if(DEBUG == true) {
                    error_log(date('[Y-m-d H:i e] '). "Invalid IPN: $req" . PHP_EOL, 3, LOG_FILE);
            }
    }
    ?>

I finally solved this. 我终于解决了这个问题。 The issue was with curl setup. 问题是卷曲设置。

Orders with multiple products are much longer than the orders with single products. 具有多个产品的订单比具有单个产品的订单长得多。

curl is set to send an extra header (HTTP/1.1 100 Continue) when the data is over a certain length. 当数据超过一定长度时,curl设置为发送额外的标头(HTTP / 1.1 100继续)。

There is a simple fix for this. 有一个简单的解决方案。

Add 'Expect:' as a value to the CURLOPT_HTTPHEADER array. 将“期望:”作为值添加到CURLOPT_HTTPHEADER数组。

So: 所以:

curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));

Becomes

curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Expect:','Connection: Close'));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM