1
votes

UPDATE #1: I've located the problem, when I use the simulator the $res variable has the string 'VERIFIED' as it should be, since it's being exploded from the headers, however it doesn't seem to be the case when I use the sandbox, the headers stay in that variable. What can I do?

I've used the IPN php code provided by PayPal to make a payment (which depends on the product you choose) in my website. If I use the IPN simulator it works correctly, and posts the log fine, however when using the sandbox accounts (I enabled IPN on my seller account), it doesn't log after the word VERIFIED, see here, the first is the sandbox test, the other is the simulator test

    [2013-11-21 14:52 Europe/Rome] HTTP request of validation request:POST /cgi-bin/webscr HTTP/1.1
    Host: www.sandbox.paypal.com
    Accept: */*
    Connection: Close
    Content-Length: 1057
    Content-Type: application/x-www-form-urlencoded
    Expect: 100-continue

     for IPN payload: cmd=_notify-validate&mc_gross=244.00&protection_eligibility=Eligible&address_status=unconfirmed&payer_id=SJQRWD9JWG3WQ&tax=44.00&address_street=Via+Unit%1A+d%27Italia%2C+5783296&payment_date=05%3A52%3A43+Nov+21%2C+2013+PST&payment_status=Completed&charset=windows-1252&address_zip=80127&first_name=Spazioagenti&mc_fee=8.65&address_country_code=IT&address_name=Spazioagenti+Buyer&notify_version=3.7&custom=3%7C14%7C2%7C10%7C244%7C7&payer_status=verified&business=seller%40spazioagenti.it&address_country=Italy&address_city=Napoli&quantity=10&verify_sign=AYoLATaZgB5cTatNJOgByicud-f2AZq2KG1cXXct8eRGc2LKOUoshqub&payer_email=buyer%40spazioagenti.it&txn_id=2LL473335A169684V&payment_type=instant&last_name=Buyer&address_state=Napoli&receiver_email=seller%40spazioagenti.it&payment_fee=&receiver_id=2N8MTA3G7BX2W&txn_type=web_accept&item_name=Pacchetto+Appuntamenti+per+Sorgenia&mc_currency=EUR&item_number=&residence_country=IT&test_ipn=1&handling_amount=0.00&transaction_subject=3%7C14%7C2%7C10%7C244%7C7&payment_gross=&shipping=0.00&ipn_track_id=d05cb7a39bc8d
    [2013-11-21 14:52 Europe/Rome] HTTP response of validation request: HTTP/1.1 100 Continue

    HTTP/1.1 200 OK
    Date: Thu, 21 Nov 2013 13:52:48 GMT
    Server: Apache
    X-Frame-Options: SAMEORIGIN
    Set-Cookie: c9MWDuvPtT9GIMyPc3jwol1VSlO=Gsyvkagbs7ElOYK0w0MSz-85N_LQTZUfWbDB5VEBBGSXea41hUfW8kgqvr3S64gHZtDYnHKAAnxhtUudwDEoAKfy_qcwPREwYFGlKypB27oMLdN0IX5Z8kuy9guw7vyR2dJVEuDwAtCRyivAANNzi_pB_b6GCdtDpqmefesbBv1XKrJc_HR675wuSqn7ECOeREJBn-P8Q5OrTCSYlsz62eE9oFM0gsVXWRGr3rX1DR_rlk-Z9OmIGRbScwwYPY6qm6oj-3IEtyZBltdvuH3PZdeRA0BCf46x773bJOgg_D50XwRzCSDo8hCVLPZRKDjrgVYjnd69TrELucb97rYChCPHuErWVO-9_RZNJQSvIIZp7cSSeCg9ktVthqYfbrgeBLmefARnHdcR0wqjjPlyp1GWJXL2pgseS87dtyZ2DdVKJfKaa2KRBFvmSoi; domain=.paypal.com; path=/; Secure; HttpOnly
    Set-Cookie: cookie_check=yes; expires=Sun, 19-Nov-2023 13:52:48 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
    Set-Cookie: navcmd=_notify-validate; domain=.paypal.com; path=/; Secure; HttpOnly
    Set-Cookie: navlns=0.0; expires=Sat, 21-Nov-2015 13:52:48 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
    Set-Cookie: Apache=10.72.109.11.1385041968439630; path=/; expires=Sat, 14-Nov-43 13:52:48 GMT
    Connection: close
    Set-Cookie: X-PP-SILOVER=name%3DSANDBOX3.WEB.1%26silo_version%3D880%26app%3Dslingshot%26TIME%3D806391378; domain=.paypal.com; path=/; Secure; HttpOnly
    Set-Cookie: X-PP-SILOVER=; Expires=Thu, 01 Jan 1970 00:00:01 GMT
    Set-Cookie: Apache=10.72.128.11.1385041968427891; path=/; expires=Sat, 14-Nov-43 13:52:48 GMT
    Vary: Accept-Encoding
    Strict-Transport-Security: max-age=14400
    Transfer-Encoding: chunked
    Content-Type: text/html; charset=UTF-8

    VERIFIED


    -----------------------------------------------------------------------------------------------------------------------------


    [2013-11-21 15:03 Europe/Rome] HTTP request of validation request:POST /cgi-bin/webscr HTTP/1.1
Host: www.sandbox.paypal.com
Accept: */*
Connection: Close
Content-Length: 852
Content-Type: application/x-www-form-urlencoded

 for IPN payload: cmd=_notify-validate&residence_country=US&invoice=abc1234&address_city=San+Jose&first_name=John&payer_id=TESTBUYERID01&shipping=3.04&mc_fee=0.44&txn_id=369761703&receiver_email=seller%40paypalsandbox.com&quantity=1&custom=xyz123&payment_date=05%3A53%3A46+21+Nov+2013+PST&address_country_code=US&address_zip=95131&tax=2.02&item_name=something&address_name=John+Smith&last_name=Smith&receiver_id=seller%40paypalsandbox.com&item_number=AK-1234&verify_sign=An5ns1Kso7MWUdW4ErQKJJJ4qi4-AdDhuqhHs5YWS2Bd.yigopmmBy7J&address_country=United+States&payment_status=Completed&address_status=confirmed&business=seller%40paypalsandbox.com&payer_email=buyer%40paypalsandbox.com&notify_version=2.1&txn_type=web_accept&test_ipn=1&payer_status=verified&mc_currency=USD&mc_gross=12.34&address_state=CA&mc_gross1=9.34&payment_type=instant&address_street=123%2C+any+street
[2013-11-21 15:03 Europe/Rome] HTTP response of validation request: HTTP/1.1 200 OK
Date: Thu, 21 Nov 2013 14:03:33 GMT
Server: Apache
X-Frame-Options: SAMEORIGIN
Set-Cookie: c9MWDuvPtT9GIMyPc3jwol1VSlO=KR7iqlBBbqQKnRabL5TJ6Dnbg5xydQBOGeaPIRc-ShkauU79QmQF20HOui5yoQz2r3lXcrzoTn22w10461k6VaYZ1j8cP-Ps-GqlxqppLmaQfclCczIrDOLku7ewLjaSnETDJ4-zd3VLXpTT6Vv_FJeaBpNZkpAFO4yq6gCL48D40CcaOPEkBB7l-ZrW_6vKsByKiV2ocW5EMS-Zl1TqmNBGAFRh5WeWspN772rwHQJdBsUM4CljSWyM2e2H0Jzr3tpNJb9OMaq7BQcefNBc5jSWqLL_-GUpZ6BgtXL2urDFNjB3BuetscxsqwwR8cSX6wuY4gZRJ4-pE0vf-x_o6Ao4Sz-A9FgVM_gl5LO0RrJoYYj4yPzHncig0cwgBRF-_GB3S6sznJVnIkQMifoGuEIOkVisXl1jKMatG7YI3H8t5cqXyyqOYVxLp-y; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: cookie_check=yes; expires=Sun, 19-Nov-2023 14:03:33 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: navcmd=_notify-validate; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: navlns=0.0; expires=Sat, 21-Nov-2015 14:03:33 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: Apache=10.72.109.11.1385042613169322; path=/; expires=Sat, 14-Nov-43 14:03:33 GMT
Connection: close
Set-Cookie: X-PP-SILOVER=name%3DSANDBOX3.WEB.1%26silo_version%3D880%26app%3Dslingshot%26TIME%3D3037892178; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: X-PP-SILOVER=; Expires=Thu, 01 Jan 1970 00:00:01 GMT
Set-Cookie: Apache=10.72.128.11.1385042613160303; path=/; expires=Sat, 14-Nov-43 14:03:33 GMT
Vary: Accept-Encoding
Strict-Transport-Security: max-age=14400
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8

VERIFIED
[2013-11-21 15:03 Europe/Rome] POST DATA: Array
(
    [residence_country] => US
    [invoice] => abc1234
    [address_city] => San Jose
    [first_name] => John
    [payer_id] => TESTBUYERID01
    [shipping] => 3.04
    [mc_fee] => 0.44
    [txn_id] => 369761703
    [receiver_email] => [email protected]
    [quantity] => 1
    [custom] => xyz123
    [payment_date] => 05:53:46 21 Nov 2013 PST
    [address_country_code] => US
    [address_zip] => 95131
    [tax] => 2.02
    [item_name] => something
    [address_name] => John Smith
    [last_name] => Smith
    [receiver_id] => [email protected]
    [item_number] => AK-1234
    [verify_sign] => An5ns1Kso7MWUdW4ErQKJJJ4qi4-AdDhuqhHs5YWS2Bd.yigopmmBy7J
    [address_country] => United States
    [payment_status] => Completed
    [address_status] => confirmed
    [business] => [email protected]
    [payer_email] => [email protected]
    [notify_version] => 2.1
    [txn_type] => web_accept
    [test_ipn] => 1
    [payer_status] => verified
    [mc_currency] => USD
    [mc_gross] => 12.34
    [address_state] => CA
    [mc_gross1] => 9.34
    [payment_type] => instant
    [address_street] => 123, any street
)

[2013-11-21 15:03 Europe/Rome] Verified IPN: cmd=_notify-validate&residence_country=US&invoice=abc1234&address_city=San+Jose&first_name=John&payer_id=TESTBUYERID01&shipping=3.04&mc_fee=0.44&txn_id=369761703&receiver_email=seller%40paypalsandbox.com&quantity=1&custom=xyz123&payment_date=05%3A53%3A46+21+Nov+2013+PST&address_country_code=US&address_zip=95131&tax=2.02&item_name=something&address_name=John+Smith&last_name=Smith&receiver_id=seller%40paypalsandbox.com&item_number=AK-1234&verify_sign=An5ns1Kso7MWUdW4ErQKJJJ4qi4-AdDhuqhHs5YWS2Bd.yigopmmBy7J&address_country=United+States&payment_status=Completed&address_status=confirmed&business=seller%40paypalsandbox.com&payer_email=buyer%40paypalsandbox.com&notify_version=2.1&txn_type=web_accept&test_ipn=1&payer_status=verified&mc_currency=USD&mc_gross=12.34&address_state=CA&mc_gross1=9.34&payment_type=instant&address_street=123%2C+any+street 

The code I'm using for the IPN listener is this:

// CONFIG: Enable debug mode. This means we'll log requests into 'ipn.log' in the same directory.
    // Especially useful if you encounter network errors or other intermittent problems with IPN (validation).
    // Set this to 0 once you go live or don't require logging.
    define("DEBUG", 1);

    // Set to 0 once you're ready to go live
    define("USE_SANDBOX", 1);

    define("LOG_FILE", "./ipn.log");

    // Read POST data
    // reading posted data directly from $_POST causes serialization
    // issues with array data in POST. Reading raw POST data from input stream instead.
    $raw_post_data = file_get_contents('php://input');
    $raw_post_array = explode('&', $raw_post_data);
    $myPost = array();
    foreach ($raw_post_array as $keyval) {
        $keyval = explode ('=', $keyval);
        if (count($keyval) == 2)
            $myPost[$keyval[0]] = urldecode($keyval[1]);
    }
    // read the post from PayPal system and add 'cmd'
    $req = 'cmd=_notify-validate';
    if(function_exists('get_magic_quotes_gpc')) {
        $get_magic_quotes_exists = true;
    }
    foreach ($myPost as $key => $value) {
        if($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) {
            $value = urlencode(stripslashes($value));
        } else {
            $value = urlencode($value);
        }
        $req .= "&$key=$value";
    }

    // Post IPN data back to PayPal to validate the IPN data is genuine
    // Without this step anyone can fake IPN data

    if(USE_SANDBOX == true) {
        $paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr";
    } else {
        $paypal_url = "https://www.paypal.com/cgi-bin/webscr";
    }

    $ch = curl_init($paypal_url);
    if ($ch == FALSE) {
        return FALSE;
    }

    curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);

    if(DEBUG == true) {
        curl_setopt($ch, CURLOPT_HEADER, 1);
        curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
    }

    // CONFIG: Optional proxy configuration
    //curl_setopt($ch, CURLOPT_PROXY, $proxy);
    //curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);

    // Set TCP timeout to 30 seconds
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));

    // CONFIG: Please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set the directory path
    // of the certificate as shown below. Ensure the file is readable by the webserver.
    // This is mandatory for some environments.

    //$cert = __DIR__ . "./cacert.pem";
    //curl_setopt($ch, CURLOPT_CAINFO, $cert);

    $res = curl_exec($ch);
    if (curl_errno($ch) != 0) // cURL error
    {
        if(DEBUG == true) {
            error_log(date('[Y-m-d H:i e] '). "Can't connect to PayPal to validate IPN message: " . curl_error($ch) . PHP_EOL, 3, LOG_FILE);
        }
        curl_close($ch);
        exit;

    } else {
        // Log the entire HTTP response if debug is switched on.
        if(DEBUG == true) {
            error_log(date('[Y-m-d H:i e] '). "HTTP request of validation request:". curl_getinfo($ch, CURLINFO_HEADER_OUT) ." for IPN payload: $req" . PHP_EOL, 3, LOG_FILE);
            error_log(date('[Y-m-d H:i e] '). "HTTP response of validation request: $res" . PHP_EOL, 3, LOG_FILE);

            // Split response headers and payload
            list($headers, $res) = explode("\r\n\r\n", $res, 2);
        }
        curl_close($ch);
    }

    // Inspect IPN validation result and act accordingly

    if (strcmp ($res, "VERIFIED") == 0) {
        error_log(date('[Y-m-d H:i e] '). "POST DATA: ". print_r($_POST, true) . PHP_EOL, 3, LOG_FILE);
        // check whether the payment_status is Completed
        // check that txn_id has not been previously processed
        // check that receiver_email is your PayPal email
        // check that payment_amount/payment_currency are correct
        // process payment and mark item as paid.

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

        if(DEBUG == true) {
            mail('[email protected]', 'Verified IPN', 'verified');
            error_log(date('[Y-m-d H:i e] '). "Verified IPN: $req ". PHP_EOL, 3, LOG_FILE);
        }
    } else if (strcmp ($res, "INVALID") == 0) {
        // log for manual investigation
        // Add business logic here which deals with invalid IPN messages
        if(DEBUG == true) {
            mail('[email protected]', 'Invalid IPN', 'not verified');
            error_log(date('[Y-m-d H:i e] '). "Invalid IPN: $req" . PHP_EOL, 3, LOG_FILE);
        }
    }

I'm assuming there's something wrong with my form? I added everything as suggested by PayPal Javascript buttons

Here's my buy no button form HTML code:

<form method="post" action="https://www.sandbox.paypal.com/cgi-bin/webscr" class="paypal-button" target="_top">
                <input type="hidden" name="button" value="buynow">
                <input type="hidden" name="item_name" value="Pacchetto Appuntamenti per Sorgenia">
                <input type="hidden" name="amount" value="20">
                <input type="hidden" name="currency_code" value="EUR">
                <input type="hidden" name="quantity" value="10">
                <input type="hidden" name="tax_rate" value="22">
                <input type="hidden" name="lc" value="IT">
                <input type="hidden" name="env" value="www.sandbox">
                <input type="hidden" name="return" value="http://test.xxxxx.it/utente/storicoordini">
                <input type="hidden" name="notify_url" value="http://test.xxxxx.it/utente/ipn">
                <input type="hidden" name="custom" value="3|14|2|10|244|7">
                <input type="hidden" name="rm" value="2"><input type="hidden" name="cmd" value="_xclick">
                <input type="hidden" name="business" value="2N8MTA3G7BX2W">
                <input type="hidden" name="bn" value="JavaScriptButton_buynow">
                <button type="submit" class="paypal-button large">Buy Now</button>
            </form>
1

1 Answers

4
votes

You're only splitting out the headers IF debug is on. Perhaps that's the problem. I'm not sure why you bother to pull out the headers as the response is going to be exactly the same plus VERIFIED (or not). I just match against the entire response.

if (preg_match("!(VERIFIED)\s*\Z!",$res))
{  /*payment verified, handle */  }
else
{  /* boo fake payment OR paypal is having problems */  }