2015-04-04 103 views
1

我在寫一個WordPress插件,通過PayPal處理付款。我有一個PayPal IPN腳本,在支付成功時發送電子郵件通知(除了PayPal的電子郵件通知)。我的插件的一些用戶報告說,他們在幾天內收到此電子郵件通知的多個副本。PayPal IPN重複運行

我在開發插件時就發現了這個問題,而且我發現的解決方案是立即發送PayPal 200響應。 (這裏是一些討論的問題:https://www.paypal-community.com/t5/About-Settings-Archive/Paypal-repeats-identical-IPN-posts/td-p/465559)。這似乎在我的測試網站上正常工作,但顯然不適合所有用戶。

當我使用PayPal IPN模擬器時,它不會給我任何錯誤消息。

除了立即發送200響應外,我還有什麼可以阻止PayPal重複IPN請求嗎?

這裏是我的代碼:

<?php 

// Create a query var so PayPal has somewhere to go 
// https://willnorris.com/2009/06/wordpress-plugin-pet-peeve-2-direct-calls-to-plugin-files 
function cdashmm_register_query_var($vars) { 
    $vars[] = 'cdash-member-manager'; 
    return $vars; 
} 
add_filter('query_vars', 'cdashmm_register_query_var'); 


// If PayPal has gone to our query var, check that it is correct and process the payment 
function cdashmm_parse_paypal_ipn_request($wp) { 
    // only process requests with "cdash-member-manager=paypal-ipn" 
    if (array_key_exists('cdash-member-manager', $wp->query_vars) && $wp->query_vars['cdash-member-manager'] == 'paypal-ipn') { 

    if(!isset($_POST['txn_id'])) { 
     // send a 200 message to PayPal IPN so it knows this happened 
     header('HTTP/1.1 200 OK'); 
     // POST data isn't there, so we aren't going to do anything else 
    } else { 
     // we have valid POST, so we're going to do stuff with it 
     // send a 200 message to PayPal IPN so it knows this happened 
     header('HTTP/1.1 200 OK'); 

     // process the request. 
     $req = 'cmd=_notify-validate'; 
     foreach($_POST as $key => $value) : 
      $value = urlencode(stripslashes($value)); 
      $req .= "&$key=$value"; 
     endforeach; 

     $header = "POST /cgi-bin/webscr HTTP/1.1\r\n"; 
     $header .= "Content-Length: " . strlen($req) . "\r\n"; 
     $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; 
     $header .= "Host: www.paypal.com\r\n"; 
     $header .= "Connection: close\r\n\r\n"; 
     $fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30); 

     if(!$fp) { 
      // HTTP ERROR 
     } else { 
      fputs ($fp, $header . $req); 
      while(!feof($fp)) { 

       $res = fgets ($fp, 1024); 

       $fh = fopen('result.txt', 'w'); 
        fwrite($fh, $res); 
        fclose($fh); 

       if (strcmp (trim($res), "VERIFIED") == 0) { 

        /* Do a bunch of WordPress stuff - create some posts, send some emails */ 

        } 

       elseif(strcmp (trim($res), "INVALID") == 0) { 
        // probably ought to do something here 

       } 

      } 
     fclose ($fp); 
     } 
    } 
} 
} 
add_action('parse_request', 'cdashmm_parse_paypal_ipn_request'); 

?> 

回答

1

您無法從重複請求停止貝寶。這是IPN系統的一部分,以確保即使網站宕機,交易也能清除。因此,您應該將此交易ID存儲在數據庫中,並檢查以確保您以前沒有遇到過它。如果您以前遇到過,則可以記錄您正在看到重複。否則,處理它。這種利用交易類的

簡單的想法:

foreach ($_POST as $key => $value) { 
    $value = urlencode(stripslashes($value)); 
    $req .= "&$key=$value"; 
    $value = urldecode($value); 
    foreach ($pp_vars as $search) { 
    if ($key == $search) 
     $$key = $value; 
    } 
    if (preg_match("/txn_id/", $key)) { 
     $txn_id = $value; 
    } 
    if (preg_match("/item_number/", $key)) { 
    $item_number = $value; 
    } 
} 

$model = new Transactions(); 
if ($model->exists('txid', $txn_id)) { 
    $res = "REPEAT"; 
} 
$model->action[0] = $res; 
$model->txid[0] = $txn_id; 
$model->description[0] = $req; 
$model->price[0] = $payment_gross; 
$model->reviewed[0] = 0; 
$model->user_id[0] = $user->id; 
$model->created_at[0] = date("Y-m-d H:i:s"); 
$model->updated_at[0] = $model->created_at; 
$model->save();  
+0

謝謝!實際上我已經存儲了交易ID,所以我可以使用一些WordPress查詢來查看它是否已經存在。 – Gwendydd 2015-04-05 22:47:45