2015-04-04 2 views
1

Я пишу плагин WordPress, который обрабатывает платежи через PayPal. У меня есть сценарий IPN PayPal, который отправляет уведомление по электронной почте (в дополнение к уведомлению по электронной почте PayPal), когда платеж будет успешным. Некоторые пользователи моего плагина сообщают, что они получают несколько копий этого уведомления по электронной почте в течение нескольких дней.PayPal IPN работает повторно

Я обнаружил эту проблему на ранней стадии, когда я разрабатывал плагин, и решение, которое я нашел, это немедленно отправить PayPal на 200 ответов. (Ниже приведено обсуждение проблемы: https://www.paypal-community.com/t5/About-Settings-Archive/Paypal-repeats-identical-IPN-posts/td-p/465559). Кажется, что это работает на моем тестовом сайте, но, очевидно, не работает для всех моих пользователей.

Когда я использую симулятор IPN PayPal, он не дает мне никаких сообщений об ошибках.

Помимо отправки ответа от 200 сразу, есть ли что-нибудь, что я могу сделать, чтобы остановить повторение запроса IPN от PayPal?

Вот мой код:

<?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

Вы не можете остановить Paypal от повторения запроса. Это часть системы IPN, чтобы убедиться, что транзакции очищены, даже если сайт не работает. Следовательно, вы должны сохранить этот идентификатор транзакции в базе данных и убедиться, что в прошлом он не встречался. Если вы столкнулись с этим ранее, вы можете записать, что вы видите повторение. В противном случае обработайте его.

Простая идея этого с помощью класса Transactions:

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

Спасибо! Я на самом деле уже храню идентификатор транзакции, поэтому я могу использовать некоторые запросы WordPress, чтобы убедиться, что он уже существует. – Gwendydd