2012-08-02 53 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错误页面。