2
votes

I have an IPN which is sending the messages correctly to my file, I have confirmed that I am receiving them, first here's my code:

echo "test";
// Response from Paypal

// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
foreach ($_POST as $key => $value) {
    $value = urlencode(stripslashes($value));
    $value = preg_replace('/(.*[^%^0^D])(%0A)(.*)/i','${1}%0D%0A${3}',$value);// IPN fix
    $req .= "&$key=$value";
}

// assign posted variables to local variables
$data['item_name']          = $_POST['item_name'];
$data['item_number']        = $_POST['item_number'];
$data['payment_status']     = $_POST['payment_status'];
$data['payment_amount']     = $_POST['mc_gross'];
$data['payment_currency']   = $_POST['mc_currency'];
$data['txn_id']             = $_POST['txn_id'];
$data['receiver_email']     = $_POST['receiver_email'];
$data['payer_email']        = $_POST['payer_email'];
$data['custom']             = $_POST['custom'];

// post back to PayPal system to validate
$header  = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Host: www.sanbox.paypal.com\r\n";
$header .= "Accept: */*\r\n";
$header .= "Connection: Close\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "\r\n";

$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30); 
if ($fp === FALSE) {
exit("Could not open socket");
}else{
if (!$fp) {
    echo "Error code: 200";
}else{

    fputs ($fp, $header . $req);
$res = stream_get_contents($fp, 2048);
echo "test2";
$res = trim($res);
        if (strcmp($res, "VERIFIED") == 0){
        echo "test3";
            // Used for debugging
            //@mail("[email protected]", "PAYPAL DEBUGGING", "Verified Response<br />data = <pre>".print_r($post, true)."</pre>");

            // Validate payment (Check unique txnid & correct price)
            $valid_txnid = check_txnid($data['txn_id']);
            $valid_price = check_price($data['payment_amount'], $data['item_number']);
            // PAYMENT VALIDATED & VERIFIED!
            if($valid_txnid && $valid_price){
                $orderid = updatePayments($data);       
                if($orderid){       
                   echo "thanks for your payment!";
                   $lel = mysqli_query($con,"UPDATE stats SET stats.bankedgold = 10000 WHERE stats.id = $id4");
                    // Payment has been made & successfully inserted into the Database                              
                }else{                          
                    echo "Error code: 100";
                    // E-mail admin or alert user
                }
            }else{
                echo "Error code: 130";
                // Payment made but data has been changed
                // E-mail admin or alert user
            }                       

        }else if (strcmp ($res, "INVALID") == 0) {
             echo "Error code: 170";
            // PAYMENT INVALID & INVESTIGATE MANUALY! 
            // E-mail admin or alert user

            // Used for debugging
            //@mail("[email protected]", "PAYPAL DEBUGGING", "Invalid     Response<br />data = <pre>".print_r($post, true)."</pre>");
        }       
    echo strcmp($res,"VERIFIED" == 0);      
fclose ($fp);
}   

}
}

Now, a var_dump of $res gives:

HTTP/1.1 200 OK
Date: Mon, 02 Mar 2015 11:24:35 GMT 
Server: Apache X-Frame-  
Options: SAMEORIGIN 
Set-Cookie: <REDACTED_FOR_PRIVACY>
Set-Cookie: navcmd=_notify-validate; domain=.paypal.com; path=/; Secure; HttpOnly 
Set-Cookie: navlns=0.0; expires=Wed, 01-Mar-2017 11:24:35 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: Apache=10.72.108.11.1425295475397401; path=/; expires=Wed, 22-Feb-45 11:24:35 GMT
Vary: Accept-Encoding,User-Agent Connection: close 
Set-Cookie: <REDACTED_FOR_PRIVACY>
Set-Cookie: X-PP-SILOVER=; Expires=Thu, 01 Jan 1970 00:00:01 GMT    
Set-Cookie: Apache=10.72.128.11.1425295475383817; path=/; expires=Wed, 22-Feb-45 11:24:35 GMT
Strict-Transport-Security: max-age=14400 
Transfer-Encoding: chunked 
Content-Type: text/html; charset=UTF-8 8

VERIFIED 0

But I need it to say just VERIFIED or INVALID so I can determine what to do from there.

A simple fix for me would be to add "strpos" and just see if it contains the words but I want to verify with you experts that it would be a good fix?

2

2 Answers

0
votes

PayPal has started using HTTP/1.1 to send its responses. This means, among other things, that you get Transfer-Encoding: chunked in the response.

The chunked encoding requires parsing. Typically it will look like this:

8
VERIFIED

0

Translated, this gives "chunk of length 8 = VERIFIED || chunk of length 0 = end of stream"

If you can't parse this response, you can try to force PayPal to not use chunked encoding by specifying HTTP/1.0 in your validation response. Alternatively, use a better library like cURL to do the parsing for you - PayPal's demo IPN code was written for a very old version of PHP, or at least one with no extensions enabled. It seems like the programmer was ignorant of the http_build_query function to properly encode the $req verification data, which is just sad really. You'd think PayPal could afford competent developers *ahem* but anyway... Personally I "solved" it by just reading the Content-Length header - all the responses that PayPal can send here have different lengths. Sort of cheating, but it worked.

Hope this helps :)

0
votes

Change this line:

$value = urlencode(stripslashes($value));

To this:

$value = urlencode($value);

You only need to use stripslashes there if you're runnning PHP with Magic Quotes on. As of PHP 5.4, that's (thankfully) no longer possible.

Paypal allows user data to contain backslashes (I have seen it in IPN data in the address_street variable). If you strip the backslashes out from IPN data that had them, Paypal will return an INVALID response.