Forum Moderators: buckworks

Message Too Old, No Replies

Very Frustrating PayPal IPN Problem - Constantly Returning Invalid

PayPal IPN Listener is returning Invalid from PayPal Sandbox

         

php_dave

4:09 am on Apr 6, 2011 (gmt 0)

10+ Year Member



Hello, fellow web developers. This is my first post. I have joined this forum after trawling the web for answers to my very frustrating problem.

Basically I am looking to set up subscriptions on a couple of my websites. After researching the options the simplest way to do this seemed to be PayPal's subscription service.

Of course, only members who are subscribed will have access to certain parts of the site so naturally I wanted something that automates payment and talks to my database to set permission levels based on succesful payments. PayPal's IPN (Instant Payment Notification) seems to be just the thing I need.

However, I'm having trouble getting it to work for me. I've set up my IPN Listener and have tested it in the PayPal Sandbox. It succesfully sends each time. But what it does NOT do is return VERIFIED. It keeps on returning INVALID or nothing at all! I can't work out why this is as I have followed all the instructions to a tee.

Here is my code:



// ***************** IPN LISTENER *********************
// PHP 4.1

// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';

foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
}

// post back to PayPal system to validate
$header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";

// In a live application send it back to www.paypal.com
// but during development you will want to use the paypal sandbox
// So comment out one of the following lines

// $fp = fsockopen ('www.sandbox.paypal.com', 80, $errno, $errstr, 30);
$fp = fsockopen ('www.paypal.com', 80, $errno, $errstr, 30);

// or use port 443 for an SSL connection
//$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);

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

// CODE TO UPDATE THE DATABASE TO SAY THAT
// IT HAS RETURNED VERIFIED

} else if (strcmp ($res, "INVALID") == 0) {

// CODE TO UPDATE THE DATABASE TO SAY THAT
// IT HAS RETURNED INVALID

} else {

// CODE TO UPDATE THE DATABASE TO SAY THAT
// IT HAS RETURNED NEITHER

}

}
fclose ($fp);
}

// ***************** END IPN LISTENER *********************



The only variety of code that I can find is the URL to send the Listener's reply to.

As you can see above, I have found:
1) $fp = fsockopen ('www.sandbox.paypal.com', 80, $errno, $errstr, 30);
2) $fp = fsockopen ('www.paypal.com', 80, $errno, $errstr, 30);
3) $fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);

Therefore I have tested the Listener from the PayPal Sandbox with each of these lines of code. The IPN is sent succesfully with each of them but none of them return VERIFIED. And for some reason if I use the sandbox.paypal line of code (number 1) it doesn't return anything ($res is blank). Even though I'm sending it from Sandbox and PayPal tells you to use the sandbox URL if this is so!

The only real advice I have found for fixing INVALID returns is from [x.com...]


REASONS FOR INVALID

- Make sure you are posting back ALL variables/values.

For PayPal to return VERIFIED, your IPN script needs to post back ALL the variables that were posted to it in the first place. In other words, if your script only needs to manipulate 1 or 2 variables, it is not enough to post back to PayPal only the variables/values your script is concerned with. Your script should post back EVERYTHING that was initially posted to it from PayPal. This is the only way PayPal will return VERIFIED

- Make sure you are not posting back to the wrong URL.

If you are testing in the Sandbox, you need to ensure your script posts back to www.sandbox.paypal.com. If you are on the live site, the script should post back to www.paypal.com. You will receive INVALID if you are testing in the Sandbox and your script posts back to the live site (or vice versa)

- Encoding

PayPal's IPN server expects that your script will POST back all variables that were posted to it and more importantly, that they are encoded the same way as they were sent to your script. If your script inadvertently changed the encoding of a character or interprets an encoded character as another character and POSTs back, you will likely see INVALID. This can happen sporadically and tends to occur, for example, when a payment is received and the buyer may have an accented character in their name or the order is for some item with a non-standard character in the item name. These instances are tricky to troubleshoot but it is listed here as it can cause INVALID when you would expect VERIFIED. Look for this issue when you are seeing that certain IPNs are INVALID and all the rest are VERIFIED.


As I said before, as far as I can see, I'm not doing anything wrong as suggested by the troubleshooting advice!

I'm really hoping that there is someone on here who is familiar with PayPal IPNs, who can take one look at my code and spot a really dumb schoolboy error somewhere and correct me on it. In the meantime though I am getting more and more frustrated at this apparently illogical error. ARRRGH!

Thank you very, very much in advance, anyone who sovles this issue for me!

PS: This is a graphic to explain pretty much everything I just typed but to also show you my exact code.

[i.imgur.com...]

Daldain

6:01 am on Apr 6, 2011 (gmt 0)

10+ Year Member




foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
}


Try replacing the above with (requires PHP 5+):


$req .= '&'.http_build_query($_POST);


Let us know how you go. I can't remember if IPN validation is possible in the sandbox area of PayPal.

If you are auto generating the IPN with the sandbox IPN generator, it definitely won't validate on the live PayPal URL's.

php_dave

6:59 am on Apr 6, 2011 (gmt 0)

10+ Year Member



Thanks for your reply, Daldain!

I replaced the code you suggested to replace with the $req line of code you quoted. However, my hosts are running PHP 4.4.9 and it caused nothing to happen at all.

And yes, I would have presumed that as I am running test IPNs from the Sandbox I would only use the sandbox.paypal URL but because nothing seemed to be working I tried and tested the other 2 URLs as well. Oddly enough it's the sandbox URL which causes there to be NO output at all whereas the other two at least send back an INVALID.

It's hurting my brain :(

Any other suggestions?

ectect

7:14 am on Apr 6, 2011 (gmt 0)

10+ Year Member



I saw a similar issue yesterday with IPN problems and upgrading to PHP5 sorted it out immediately - I'd get on to your host.

php_dave

7:30 am on Apr 6, 2011 (gmt 0)

10+ Year Member



Really? Ah damn, my hosts are a massive American company with millions of websites and a wall of call centers between me and the people who push the buttons. I can't see them acting too fast when I message them to upgrade their PHP :-(

On PayPal's page of example codes they have it listed as PHP 4.1

[paypal.com...]

Surely the IPN should work with that and anything above?

Daldain

8:44 am on Apr 6, 2011 (gmt 0)

10+ Year Member



Actually I think I see the problem. According to my development environment I connect to "https://www.sandbox.paypal.com/" which means you should be using port 443 rather than 80 when testing in the sandbox.


$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);


Let us know.

php_dave

6:09 pm on Apr 6, 2011 (gmt 0)

10+ Year Member



Hi Daldain.

I had in fact already tried that but forgot to mention it in my first post.

$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30); results in nothing! Neither Verified nor Invalid :(

And just to reitterate my earlier post:
$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30); results in "INVALID"

Man, this is annoying!

php_dave

11:17 pm on Apr 19, 2011 (gmt 0)

10+ Year Member



Hello everyone.

I have figured out the problem and felt I should share the answers on here so that maybe, just maybe, another lost soul will be searching the Interwebs with the exact same problem and will stumble across this thread and all will be redeemed!

In a nutshell, as is the case with most coding problems that don't seem logical, it came down to good old fashioned school boy error.

So... if you're setting up a PayPal IPN Listener and when you test it, it's always returning INVALID then make sure you check that the tables you use in your MySQL to tell your database what to update ACTUALLY EXIST!

It really was that dumb.

In my update query I had entered one of the table names incorrectly. On a normal PHP page it would tell you this error and you'd be able to fix it immediately but because an IPN Listener page is only used by the PayPal bot there is no error to be seen for the coder.

PROBLEM SOLVED!

Great to see my stupid mistake only delayed my plans by 2 weeks >:-/

Good day to you all.