2011-10-30 113 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