PHP Paypal IPN:交易未确认

发布于 2024-12-13 01:43:34 字数 3485 浏览 0 评论 0原文

我正在为自定义数字电子商务创建 IPN,但有一个问题: 一切正常文件,我在数据库中创建一个“待付款”,其 ID 称为 PID(付款 ID),用户转到 paypal 页面,当付款完成时,paypal 在 IPN 侦听器上与我联系,检查是否付款完成并启用用户购买的所有媒体。

我使用 micah carrick php 类成功创建了一个 IPN ( http://www.micahcarrick.com/php-paypal-ipn- Integration-class.html ),一切正常,除了我总是得到待定付款状态并且无法得到确认。

我目前正在 paypal 沙箱中对其进行测试,我创建了 2 个买家和 1 个卖家,并且我已经为每个人启用了“付款审核”。

我也尝试了不同的方法,但总是得到相同的结果。

代码: file_put_contents('ipn.log',"\n>IPN\n",FILE_APPEND);

//Check the Payment ID,i pass it to the IPN by GET
if(!isset($_GET['pid'])|| !is_numeric($_GET['pid'])){
     file_put_contents('ipn.log',"\n!!!IPN:INVALID PID(".$_GET['pid'].")!!!\n",FILE_APPEND);
     exit('PID INVALIDO!');

}


//Logging errors
ini_set('log_errors', true);
ini_set('error_log', dirname(__FILE__).'/ipn_errors.log');

// instantiate the IpnListener class  
require('ipnlistener.php');
$listener = new IpnListener();      


//Use the sandbox instead of going "live"
$listener->use_sandbox = true;


//validate the request

try {
   $listener->requirePostMethod();
   $verified = $listener->processIpn();
} 
catch (Exception $e) {
   error_log($e->getMessage());
   exit(0);
}


//Just for debug
file_put_contents('ipn.log',"\n###IPN:verifying...###\n",FILE_APPEND); 


if($verified){//the payment is verified                                                                           
        file_put_contents('ipn.log',"\n###IPN:transaction verified(confirmed=".$_POST['payment_status'].")###\n".$listener->getTextReport(),FILE_APPEND); 
        /*
        Once you have a verified IPN you need to do a few more checks on the POST
        fields--typically against data you stored in your database during when the
        end user made a purchase (such as in the "success" page on a web payments
        standard button). The fields PayPal recommends checking are:
        1. Check the $_POST['payment_status'] is "Completed"
        2. Check that $_POST['txn_id'] has not been previously processed
        3. Check that $_POST['receiver_email'] is your Primary PayPal email
        4. Check that $_POST['payment_amount'] and $_POST['payment_currency']
        are correct
        Since implementations on this varies, I will leave these checks out of this
        example and just send an email using the getTextReport() method to get all
        of the details about the IPN.
        */  
        if($_POST['payment_status']=="Completed"){
                //--check if the price is right and enable the user media--
                confirm_payment($_GET['pid'],$_POST['payment_amount']);
                file_put_contents('ipn.log',"\n###IPN:Transaction completed###\n".$listener->getTextReport(),FILE_APPEND);    
        }                                                                        

} 

else {
/*
An Invalid IPN *may* be caused by a fraudulent transaction attempt. It's
a good idea to have a developer or sys admin manually investigate any
invalid IPN.
*/

   file_put_contents('ipn.log',"\n###IPN:ERROR###\n".$listener->getTextReport(),FILE_APPEND);    

}

我创建的调试日志总是这样

<强>> IPN <--它表明该 IPN 被正确调用
##IPN:verifying...### <--IPN 正在验证交易
##IPN:交易已验证(confirmed=Pending)<--交易已验证,但尚未确认,因为它正在等待,我无法启用下载!

I'm creating an IPN for a custom digital ecommerce but i have a problem:
everything works file,i create a "pending payment" in my database with an ID that i call PID (payment id),the user go to the paypal page and when the payment is completed paypal contact me on the IPN listener that checks if the payment is completed and enable all the media that the user bought.

I successfully created an IPN using the micah carrick php class
( http://www.micahcarrick.com/php-paypal-ipn-integration-class.html ) and everything is working exept i ALWAYS get a pendign payment status and i can't get a confirmed one.

I'm currently testing it in the paypal sandbox,i created 2 buyers and one seller and i have enabled the "payment review" for everybody.

I tryed also different approach but i always get the same result.

Code:
file_put_contents('ipn.log',"\n>IPN\n",FILE_APPEND);

//Check the Payment ID,i pass it to the IPN by GET
if(!isset($_GET['pid'])|| !is_numeric($_GET['pid'])){
     file_put_contents('ipn.log',"\n!!!IPN:INVALID PID(".$_GET['pid'].")!!!\n",FILE_APPEND);
     exit('PID INVALIDO!');

}


//Logging errors
ini_set('log_errors', true);
ini_set('error_log', dirname(__FILE__).'/ipn_errors.log');

// instantiate the IpnListener class  
require('ipnlistener.php');
$listener = new IpnListener();      


//Use the sandbox instead of going "live"
$listener->use_sandbox = true;


//validate the request

try {
   $listener->requirePostMethod();
   $verified = $listener->processIpn();
} 
catch (Exception $e) {
   error_log($e->getMessage());
   exit(0);
}


//Just for debug
file_put_contents('ipn.log',"\n###IPN:verifying...###\n",FILE_APPEND); 


if($verified){//the payment is verified                                                                           
        file_put_contents('ipn.log',"\n###IPN:transaction verified(confirmed=".$_POST['payment_status'].")###\n".$listener->getTextReport(),FILE_APPEND); 
        /*
        Once you have a verified IPN you need to do a few more checks on the POST
        fields--typically against data you stored in your database during when the
        end user made a purchase (such as in the "success" page on a web payments
        standard button). The fields PayPal recommends checking are:
        1. Check the $_POST['payment_status'] is "Completed"
        2. Check that $_POST['txn_id'] has not been previously processed
        3. Check that $_POST['receiver_email'] is your Primary PayPal email
        4. Check that $_POST['payment_amount'] and $_POST['payment_currency']
        are correct
        Since implementations on this varies, I will leave these checks out of this
        example and just send an email using the getTextReport() method to get all
        of the details about the IPN.
        */  
        if($_POST['payment_status']=="Completed"){
                //--check if the price is right and enable the user media--
                confirm_payment($_GET['pid'],$_POST['payment_amount']);
                file_put_contents('ipn.log',"\n###IPN:Transaction completed###\n".$listener->getTextReport(),FILE_APPEND);    
        }                                                                        

} 

else {
/*
An Invalid IPN *may* be caused by a fraudulent transaction attempt. It's
a good idea to have a developer or sys admin manually investigate any
invalid IPN.
*/

   file_put_contents('ipn.log',"\n###IPN:ERROR###\n".$listener->getTextReport(),FILE_APPEND);    

}

The debug log i created is always like this

> IPN <--it states that the ipn was correctly called
##IPN:verifying...### <--the IPN is verifying the transaction
##IPN:transaction verified(confirmed=Pending)<--the transaction is verified but it's NOT confirmed because it's pending,i can't enable the download!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

天涯离梦残月幽梦 2024-12-20 01:43:34

禁用付款审核。付款审核将始终将其置于待处理状态。
这实际上就是它的全部要点;能够使用负面测试和付款审核来测试“负面”场景来验证您的错误处理。

Disable Payment Review. Payment Review will always place them in a Pending state.
That's actually the whole point of it; to be able to use negative testing and payment review in order to test 'negative' scenario's to verify your error handling.

梨涡少年 2024-12-20 01:43:34

我不熟悉你正在使用的类,但这就是我在所有工作中一直在 PP IPN 使用的类,它就像一种魅力,也许有一天我会做出自己的面向对象的方式,但现在这似乎来完成这个技巧,我希望它对你有帮助。
(只是为了让您走上正轨,我对传入和传出 PP 的消息使用相同的文件)

$sandbox="sandbox.";
$paypal_email="[email protected]";

$item_id = "1XN12PJ";
$cost = "22.30";
$item_name = 'My Item';
$return_url = "http://www.example.com/return";
$cancel_url = "http://www.example.com/cancel";
$notify_url = "http://www.example.com/notify";

function check_txnid($tnxid){
    global $link;
    $sql = mysql_query("SELECT * FROM `payments_pending` WHERE `txnid` = '$tnxid'", $link);     
    return mysql_num_rows($sql)==0;
}

function check_price($price, $id){
    $sql = mysql_query("SELECT `cost` FROM `orders` WHERE `id` = '$id'");
    if (mysql_numrows($sql) != 0) {
        $row = mysql_fetch_array($sql);
        $num = (float) $row['cost'];
        if($num - $price == 0){
            return true;
        }
    }
    return false;
}

if (!isset($_POST["txn_id"]) && !isset($_POST["txn_type"])){    // Request TO Paypal
    // Firstly Append paypal account to querystring
    $querystring .= "?business=".urlencode($paypal_email)."&";  

    // Append amount& currency (£) to quersytring so it cannot be edited in html
    $querystring .= "lc=CA&";
    $querystring .= "currency_code=CAD&";
    $querystring .= "item_number=".$item_id."&";

    //The item name and amount can be brought in dynamically by querying the $_POST['item_number'] variable.
    $querystring .= "item_name=".urlencode($item_name)."&";
    $querystring .= "amount=".$cost."&";

    //loop for posted values and append to querystring
    foreach($_POST as $key => $value){
        $value = urlencode(stripslashes($value));
        $querystring .= "$key=$value&";
    }

    // Append paypal configs
    $querystring .= "return=".urlencode(stripslashes($return_url))."&";
    $querystring .= "cancel_return=".urlencode(stripslashes($cancel_url))."&";
    $querystring .= "notify_url=".urlencode($notify_url);

    // Append querystring with custom field
    //$querystring .= "&custom=".USERID;

    // Redirect to paypal IPN
    header('location:https://www.'.$sandbox.'paypal.com/cgi-bin/webscr'.$querystring);
    exit();
}else{      // Response FROM Paypal
    // read the post from PayPal system and add 'cmd'
    $req = 'cmd=_notify-validate';
    foreach ($_POST as $key => $value) {
        $req .= "&$key=$value";
    }

    // assign posted variables to local variables
    $data                       = array();
    $data['item_name']          = $_POST['item_name'];
    $data['item_number']        = $_POST['item_number'];
    $data['payment_status']     = $_POST['payment_status'];
    $data['payment_amount']     = $_POST['mc_gross'];
    $data['payment_currency']   = $_POST['mc_currency'];
    $data['txn_id']             = $_POST['txn_id'];
    $data['receiver_email']     = $_POST['receiver_email'];
    $data['payer_email']        = $_POST['payer_email'];
    $data['custom']             = $_POST['custom'];

    // post back to PayPal system to validate
    $header = "POST /cgi-bin/webscr HTTP/1.0\r\n";
    $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
    $header .= "Content-Length: " . strlen($req) . "\r\n\r\n";

    $fp = fsockopen ('ssl://www.'.$sandbox.'paypal.com', 443, $errno, $errstr, 30);
    if(!$fp){
        // HTTP ERROR : Do something to notify you
    }
    else {  
        fputs($fp, $header.$req);

        $res = "";
        while (!feof($fp)){
            $res .= fgets($fp, 1024);
        }

        if(strpos($res, "VERIFIED")!==false){
            // Validate payment (Check unique txnid & correct price)
            $valid_txnid = check_txnid($data['txn_id']);
            // $valid_price = check_price($data['payment_amount'], $data['item_number']);

            $valid_price = check_price($data['payment_amount'], $_POST['item_number']);
            // PAYMENT VALIDATED & VERIFIED!
            if($valid_txnid && $valid_price){
                $orderid = updatePayments($data);
                if($orderid){
                    // Payment has been made & successfully inserted into the Database

                }else{
                    // Error inserting into DB
                }
            }
            else{                   
                // Payment made but data has been changed  : Do something to notify you
            }                       
        }
        else{
            if(strpos($res, "VERIFIED")!==false){
                // PAYMENT INVALID & INVESTIGATE MANUALY!  : Do something to notify you
            }
        }
        fclose($fp);
    }   
}

I am not familiar with the class you are using, but this is what i have been using for PP IPN in all my work and it works like a charm, maybe one day i'll make my own Object Oriented way but for now this seems to be doing the trick and i hope it helps you.
(Just to get you on the right track, i am using the same file for incoming and outcoming messages to/from PP)

$sandbox="sandbox.";
$paypal_email="[email protected]";

$item_id = "1XN12PJ";
$cost = "22.30";
$item_name = 'My Item';
$return_url = "http://www.example.com/return";
$cancel_url = "http://www.example.com/cancel";
$notify_url = "http://www.example.com/notify";

function check_txnid($tnxid){
    global $link;
    $sql = mysql_query("SELECT * FROM `payments_pending` WHERE `txnid` = '$tnxid'", $link);     
    return mysql_num_rows($sql)==0;
}

function check_price($price, $id){
    $sql = mysql_query("SELECT `cost` FROM `orders` WHERE `id` = '$id'");
    if (mysql_numrows($sql) != 0) {
        $row = mysql_fetch_array($sql);
        $num = (float) $row['cost'];
        if($num - $price == 0){
            return true;
        }
    }
    return false;
}

if (!isset($_POST["txn_id"]) && !isset($_POST["txn_type"])){    // Request TO Paypal
    // Firstly Append paypal account to querystring
    $querystring .= "?business=".urlencode($paypal_email)."&";  

    // Append amount& currency (£) to quersytring so it cannot be edited in html
    $querystring .= "lc=CA&";
    $querystring .= "currency_code=CAD&";
    $querystring .= "item_number=".$item_id."&";

    //The item name and amount can be brought in dynamically by querying the $_POST['item_number'] variable.
    $querystring .= "item_name=".urlencode($item_name)."&";
    $querystring .= "amount=".$cost."&";

    //loop for posted values and append to querystring
    foreach($_POST as $key => $value){
        $value = urlencode(stripslashes($value));
        $querystring .= "$key=$value&";
    }

    // Append paypal configs
    $querystring .= "return=".urlencode(stripslashes($return_url))."&";
    $querystring .= "cancel_return=".urlencode(stripslashes($cancel_url))."&";
    $querystring .= "notify_url=".urlencode($notify_url);

    // Append querystring with custom field
    //$querystring .= "&custom=".USERID;

    // Redirect to paypal IPN
    header('location:https://www.'.$sandbox.'paypal.com/cgi-bin/webscr'.$querystring);
    exit();
}else{      // Response FROM Paypal
    // read the post from PayPal system and add 'cmd'
    $req = 'cmd=_notify-validate';
    foreach ($_POST as $key => $value) {
        $req .= "&$key=$value";
    }

    // assign posted variables to local variables
    $data                       = array();
    $data['item_name']          = $_POST['item_name'];
    $data['item_number']        = $_POST['item_number'];
    $data['payment_status']     = $_POST['payment_status'];
    $data['payment_amount']     = $_POST['mc_gross'];
    $data['payment_currency']   = $_POST['mc_currency'];
    $data['txn_id']             = $_POST['txn_id'];
    $data['receiver_email']     = $_POST['receiver_email'];
    $data['payer_email']        = $_POST['payer_email'];
    $data['custom']             = $_POST['custom'];

    // post back to PayPal system to validate
    $header = "POST /cgi-bin/webscr HTTP/1.0\r\n";
    $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
    $header .= "Content-Length: " . strlen($req) . "\r\n\r\n";

    $fp = fsockopen ('ssl://www.'.$sandbox.'paypal.com', 443, $errno, $errstr, 30);
    if(!$fp){
        // HTTP ERROR : Do something to notify you
    }
    else {  
        fputs($fp, $header.$req);

        $res = "";
        while (!feof($fp)){
            $res .= fgets($fp, 1024);
        }

        if(strpos($res, "VERIFIED")!==false){
            // Validate payment (Check unique txnid & correct price)
            $valid_txnid = check_txnid($data['txn_id']);
            // $valid_price = check_price($data['payment_amount'], $data['item_number']);

            $valid_price = check_price($data['payment_amount'], $_POST['item_number']);
            // PAYMENT VALIDATED & VERIFIED!
            if($valid_txnid && $valid_price){
                $orderid = updatePayments($data);
                if($orderid){
                    // Payment has been made & successfully inserted into the Database

                }else{
                    // Error inserting into DB
                }
            }
            else{                   
                // Payment made but data has been changed  : Do something to notify you
            }                       
        }
        else{
            if(strpos($res, "VERIFIED")!==false){
                // PAYMENT INVALID & INVESTIGATE MANUALY!  : Do something to notify you
            }
        }
        fclose($fp);
    }   
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文