I am testing integrating a website to Paypal, using Web Payments standard and HTML Variables.
I have written a simple PHP script to handle the IPN notifications.
According to the Paypal documentation, the Paypal server responds with a simple 'VERIFIED' or 'INVALID' response, once you ping the received data back to Paypal.
In my handler, I am doing a case sensitive string comparison for those two keywords, if either one of these known keywords is not found, then it is treated as an error.
<?php
$fp = fsockopen ($socket_url, 80, $errno, $errstr, 10);
if (!$fp){
// SOCKET ERROR
return false;
}
else {
fputs ($fp, $header . $req);
$is_ok = false;
while (!feof($fp)) {
$res = fgets ($fp, 1024);
if (strcmp("VERIFIED",$this->ipn_response)==0) {
//do something ...
}
// if the IPN POST was 'INVALID'
else if (strcmp ($res, "INVALID") == 0) {
fclose ($fp);
return false;
}
else {
echo "Unknown response from Paypal: $res";
fclose ($fp);
return false;
}
}
fclose ($fp);
return true;
}
?>
My error message shows that I am receiving an 'HTTP/1.1 200 OK' response from Paypal.
Unknown response from Paypal:
'HTTP/1.1 200 OK'
Has the PayPal API changed, or am I doing something wrong?
PayPal's response is in the body of the HTTP response. You need to process the HTTP headers before you can get at the body. Or, alternately, just keep reading lines until you find a blank line, and the next line will be the body.
Sorry, my original response was really badly worded :)
fgets is only reading line by line, the first line being the HTTP response. Your code never gives the opportunity to continue reading, though, as you 'error out' after the first line is processed.
I'd be inclined to replace your while loop with something like:
while (!feof($fp)) {
$res = trim(fgets($fp, 1024));
if (strcmp($res, "VERIFIED")==0) {
//do something ...
}
else if (strcmp($res, "INVALID") == 0) {
fclose ($fp);
return false;
}
}
As @Mike said, you've to read the whole body - in your case you're just testing if VERIFIED
or INVALID
appears in the first 1024 bytes of the reply, which is probably the header.
By the way, you don't need to use fsockopen()
, most people do because PayPal provides an example using it so that it works in old box setups. CURL or file_get_contents
with an HTTP POST context will do the job just fine, here is an example I coded for the phunction PHP framework:
public static function PayPal($email, $status = 'Completed', $sandbox = false)
{
if (preg_match('~^(?:.+[.])?paypal[.]com$~', gethostbyaddr($_SERVER['REMOTE_ADDR'])) > 0)
{
$url = ($sandbox !== true) ? '' : '.sandbox';
$result = self::CURL('https://www' . $url . '.paypal.com/cgi-bin/webscr/', array_merge(array('cmd' => '_notify-validate'), $_POST), 'POST');
if ($result == 'VERIFIED')
{
$email = strlen($email) * strcasecmp($email, $_POST['receiver_email']);
$status = strlen($status) * strcasecmp($status, $_POST['payment_status']);
if (($email == 0) && ($status == 0))
{
return true;
}
}
}
return false;
}