2011-10-30 64 views
0

我正在创建一个自定义数字电子商务的IPN,但我有一个问题: 一切工作文件,我在我的数据库中创建一个“等待支付”与我称为PID的ID付款ID),用户转到贝宝页面,当付款完成后,贝宝与IPN监听器联系,检查付款是否完成并启用用户购买的所有媒体。PHP Paypal IPN:交易未确认

我成功创建IPN使用弥卡里克PHP类 (http://www.micahcarrick.com/php-paypal-ipn-integration-class.html)和一切工作exept 我总是得到一个pendign付款状态,我不能得到证实的。

我目前正在贝宝沙盒中测试它,我创建了2个买家和一个卖家,并且我已经为每个人启用了“付款审查”。

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

代码: 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 < --IT指出IPN正确称为
## IPN:验证... ## # < - IPN正在验证交易
## IPN:交易验证(确认=待定) < - 交易是验证但它没有被确认,因为它正在等待,我无法启用下载!

回答

2

禁用付款审查。付款审查将始终将它们置于待定状态。
这实际上是它的全部点;能够使用负面测试和付款审查来测试'负面'情况来验证您的错误处理。

+0

你是对的,我遵循了一个指导,相反的说明; 无论如何没有指定你必须创建一个“买家”帐户,并使用它的电子邮件作为目的地(而不是你的dev.paypal电子邮件)。 也支付的价格是$ _POST ['mc_gross'] NOT $ _POST ['payment_amount']如评论中所述。 – Plokko

0

我对你使用的课程并不熟悉,但这是我在我的所有工作中用于PP IPN的原因,它的作用就像是一种魅力,也许有一天我会让自己的面向对象但现在这似乎是在做伎俩,我希望它可以帮助你。 (只是为了让你在正确的轨道上,我使用的是相同的文件传入和outcoming消息/从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); 
    } 
} 
+0

您不检查交易状态是否已完成,因此恶意用户可以尝试使用未完成但已验证的paymet来解锁某些媒体。 至少是paypal所说的: “由于IPN消息可以在交易进度的不同阶段发送,因此在启用商品发货或允许下载数字媒体之前,请确保交易的付款状态已”完成“。 https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_admin_IPNIntro – Plokko

+0

我认为这是诀窍:'if(strpos($ res,“VERIFIED”)!==假){' 验证意味着COMPLETED否? (我可能是错的,但我的脚本是基于一个paypal教程:https://cms.paypal.com/cms_content/CA/en_US/files/developer/IPN_PHP_41。txt) –

+0

不,这是不正确的。验证只意味着IPN消息是真实的,但它没有提及事务状态。 – Robert