Paypal IPN PHP脚本无法插入数据库

I read some answers trying to solve my problem but nothing worked. The code below is from https://github.com/Quixotix/PHP-PayPal-IPN

What I have already done:

  • set ipn url at paypal (not localhost);
  • removed "completed" condition;
  • removed "txn_id" and others conditions trying to make it works;

None of these attempts worked for me, even if I use ipn simulator.

<?php

// tell PHP to log errors to ipn_errors.log in this directory
ini_set('log_errors', true);
ini_set('error_log', dirname(__FILE__).'/ipn_errors.log');

  // intantiate the IPN listener
include('PHP-PayPal-IPN-master/ipnlistener.php');
$listener = new IpnListener();

// tell the IPN listener to use the PayPal test sandbox
$listener->use_sandbox = true;

  // try to process the IPN POST
try {
    $listener->requirePostMethod();
    $verified = $listener->processIpn();
} catch (Exception $e) {
   error_log($e->getMessage());
   exit(0);
}

if ($verified) {

$errmsg = ' <br/>';   // stores errors from fraud checks

// 1. Make sure the payment status is "Completed" 
if ($_POST['payment_status'] != 'Completed') { 
    //simply ignore any IPN that is not completed
    exit(0); 
}

// 2. Make sure seller email matches your primary account email.
if ($_POST['receiver_email'] != 'seller@sandbox.com') {
    $errmsg .= "'receiver_email' does not match: ";
    $errmsg .= $_POST['receiver_email']."
";
}

// 3. Make sure the amount(s) paid match
if ($_POST['mc_gross'] != '10') {
    $errmsg .= "'mc_gross' does not match: ";
    $errmsg .= $_POST['mc_gross']."
";
}


// 4. Make sure the currency code matches
if ($_POST['mc_currency'] != 'USD') {
    $errmsg .= "'mc_currency' does not match: ";
    $errmsg .= $_POST['mc_currency']."
";
}

// 5. Ensure the transaction is not a duplicate.
include_once("../includes/psl-config.php");
$mysqli = new mysqli(HOST, USER, PASSWORD, DATABASE);

$txn_id = mysqli_real_escape_string($mysqli, $_POST['txn_id']);
$sql = "SELECT COUNT(*) FROM paypal WHERE txn_id = '$txn_id'";
$r = mysqli_query($mysqli, $sql);

if (!$r) {
    error_log(mysqli_error($mysqli));
    exit(0);
}

$exists = $r;

if ($exists) {
    $errmsg .= "'txn_id' has already been processed: ".$_POST['txn_id']."
";
} */

if (!empty($errmsg)) {

    // manually investigate errors from the fraud checking
    $body = "IPN failed fraud checks: 
$errmsg

";
    $body .= $listener->getTextReport();
    mail('habitodigital@hotmail.com', 'IPN Fraud Warning', $body);

} else {

    // add this order to a table of completed orders
    if (isset($_POST['item_number'])) {
        $item_number = $_POST['item_number'];
    }

if($stmt = $mysqli->prepare("INSERT INTO paypal (item_number) VALUES (?)")){
            $stmt->bind_param('s', $item_number);
            $stmt->execute();   
        }else{
            $errmsg .= "Error trying to insert into DB<br/>";
            error_log(mysqli_error($mysqli));
        }                               

    // free user ads here
}

} else {
   // manually investigate the invalid IPN
   mail('habitodigital@hotmail.com', 'Invalid IPN', $listener->getTextReport());
}

?>

I´m receiving fraud email all the time. Sometimes it brings me txn_id has already been processed but how can it check this if nothing has been inserted into database?

Seems you'd recieve fraud emails when the script returns INVALID for the IPN verification,

$verified = $listener->processIpn();

IPN verification will only pass when it's posted back to PayPal exactly unchanged from what it was sent to your server, except for real fraud cases or malicious tampered data, chances are language encoding would easily casue a discrepancy on the IPN data between PayPal and your website, thus eventually leads to an INVALID result.

The best practice is that you may want to check your PayPal account encoding settings and make it to UTF-8, to ensure all types of characters can be properly formatted and avoid the verification failure.

Login to PayPal account > My Account > Profile > Language Encoding > More Options