siliconpi
siliconpi

Reputation: 8297

Validate that IPN call is from PayPal?

How can I validate that a PayPal IPN POST request to my specified notifyURL is indeed coming from PayPal?

I don't mean comparing the data to what I sent earlier, but how can I verify that the server / IP address this PayPal request is coming from is indeed a valid one?

Upvotes: 8

Views: 12440

Answers (6)

mrded
mrded

Reputation: 5290

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');
}

Upvotes: 3

Lobos
Lobos

Reputation: 559

This is the easiest way I have found to do it, also as per PayPal suggests. I uses http_build_query() to construct the url from the post that was sent to the site from paypal. Paypal docs states that you should send this back for verification and that is what we do with file_get_contents. you will note that I use strstr to check if the word 'VERIFIED' is present and so we continue in the function, if not we return 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;

Upvotes: 12

Sergey Shuchkin
Sergey Shuchkin

Reputation: 2197

HTTP header User-Agent required now!

$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
}

Upvotes: 3

Alix Axel
Alix Axel

Reputation: 154663

This is what I use:

if (preg_match('~^(?:.+[.])?paypal[.]com$~', gethostbyaddr($_SERVER['REMOTE_ADDR'])) > 0)
{
    // came from paypal.com (unless your server got r00ted)
}

Upvotes: -1

Jacco
Jacco

Reputation: 23799

If I remember correctly, the PayPal uses a static IP for it's IPN calls.

So, checking for the correct IP should work.

alternatively, you could make use of gethostbyaddr or gethostbyname.

Upvotes: 1

Amber
Amber

Reputation: 527328

The IPN protocol consists of three steps:

  1. PayPal sends your IPN listener a message that notifies you of the event
  2. Your listener sends the complete unaltered message back to PayPal; the message must contain the same fields in the same order and be encoded in the same way as the original message
  3. PayPal sends a single word back, which is either VERIFIED if the message originated with PayPal or INVALID if there is any discrepancy with what was originally sent

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

Upvotes: 16

Related Questions