2012-08-02 55 views
3

我使用Wordpress插件Donate Plus,它在一段時間內還沒有更新,而且對於大多數用戶來說它不能正常工作。所以我對代碼做了一些修改,試圖讓它再次運行。除了在我的PayPal賬戶的IPN歷史記錄中,所有交易都具有「重試」狀態並具有404的HTTP響應代碼,我的一切工作都很好。PayPal IPN傳送狀態設置爲「重試」HTTP響應代碼404

腳本中有一個IPN調試功能,它返回「已驗證IPN交易[已完成]「,表明一切都已經完成。但是,我收到了多條調試消息,發送了多條感謝消息以及多條條目到我的MySQL數據庫中,所有這些我都認爲與「重試」問題有關。

我已經在PayPal中手動設置了通知URL,因爲我聽說這可以解決一些問題。不過,我仍然遇到同樣的問題。

我瞭解腳本需要將完整的未更改的IPN消息發送回PayPal;即消息必須以相同的順序包含相同的字段,並且以與原始消息相同的方式編碼。但是我不確定如何檢查$ postipn返回的內容,以便檢查這是否是問題。

我包括在任何人的情況下充分paypal.php下面的腳本能發現什麼問題是:

<?php 
    /* 
    //************************************************************ 
    //************************************************************ 
    //** Bugs fixed by...          ** 
    //**              ** 
    //** Copyright Encentra 2011        ** 
    //** www.encentra.se          ** 
    //** consultant: Johan Rufus Lagerström     ** 
    //************************************************************ 
    //************************************************************ 
    */ 

######################################################### 
#              # 
# File   : PayPal.php       # 
# Version   : 1.9        # 
# Last Modified : 12/15/2005       # 
# Copyright  : This program is free software; you # 
# can redistribute it and/or #modify it under the terms # 
# of the GNU General Public License as published by the # 
# Free Software Foundation        # 
# See the #GNU General Public License for more details. # 
#    DO NOT REMOVE LINK      # 
# Visit: http://www.belahost.com for updates/scripts # 
######################################################### 
# THIS SCRIPT IS FREEWARE AND IS NOT FOR RE-SALE  # 
######################################################### 

require("../../../wp-blog-header.php"); 
global $wpdb; 
$dplus = get_option('DonatePlus'); 
$email_IPN_results = $dplus['IPN_email']; 
$tmp_nl = "\r\n"; 

if(class_exists('DonatePlus'))$donateplus = new DonatePlus(); 

#1 = Live on PayPal Network 
#2 = Testing with www.BelaHost.com/pp 
#3 = Testing with the PayPal Sandbox 
$verifymode  = $dplus['testing_mode']; # be sure to change value for testing/live! 
# Send notifications to here 
$send_mail_to = $dplus['paypal_email']; 
# subject of messages 
$sysname  = "Donate Plus - Paypal IPN Transaction"; 
# Your primary PayPal e-mail address 
//$paypal_email  = $dplus['paypal_email']; 
# Your sendmail path 
//$mailpath   = "/usr/sbin/sendmail -t"; 
#the name you wish to see the messages from 
//$from_name  = $dplus['ty_name']; 
#the emails will be coming from 
//$from_email = $dplus['ty_email']; 


# Convert Super globals For backward compatibility 
if(phpversion() <= "4.0.6") {$_POST=($HTTP_POST_VARS);} 

# Check for IPN post if none then return 404 error. 
if (!$_POST['txn_type']){ 
    if($email_IPN_results) send_mail($send_mail_to,$sysname." [ERROR - 404]","IPN Fail: 404 error!","",__LINE__); 
    header("Status: 404 Not Found"); 
    die(); 
}else{ 
    header("Status: 200 OK"); 
} 

# Now we Read the Posted IPN 
$postvars = array(); 

//print_r($_POST); 
foreach ($_POST as $ipnvars => $ipnvalue){ 
    $postvars[] = $ipnvars; $postvals[] = $ipnvalue; 
} 
# Now we ADD "cmd=_notify-validate" for Post back Validation 
$postipn = 'cmd=_notify-validate'; 
$orgipn  = '<b>Posted IPN variables in order received:</b><br><br>'; 
# Prepare for validation 
for($x=0; $x < count($postvars); $x++){ 
    $y   = $x+1; 
    $postkey = $postvars[$x]; 
    $postval = $postvals[$x]; 
    $postipn .= "&".$postkey."=".urlencode($postval); 
    $orgipn  .= "<b>#".$y."</b> Key: ".$postkey." <b>=</b> ".$postval."<br>"; 
} 


if($verifymode == 1){  //1 = Live on PayPal Network 
    ## Verify Mode 1: This will post the IPN variables to the Paypal Network for Validation 
    $port = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30); 
    //$port = fsockopen ("paypal.com", 80, $errno, $errstr, 30); 
    $header = "POST /cgi-bin/webscr HTTP/1.0\r\n". 
    "Host: www.paypal.com\r\n". 
    "Content-Type: application/x-www-form-urlencoded\r\n". 
    "Content-Length: ".strlen($postipn)."\r\n\r\n"; 
}elseif ($verifymode == 2){ //2 = Testing with www.BelaHost.com/pp 
    ## Verify Mode 2: This will post the IPN variables to Belahost Test Script for validation 
    ## Located at www.belahost.com/pp/index.php 
    $port = fsockopen ("www.belahost.com", 80, $errno, $errstr, 30); 
    $header = "POST /pp/ HTTP/1.0\r\n". 
    "Host: www.belahost.com\r\n". 
    "Content-Type: application/x-www-form-urlencoded\r\n". 
    "Content-Length: ".strlen($postipn)."\r\n\r\n";   
}elseif ($verifymode == 3){ //3 = Testing with the PayPal Sandbox 
    $port = fsockopen ("ssl://www.sandbox.paypal.com", 443, $errno, $errstr, 30); 
    $header = "POST /cgi-bin/webscr HTTP/1.0\r\n". 
    "Host: www.sandbox.paypal.com\r\n". 
    "Content-Type: application/x-www-form-urlencoded\r\n". 
    "Content-Length: ".strlen($postipn)."\r\n\r\n"; 
}else{ 
    $error=1; 
    //echo "CheckMode: ".$verifymode." is invalid!"; 
    if($email_IPN_results) send_mail($send_mail_to,$sysname." [ERROR - Misc]","Fail: CheckMode: ".$verifymode." is invalid!","",__LINE__); 
    die(); 
} 


# Error at this point: If at this point you need to check your Firewall or your Port restrictions? 
if (!$port && !$error){ 
    //echo "Problem: Error Number: ".$errno." Error String: ".$errstr; 
    #Here is a small email notification so you know if your system ever fails   
    if($email_IPN_results) send_mail($send_mail_to,$sysname." [ERROR - Misc]","Your Paypal System failed due to $errno and string $errstr","",__LINE__);   
    die(); 
}else{ 
    # If No Errors to this point then we proceed with the processing. 
    # Open port to paypal or test site and post Varibles. 
    fputs ($port, $header.$postipn); 
    while (!feof($port)){ 
     $reply = fgets ($port, 1024); 
     $reply = trim ($reply); 
    } 

    # Prepare a Debug Report 
    $ipnreport = $orgipn."<br><b>"."IPN Reply: ".$reply."</b>"; 

    # Buyer Information 
    $address_city   = $_POST['address_city']; 
    $address_country  = $_POST['address_country']; 
    $address_country_code = $_POST['address_country_code']; 
    $address_name   = $_POST ['address_name']; 
    $address_state   = $_POST['address_state']; 
    $address_status   = $_POST['address_status']; 
    $address_street   = $_POST['address_street']; 
    $address_zip   = $_POST['address_zip']; 
    $first_name    = $_POST['first_name']; 
    $last_name    = $_POST['last_name']; 
    $payer_business_name = $_POST['payer_business_name']; 
    $payer_email   = $_POST['payer_email']; 
    $payer_id    = $_POST['payer_id']; 
    $payer_status   = $_POST['payer_status']; 
    $residence_country  = $_POST['residence_country']; 
    # Below Instant BASIC Payment Notifiction Variables 
    $business    = $_POST['business']; 
    $item_name    = $_POST['item_name']; 
    $item_number   = $_POST['item_number']; 
    $quantity    = $_POST['quantity']; 
    $receiver_email   = $_POST['receiver_email']; 
    $receiver_id   = $_POST['receiver_id']; 
    #Advanced and Customer information 
    $custom     = $_POST['custom']; 
    $invoice    = $_POST['invoice']; 
    $memo     = $_POST['memo']; 
    $option_name1   = $_POST['option_name1'];  //name 
    $option_name2   = $_POST['option_name2']; 
    $option_selection1  = $_POST['option_selection1']; //email 
    $option_selection2  = $_POST['option_selection2']; //comment 
    $tax     = $_POST['tax']; 
    #Website Payment Pro and Other IPN Variables 
    $auth_id    = $_POST['auth_id']; 
    $auth_exp    = $_POST['auth_exp']; 
    $auth_amount   = $_POST['auth_amount']; 
    $auth_status   = $_POST['auth_status']; 
    # Shopping Cart Information 
    $mc_gross    = $_POST['mc_gross']; 
    $mc_handling   = $_POST['mc_handling']; 
    $mc_shipping   = $_POST['mc_shipping']; 
    $num_cart_items   = $_POST['num_cart_items']; 
    # Other Transaction Information 
    $parent_txn_id   = $_POST['parent_txn_id']; 
    $payment_date   = $_POST['payment_date']; 
    $payment_status   = $_POST['payment_status']; 
    $payment_type   = $_POST['payment_type']; 
    $pending_reason   = $_POST['pending_reason']; 
    $reason_code   = $_POST['reason_code']; 
    $remaining_settle  = $_POST['remaining_settle']; 
    $transaction_entity  = $_POST['transaction_entity']; 
    $txn_id     = $_POST['txn_id']; 
    $txn_type    = $_POST['txn_type']; 
    # Currency and Exchange Information 
    $exchange_rate   = $_POST['exchange_rate']; 
    $mc_currency   = $_POST['mc_currency']; 
    $mc_fee     = $_POST['mc_fee']; 
    $payment_fee   = $_POST['payment_fee']; 
    $payment_gross   = $_POST['payment_gross']; 
    $settle_amount   = $_POST['settle_amount']; 
    $settle_currency  = $_POST['settle_currency']; 
    # Auction Information 
    $for_auction   = $_POST['for_auction']; 
    $auction_buyer_id  = $_POST['auction_buyer_id']; 
    $auction_closing_date = $_POST['auction_closing_date']; 
    $auction_multi_item  = $_POST['auction_multi_item']; 
    # Below are Subscription - Instant Payment Notifiction Variables 
    $subscr_date   = $_POST['subscr_date']; 
    $subscr_effective  = $_POST['subscr_effective']; 
    $period1    = $_POST['period1']; 
    $period2    = $_POST['period2']; 
    $period3    = $_POST['period3']; 
    $amount1    = $_POST['amount1']; 
    $amount2    = $_POST['amount2']; 
    $amount3    = $_POST['amount3']; 
    $mc_amount1    = $_POST['mc_amount1']; 
    $mc_amount2    = $_POST['mc_amount2']; 
    $mc_amount3    = $_POST['mc_amount3']; 
    $recurring    = $_POST['recurring']; 
    $reattempt    = $_POST['reattempt']; 
    $retry_at    = $_POST['retry_at']; 
    $recur_times   = $_POST['recur_times']; 
    $username    = $_POST['username']; 
    $password    = $_POST['password']; 
    $subscr_id    = $_POST['subscr_id']; 
    # Complaint Variables Used when paypal logs a complaint 
    $case_id    = $_POST['case_id']; 
    $case_type    = $_POST['case_type']; 
    $case_creation_date  = $_POST['case_creation_date']; 
    #Last but not least 
    $notify_version   = $_POST['notify_version']; 
    $verify_sign   = $_POST['verify_sign']; 

    #There are certain variables that we will not store for cart since they are dynamic      
    #such as mc_gross_x as they will be forever changing/increasing your script must check these 

    #IPN was Confirmed as both Genuine and VERIFIED 
    if(!strcmp($reply, "VERIFIED")){ 
     /* Now that IPN was VERIFIED below are a few things which you may want to do at this point. 
     1. Check that the "payment_status" variable is: "Completed" 
     2. If it is Pending you may want to wait or inform your customer? 
     3. You should Check your datebase to ensure this "txn_id" or "subscr_id" is not a duplicate. txn_id is not sent with subscriptions! 
     4. Check "payment_gross" or "mc_gross" matches match your prices! 
     5. You definately want to check the "receiver_email" or "business" is yours. 
     6. We have included an insert to database for table paypal_ipn 
     */ 
     $split = explode(':', $item_number); 
     $display = $split[0]; 
     $uID = $split[1]; 
     $url = 'http://'.str_replace('http://','',$option_name2); 

     if(!$mc_gross)$mc_gross = $payment_gross; 
     $table_name = $wpdb->prefix."donations"; 

     //kontrollera om transaktionen redan finns sparad 
     $tmp_txn_id  = $wpdb->escape($txn_id); 
     $tmp_count  = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $table_name WHERE txn_id='$tmp_txn_id';")); 


     //if($payment_status == 'Completed'){ 
     if($tmp_count == 0){ 
      //all pin:s som kommer in tolkar vi som complete 
      $tmp_payment_status = "Completed"; 
      $mc_net = $mc_gross - $mc_fee; 
      //USE SECURE INSERT! 
      $wpdb->query(
       $wpdb->prepare("INSERT INTO $table_name 
       (name, email, url, comment, display, amount, charge, net, currency, date, user_id, status, txn_id) 
       VALUES (%s, %s, %s, %s, %d, %s, %s, %s, %s, %s, %d, %s, %s)", 
       $option_name1, $option_selection1, $url, strip_tags($option_selection2), $display, $mc_gross, $mc_fee, $mc_net, $mc_currency, date('Y-m-d H:i:s'), $uID, $tmp_payment_status, $txn_id) 
      ); 
      //send payer thank you email about where to download 
      global $currency; 
      $subject = stripslashes($dplus['ty_subject']); 
      $prefix  = $currency[$mc_currency]['symbol']; 
      $amount  = $prefix.$mc_gross.' '.$mc_currency; 
      $payer_msg = nl2br($donateplus->TagReplace(stripslashes($dplus['ty_emailmsg']), $option_name1, $amount)); 
      //$payer_msg = utf8_encode($payer_msg); 
      //echo '<br />'.$payer_msg; 
      $headers = 'MIME-Version: 1.0'."\r\n"; 
      //$headers .= 'Content-type: text/html; charset=iso-8859-1'."\r\n"; 
      $headers .= 'Content-type: text/html; charset=utf-8'."\r\n"; 
      $headers .= 'From: '.$dplus['ty_name'].' <'.$dplus['ty_email'].'>'."\r\n"; 
      wp_mail($option_selection1, $subject, $payer_msg, $headers); 
      //wp_mail($notify_email, 'New Donation Recieved!', "Donation from $option_name1 for $payment_amount"); 
      //echo $postquery; 
      if($email_IPN_results) send_mail($send_mail_to,$sysname." [PIN - Completed]","\n Verified IPN Transaction [Completed] \n \n$ipnreport\n","",__LINE__); 
     }else{ 
      //not "Completed" 
      //tar bort nedan, annars trilalr det in 10 mail per donation 
      //send_mail($send_mail_to,$sysname." [PIN - $payment_status]","\n Verified IPN Transaction [$payment_status] \n \n$ipnreport\n","",__LINE__); 
     } 


    }elseif(!strcmp($reply, "INVALID")){ # IPN was Not Validated as Genuine and is INVALID 
     /* Now that IPN was INVALID below are a few things which you may want to do at this point. 
     1. Check your code for any post back Validation problems! 
     2. Investigate the Fact that this Could be an attack on your script IPN! 
     3. If updating your DB, Ensure this "txn_id" is Not a Duplicate! 
     */ 

     # Remove Echo line below when live 
     //echo $ipnreport; 
     if($email_IPN_results) send_mail($send_mail_to,$sysname." [ERROR - Invalid]","Invalid IPN Transaction".$tmp_nl.$tmp_nl.$ipnreport,"",__LINE__); 

    }else{ #ERROR 
     # If your script reaches this point there is a problem. Communication from your script to test/paypal pages could be 1 reason. 
     echo $ipnreport; 
     if($email_IPN_results) send_mail($send_mail_to,$sysname." [ERROR - Misc]","FATAL ERROR No Reply at all".$tmp_nl.$tmp_nl.$ipnreport,"",__LINE__); 
    } 


    #Terminate the Socket connection and Exit 
    fclose ($port); 
    die(); 
} 







/* ================================= 
     Below are functions 
    ================================= */ 

# Email function 
function send_mail($to, $subj, $body, $headers="",$tmp_line=0){ 
    //global 
    global $tmp_nl; 

    //var_dump till en sträng 
    $posts = var_export($_POST, true); 

    //body 
    $tmp_body = "===================================".$tmp_nl. 
       $subj." [line: $tmp_line]".$tmp_nl. 
       "===================================".$tmp_nl. 
       $body.$tmp_nl. 
       $tmp_nl. 
       "===================================".$tmp_nl. 
       $posts; 

    //skickar mail 
    wp_mail($to, $subj, $tmp_body, $headers); 

    /* 
    global $from_name, $from_email, $mailpath; 

# E-mail Configuration 
    $announce_subject = "$subj"; 
    $announce_from_email = "$from_email"; 
    $announce_from_name = "$from_name"; 
    $announce_to_email = "$to"; 
    $MP = "$mailpath"; 
    $spec_envelope = 1; 
    # End email config 
# Access Sendmail 
# Conditionally match envelope address 
    if(isset($spec_envelope)) 
    { 
    $MP .= " -f $announce_from_email"; 
    } 
    $fd = popen($MP,"w"); 
    fputs($fd, "To: $announce_to_email\n"); 
    fputs($fd, "From: $announce_from_name <$announce_from_email>\n"); 
    fputs($fd, "Subject: $announce_subject\n"); 
    fputs($fd, "X-Mailer: MyPayPal_Mailer\n"); 
    fputs($fd, "Content-Type: text/html\n"); 
    fputs($fd, $body); # $body will be sent when the function is used 
    pclose($fd); 
    */ 
} 

?> 

.htaccess文件

# BEGIN WordPress 
<IfModule mod_rewrite.c> 
RewriteEngine On 
RewriteBase/
RewriteRule ^index\.php$ - [L] 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteRule . /index.php [L] 
</IfModule> 

# END WordPress 

<Files wp-cron.php> 
allow from all 
Satisfy Any 
</Files> 

AddType text/x-component .htc 

回答

0

對我來說,似乎有隻有幾種可能性。

代碼

if (!$_POST['txn_type']){ 
    if($email_IPN_results) send_mail($send_mail_to,$sysname." [ERROR - 404]","IPN Fail: 404 error!","",__LINE__); 
    header("Status: 404 Not Found"); 
    die(); 
}else{ 
    header("Status: 200 OK"); 
} 

顯然是值得研究的一個部分,因爲它輸出404在我的IPN處理程序中,我使用empty($_POST)你使用過!$_POST['txn_type']。您也可以嘗試!isset($_POST['txn_type'])!$_POST['txn_type']從字面上評估txn_type是否等於false,這不像專門檢查該值是否一般存在那樣可靠。我懷疑這是實際的問題,但這是值得關注的。

404的一些其他可能的原因可能是:

  • 某處在您的PayPal按鈕代碼,它設置了一個不存在的IPN URL。
  • 您手動輸入的IPN網址存在拼寫錯誤。
  • 您的htaccess阻止直接訪問IPN URL。如果htaccess執行任何重定向(例如從domain.com到www.domain.com),並且您使用domain.com作爲IPN域,則重定向將導致所有發佈數據被丟棄,然後您的代碼將準確輸出404錯誤。

我的錢會是它是一個htaccess重定向問題。我非常熟悉打破錶單發佈的重定向。

編輯

你可以嘗試做一個跳過貝寶完全只是爲了測試IPN一個簡單的測試形式。一些簡單的東西

<form method="post" action="IPN_URL"> 
<input type='hidden' name='txn_type' value='subscr_payment'> 
<input type='submit' value='Test IPN'></form> 

很明顯,用適當的URL替換IPN_URL。如果提交時沒有404,那麼腳本設置IPN URL的方式可能有問題。

您也可以檢查服務器日誌中的404錯誤,並將日誌中缺失的URL與您期望看到的URL進行比較。

EDIT 2

僅供參考,我做了一個測試有了這個插件,你使用相同版本的它完美地工作的時候了。我沒有在PayPal中設置IPN網址。我將「測試模式」設置爲「Live with Paypal」並填寫了PayPal電子郵件地址字段,並將所有其他設置都設爲其默認值。我付了款,IPN和其他一切正常。我正在使用3.4.1版本的普通WP設置(不是多站點)。

您使用WP多站點嗎?我知道設置頁面中顯示的URL在這些情況下可能是錯誤的。

看完http://wordpress.org/support/topic/plugin-donate-plus-ipn-not-working之後,看起來實際上這個插件存在一些問題。我快速瀏覽了一下,http://wordpress.org/extend/plugins/paypal-donations/似乎已經更新了一點,而且它似乎沒有與另一個相同的怪癖。你可以閱讀關於它here。最壞的情況,你可以切換到那個。

+0

感謝您的回答。根據你上面提到的代碼,我已經評論了這一點,並將兩個標題設置爲「Status:200 OK」,但仍然出現404錯誤。此外,腳本不會死亡,並且我正在收到以「已驗證」狀態發送的IPN調試電子郵件,所以我非常確定這不是問題。就其他可能性而言,我確信IPN URL是正確的(點2)。我將檢查另外兩個問題並儘快回覆您。 – Nick 2012-08-10 12:01:19

+0

就重定向問題而言(第3點),我之前將通知URL設置爲'http:// www。[URL ...]',我仍然收到404錯誤。這是否意味着問題與重定向無關? – Nick 2012-08-10 12:58:49

+0

關於第1點,處理提交PayPal付款的腳本僅將IPN URL設置在一個地方,這是正確的URL。 – Nick 2012-08-10 13:02:07

0

今天我有這個問題...貝寶IPN的歷史記錄顯示通知爲retrying即使我指定的notify_url是有效的。

問題是貝寶將數據發送到該網址的https://(安全)版本; 如果您在瀏覽器中粘貼https://網址,您可能會發現您的主機未顯示該網站超過https://,這也是Paypal所看到的,通常是404錯誤頁面。