Подтвердить, что вызов IPN поступил от PayPal?
Как я могу подтвердить, что запрос PayPal IPN POST на мой указанный notifyURL действительно исходит от PayPal?
Я не имею в виду сравнение данных с тем, что я отправил ранее, но как я могу убедиться, что сервер / IP-адрес, с которого поступил этот запрос PayPal, действительно действителен?
6 ответов
Протокол IPN состоит из трех этапов:
- PayPal отправляет вашему слушателю IPN сообщение, уведомляющее вас о событии
- Ваш слушатель отправляет полное неизмененное сообщение обратно в PayPal; сообщение должно содержать те же поля в том же порядке и быть закодировано так же, как и исходное сообщение
- PayPal отправляет обратно одно слово, которое либо ПРОВЕРЯЕТСЯ, если сообщение отправлено с помощью PayPal, либо НЕДОПУСТИМО, если есть расхождение с тем, что было отправлено изначально.
https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_admin_IPNIntro
Это самый простой способ, который я нашел для этого, также в соответствии с рекомендациями PayPal. Я использую http_build_query() для создания URL-адреса из сообщения, отправленного на сайт из PayPal. Paypal docs заявляет, что вы должны отправить это обратно для проверки, и это то, что мы делаем с file_get_contents. Вы заметите, что я использую strstr, чтобы проверить, присутствует ли слово "VERIFIED", и поэтому мы продолжим работу, если нет, мы вернем false...
$verify_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_notify-validate&' . http_build_query( $_POST );
if( !strstr( file_get_contents( $verify_url ), 'VERIFIED' ) ) return false;
HTTP-заголовок User-Agent требуется сейчас!
$vrf = file_get_contents('https://www.paypal.com/cgi-bin/webscr?cmd=_notify-validate', false, stream_context_create(array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\nUser-Agent: MyAPP 1.0\r\n",
'method' => 'POST',
'content' => http_build_query($_POST)
)
)));
if ( $vrf == 'VERIFIED' ) {
// Check that 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
}
https://gist.github.com/mrded/a596b0d005e84bc27bad
function paypal_is_transaction_valid($data) {
$context = stream_context_create(array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data),
),
));
$content = file_get_contents('https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_notify-validate', false, $context);
return (bool) strstr($content, 'VERIFIED');
}
Если я правильно помню, PayPal использует статический IP для своих вызовов IPN.
Таким образом, проверка правильности IP должна работать.
в качестве альтернативы, вы можете использовать gethostbyaddr
или же gethostbyname
,
Это то, что я использую:
if (preg_match('~^(?:.+[.])?paypal[.]com$~', gethostbyaddr($_SERVER['REMOTE_ADDR'])) > 0)
{
// came from paypal.com (unless your server got r00ted)
}