Paypal SandBox IPN всегда возвращает INVALID

Как упоминалось в одном из комментариев в ответе ниже, я пробовал следовать этому руководству . Итак, теперь у меня есть следующее:


Файл ipn.php:

<?php $ipn_post_data = $_POST; $url = 'https://www.sandbox.paypal.com/cgi-bin/webscr'; // Set up request to PayPal $request = curl_init(); curl_setopt_array($request, array ( CURLOPT_URL => $url, CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => http_build_query(array('cmd' => '_notify-validate') + $ipn_post_data), CURLOPT_RETURNTRANSFER => TRUE, CURLOPT_HEADER => FALSE, CURLOPT_SSL_VERIFYPEER => TRUE, CURLOPT_CAINFO => 'cacert.pem', )); // Execute request and get response and status code $response = curl_exec($request); $status = curl_getinfo($request, CURLINFO_HTTP_CODE); // Close connection curl_close($request); if($status == 200 && $response == 'VERIFIED') { $subject = "valid"; $message = "good"; } else { $subject = "invalid"; $message = "bad"; } $to = "oshirowanen@mail.com"; $from = "me@desktop.com"; $header = 'MIME-Version: 1.0' . "\r\n"; $header .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n"; $header .= 'To: Oshirowanen <oshirowanen@mail.com>' . "\r\n"; $header .= 'From: Me <me@desktop.com>' . "\r\n"; mail($to,$subject,$message,$header); ?> 

Полученное письмо:

 Subject "invalid" Message "bad" 

Редактировать:

Теперь, когда я вижу массив, который вы вывели, попробуйте заменить это, чтобы избавиться от ошибки массива PHP:

 foreach ($_POST as $key => $value) { if (!is_array($value)) { $value = urlencode(stripslashes($value)); $req .= "&$key=$value"; } else if (is_array($value)) { $paymentArray = explode(' ', $value[0]); $paymentCurrency = urlencode(stripslashes($paymentArray[0])); $paymentGross = urlencode(stripslashes($paymentArray[1])); $req .= '&mc_currency=' . $paymentCurrency . '&mc_gross=' . $paymentGross; } } 

Вот отредактированный код в полном объеме:

 // read the post from PayPal system and add 'cmd' $req = 'cmd=' . urlencode('_notify-validate'); foreach ($_POST as $key => $value) { if (!is_array($value)) { $value = urlencode(stripslashes($value)); $req .= "&$key=$value"; } else if (is_array($value)) { $paymentArray = explode(' ', $value[0]); $paymentCurrency = urlencode(stripslashes($paymentArray[0]); $paymentGross = urlencode(stripslashes($paymentArray[1]); $req .= '&mc_currency=' . $paymentCurrency . '&mc_gross=' . $paymentGross; } } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://www.paypal.com/cgi-bin/webscr'); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_POSTFIELDS, $req); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Host: www.paypal.com')); $res = curl_exec($ch); curl_close($ch); // assign posted variables to local variables $item_name = $_POST['item_name']; $item_number = $_POST['item_number']; $payment_status = $_POST['payment_status']; $payment_amount = $_POST['mc_gross']; $payment_currency = $_POST['mc_currency']; $txn_id = $_POST['txn_id']; $receiver_email = $_POST['receiver_email']; $payer_email = $_POST['payer_email']; if (strcmp ($res, "VERIFIED") == 0) { // check the payment_status is Completed // check that txn_id has not been previously processed // check that receiver_email is your Primary PayPal email // check that payment_amount/payment_currency are correct // process payment } else if (strcmp ($res, "INVALID") == 0) { // log for manual investigation } 

Проверьте это !

Изменить: ознакомьтесь с советами по устранению неполадок PayPal:

https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_admin_IPNTesting

Проблема в том, что вы не проверяете код ответа HTTP, поэтому вы вводите «Недопустимый заголовок узла» в качестве ответа PayPal, в то время как это ответ веб-сервера (для кода состояния 400).
Если вы посмотрите на документацию PayPal , есть пример PHP, который очень похож на ваш код, поскольку он использует функции «fsockopen», «fputs» и «fgets» для связи с сервером PayPal.
Но если вы внимательно посмотрите на замечание после вызова «fsockopen», вы можете прочитать:

 // Process validation from PayPal // TODO: This sample does not test the HTTP response code. All // HTTP response codes must be handled or you should use an HTTP // library, such as cUrl 

И это точно ваша проблема: вы не проверяете, что код ответа HTTP составляет 200 (OK), прежде чем разбирать тело ответа.
Кроме того, использование функции «strtolower» неверно, поскольку реальный ответ с сервера PayPal всегда занимает верхний регистр, как показано в приведенном выше примере.
Даже если в примере PayPal используется подход «fsockopen», я считаю, что лучше использовать библиотеку PHP cURL для реализации вашего IPN-прослушивателя.
Посмотрите также на следующие ответы:

  • PHP cURL Песочница PayPal
  • cURL или fsockopen для paypal ipn

Однако, если вы действительно хотите использовать функцию fsockopen, вы всегда должны указывать поле заголовка «Host» в запросе POST, как показано в следующем фрагменте кода (взятом из руководства PHP ):

 <?php $fp = fsockopen("www.example.com", 80, $errno, $errstr, 30); if (!$fp) { echo "$errstr ($errno)<br />\n"; } else { $out = "GET / HTTP/1.1\r\n"; $out .= "Host: www.example.com\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); while (!feof($fp)) { echo fgets($fp, 128); } fclose($fp); } ?> 

ОБНОВИТЬ

Вот простая функция для рекурсивных stripslashes / urlencoding:

 <html> <body> <pre> <? $post = Array ( "transaction" => Array("USD 20.00"), "payment_request_date" => "Sun Aug '05 08:49:20 PDT 2012", "return_url" => "http://000.000.000.000/success.php" ); echo "before myUrlencode...\n"; print_r($post); function myUrlencode($post) { foreach ($post as $key => $val) { if (is_array($val)) { $post[$key] = myUrlencode($val); } else { $post[$key] = urlencode(stripslashes($val)); } } return($post); } echo "\nafter myUrlencode...\n"; print_r(myUrlencode($post)); ?> </pre> </body> </html> 
  1. Получил его работу с использованием базового образца кода 4b,

  2. $ipnNotificationUrl = ""; от базового образца кода, поскольку у меня была ценность, которую я добавил,

  3. Создал учетную запись продавца вместо учетной записи business pro в песочнице,

  4. Установите учетную запись продавца, чтобы включить URL-адрес ipn,

  5. Использовал следующий пример кода PHP 5.2 для слушателя ipn

  6. Добавлено 2 строки в слушателя, как описано здесь , 2 строки можно увидеть ниже:

  7. cacert.pem сертификат cacert.pem на мой сервер и поместили его в тот же каталог, что и слушатель ipn:

2 строки, упомянутые в пункте 6:

 CURLOPT_SSL_VERIFYPEER => TRUE, CURLOPT_CAINFO => 'cacert.pem', 

Я понятия не имею, почему учетная запись proxy sandbox не позволяет мне установить URL-адрес ipn, но учетная запись продавца.

Эти ссылки могут решить вашу проблему,

Paypal: неверная проблема с IPN

http://www.webmasterworld.com/ecommerce/4292847.htm

IP-адрес Paypal недействителен INVALID

Я не уверен, что сейчас неправильно с вашим кодом, но я борется с тобой в то же время, и мои исправления заключались в том, чтобы добавить HOST в заголовок, а хозяин должен быть http://www.paypal.com. Я использовал метод fsockopen и теперь отлично работаю.

В Curl у меня была проблема с ssl. И решение было поставить эти строки:

 curl_setopt($curl, CURLOPT_COOKIEJAR, dirname(__FILE__) . "/cookies.txt"); curl_setopt($curl, CURLOPT_COOKIEFILE, dirname(__FILE__) . "/cookies.txt"); 

где, конечно, файл cookie.txt должен существовать. и более того, мне пришлось запустить одно подключение к странице, чтобы получить данные сеанса, а затем отправить данные для отправки.

Ниже приведен заголовок, который отлично работает для меня с помощью метода fsockopen

 $header = "POST /cgi-bin/webscr HTTP/1.0\r\n"; $header .= "Host: www.paypal.com\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; $header .= "Content-Length: " . strlen($req) . "\r\n\r\n"; 

Это проблема с символом +, она часто ошибочно набирается, поэтому я сделал это обходное решение, и это сработало для меня.

payment_data = Сб Июн 04 2016 15:11:16 GMT + 0200 (CEST)

 foreach ($_POST as $key => $value) { if($key !== "payment_date"){ $req .= '&' . $key . '=' . rawurlencode(html_entity_decode($value, ENT_QUOTES, 'UTF-8')); }else{ $req .= '&' . $key . '=' . rawurlencode(str_replace(array('GMT '),array('GMT+'),$value)); }} 

Вот как избежать этих ошибок …

 foreach ($_POST as $key => $value) { if ($key=='transaction') foreach ($value as $key2=>$value2) { $value['transaction'][$key2] = urlencode(stripslashes($value2)); } else { $value = urlencode(stripslashes($value)); } $req .= "&$key=$value"; } 

Время тянет волосы, пока я не увижу ответ Идзудина. Он прав … + дата не переносится. Чтобы проверить, я удалил его из предварительно заполненного поля в симуляторе и наконец получил Verified .

Наконец, я нашел обновленный (5 августа 2016 г.) рабочий ответ на этот запрос. Вы можете использовать этот код в качестве своего последнего IPN для песочницы или Live. Со следующим соображением:

  1. Не забудьте разместить своего слушателя IPN в -> Мои инструменты продажи -> уведомление о моментах оплаты.
  2. Не используйте IPN Simulator в песочнице, он всегда будет возвращать INVALID.
  3. Создайте и используйте настоящую кнопку «Песочница», но НЕ помещайте своего слушателя IPN на страницу RETURN PAGE, в которой говорится: «Возьмите клиентов по этому URL-адресу, когда они завершат проверку».

Вот и все. Я надеюсь, это поможет.

И вот рабочий код:

 <?php $post_data = file_get_contents('php://input'); $post_array = explode('&', $post_data); $dataFromPayPal = array(); foreach ($post_array as $keyval) { $keyval = explode ('=', $keyval); if (count($keyval) == 2) $dataFromPayPal[$keyval[0]] = urldecode($keyval[1]); } $req = 'cmd=_notify-validate'; if(function_exists('get_magic_quotes_gpc')) { $get_magic_quotes_exists = true; } foreach ($dataFromPayPal as $key => $value) { if($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) { $value = urlencode(stripslashes($value)); } else { $value = urlencode($value); } $req .= "&$key=$value"; } $ch = curl_init('https://www.sandbox.paypal.com/cgi-bin/webscr'); //use https://www.sandbox.paypal.com/cgi-bin/webscr in case you are testing this on a PayPal Sanbox environment curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_POSTFIELDS, $req); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_FORBID_REUSE, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close')); if( !($res = curl_exec($ch)) ) { curl_close($ch); exit; } curl_close($ch); if (strcmp ($res, "INVALID") == 0) { echo "INVALID"; } else if (strcmp ($res, "VERIFIED") == 0) { echo "VALID"; } ?>