PayPal IPN 有时不更新数据库

Posted

技术标签:

【中文标题】PayPal IPN 有时不更新数据库【英文标题】:PayPal IPN sometimes not updating database 【发布时间】:2021-06-17 06:48:34 【问题描述】:

几个星期以来,PayPal 都没有为我的某些交易更新数据库。也许 10 个事务中有 3 个被添加到数据库中。不知道发生了什么。在此之前,一切都很好。没有错误,PayPal 历史中的每一笔交易都已完成。我不知道问题出在哪里。

这是我的 ipn.php

<?php
    if (gethostbyaddr($_SERVER['REMOTE_ADDR']) !== 'notify.paypal.com') 
        exit();
    

    // Require the functions to connect to database and fetch config values
    require 'config.php';
    require 'db.php';
    
    // Fetch and sanitize POST and GET values
    function getValue($value) 
        return (!empty($value)) ? sanitize($value) : false;
    
    function sanitize($data) 
        return htmlentities(strip_tags(mysql_znote_escape_string($data)));
    
    
    function VerifyPaypalIPN(array $IPN = null)
        if(empty($IPN))
            $IPN = $_POST;
        
        if(empty($IPN['verify_sign']))
            return null;
        
        $IPN['cmd'] = '_notify-validate';
        $PaypalHost = (empty($IPN['test_ipn']) ? 'www' : 'www.sandbox').'.paypal.com';
        $cURL = curl_init();
        curl_setopt($cURL, CURLOPT_SSL_VERIFYPEER, 1);
        curl_setopt($cURL, CURLOPT_SSL_VERIFYHOST, 2);
        curl_setopt($cURL, CURLOPT_SSLVERSION, 6);
        curl_setopt($cURL, CURLOPT_CAINFO, __DIR__ . '/cert/cacert.pem');
        curl_setopt($cURL, CURLOPT_URL, "https://$PaypalHost/cgi-bin/webscr");
        curl_setopt($cURL, CURLOPT_ENCODING, 'gzip');
        curl_setopt($cURL, CURLOPT_BINARYTRANSFER, true);
        curl_setopt($cURL, CURLOPT_POST, true); // POST back
        curl_setopt($cURL, CURLOPT_POSTFIELDS, $IPN); // the $IPN
        curl_setopt($cURL, CURLOPT_HEADER, false);
        curl_setopt($cURL, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($cURL, CURLOPT_FORBID_REUSE, true);
        curl_setopt($cURL, CURLOPT_FRESH_CONNECT, true);
        curl_setopt($cURL, CURLOPT_CONNECTTIMEOUT, 30);
        curl_setopt($cURL, CURLOPT_TIMEOUT, 60);
        curl_setopt($cURL, CURLINFO_HEADER_OUT, true);
        curl_setopt($cURL, CURLOPT_HTTPHEADER, array(
            'Connection: close',
            'Expect: ',
        ));
        $Response = curl_exec($cURL);
        $Status = (int)curl_getinfo($cURL, CURLINFO_HTTP_CODE);
    curl_close($cURL);
        if(empty($Response) or !preg_match('~^(VERIFIED|INVALID)$~i', $Response = trim($Response)) or !$Status)
            return null;
        
        if(intval($Status / 100) != 2)
            return false;
        
        return !strcasecmp($Response, 'VERIFIED');
    

    // Fetch paypal configurations
    $paypal = $config['paypal'];
    $prices = $config['paypal_prices'];
    
    // Send an empty HTTP 200 OK response to acknowledge receipt of the notification 
    header('HTTP/1.1 200 OK'); 

    // Build the required acknowledgement message out of the notification just received
    $req = 'cmd=_notify-validate';
    foreach ($_POST as $key => $value) 
        $value = urlencode(stripslashes($value));
        $req  .= "&$key=$value";
    
    $postdata = $req;
    
    // Assign payment notification values 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           = getValue($_POST['txn_id']);
    $receiver_email   = getValue($_POST['receiver_email']);
    $payer_email      = getValue($_POST['payer_email']);
    $custom           = (int)$_POST['custom'];

    $connectedIp = $_SERVER['REMOTE_ADDR'];
    mysql_insert("INSERT INTO `paypal` VALUES ('0', '$txn_id', 'Connection from IP: $connectedIp', '0', '0', '0')");
    
    $status = VerifyPaypalIPN();
    if ($status) 
        // Check that the payment_status is Completed
        if ($payment_status == 'Completed') 

            
            // Check that txn_id has not been previously processed
            $txn_id_check = mysql_select_single("SELECT `txn_id` FROM `paypal` WHERE `txn_id`='$txn_id'");
            if ($txn_id_check !== false) 
                // Check that receiver_email is your Primary PayPal email
                if ($receiver_email == $paypal['email']) 
                    
                    $status = true;
                    $paidMoney = 0;
                    $paidPoints = 0;

                    foreach ($prices as $priceValue => $pointsValue) 
                        if ($priceValue == $payment_amount) 
                            $paidMoney = $priceValue;
                            $paidPoints = $pointsValue;
                        
                    

                    if ($paidMoney == 0) $status = false; // Wrong amount of money
                    if ($payment_currency != $paypal['currency']) $status = false; // Wrong currency
                    
                    // Verify that the user haven't messed around with POST data
                    if ($status) 
                        // transaction log
                        mysql_insert("INSERT INTO `paypal` VALUES ('0', '$txn_id', '$payer_email', '$custom', '".$paidMoney."', '".$paidPoints."')");
                        
                        // Process payment
                        $data = mysql_select_single("SELECT `premium_points` AS `old_points` FROM `accounts` WHERE `id`='$custom';");

                        // Give points to user
                        $new_points = $data['old_points'] + $paidPoints;
                        mysql_update("UPDATE `accounts` SET `premium_points`='$new_points' WHERE `id`='$custom'");
                    
                  else 
                    $pmail = $paypal['email'];
                    mysql_insert("INSERT INTO `paypal` VALUES ('0', '$txn_id', 'ERROR: Wrong mail. Received: $receiver_email, configured: $pmail', '0', '0', '0')");
                
            
        
     else 
        // Something is wrong
        mysql_insert("INSERT INTO `paypal` VALUES ('0', '$txn_id', 'ERROR: Invalid data. $postdata', '0', '0', '0')");
    
?>

【问题讨论】:

【参考方案1】:

您可以在https://www.paypal.com/cgi-bin/webscr?cmd=_display-ipns-history查看您帐户的 IPN 历史记录

如果您收到所有您期望的 IPN,那么您需要调试您的侦听器。添加日志以确定出错的地方,例如无法回帖以验证 IPN。记录所有内容以确定错误是什么。同时检查您的网络服务器日志。

有关 IPN 的文档位于:https://developer.paypal.com/docs/api-basics/notifications/ipn/

【讨论】:

以上是关于PayPal IPN 有时不更新数据库的主要内容,如果未能解决你的问题,请参考以下文章

IPN 验证返回 INVALID,因为 PayPal 在 POST 中向 IPN 侦听器发送了不正确的字符集

PayPal IPN 更新以适应 HTTP1.1 - 对等方重置连接

如何使用 paypal IPN 并更新 sql 查询?

PayPal IPN 沙盒 - 更改通知 URL 不会更新

POODLE 更新后,PayPal IPN 停止使用 Tomcat/Open SSL

Paypal IPN 未检索变量