paypal IPN and PDT

paypal IPN and PDT 相關文檔說明:

https://developer.paypal.com/docs/classic/ipn/gs_IPN/

https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNTesting/

https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNPDTAnAlternativetoIPN/

https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNandPDTVariables/

中文介紹:

http://ppdev.ebay.cn/files/developer/PayPal_PDT_Token_CHN.pdf

http://wenku.baidu.com/link?url=Fgv-l09iCnGQGDuMgdTT94c8YiwuqLEB5qT8tfzBseRdlGICHXsD00N_Zx9q5vbFdydQPXlQFRssgI65ac_4g0RzBHygsWU8V7f5cKjo8AW


PDT:Auto Return for Website Payments brings your buyers back to your website immediately after payment completion. Auto Return applies to PayPal Website Payments, including Buy Now, Subscriptions, and Shopping Cart. Learn More。

如果是網站按鈕方式付款,PDT通知的url也可以用表單的return值設置,會被按鈕設置中第三部設置的成功返回的url覆蓋。


IPN:Instant Payment Notification (IPN)

You have turned on the IPN feature. You can view your IPNs on the IPN History page. If necessary, you can resend IPN messages from that page. For more information on using and troubleshooting this feature, read more about Instant Payment Notification (IPN).

Your listener must respond to every IPN message it gets, whether you take action on it or not. If you do not respond, PayPal assumes the IPN was not received and re-sends it. Further, PayPal continues to re-send the message periodically until your listener responds, although the interval between retries increases with each attempt. An IPN will be resent for up to four days, with a maximum of 15 retries.

IPN可以通過模擬器觸發,針對網站按鈕方式付款,可以被表單的notify_url覆蓋。



處理PDT關鍵是獲取 PayPal 交易流水號 tx , 另外需要token。如果是IPN 和 PDT 是互補的關係,IPN優點:可以獲取各種通知,會重發,The maximum number of retries is 15。缺點:異步,延遲。PDT實時,但是隻能獲取付款完成的通知。


測試方法:

用php程序測試,使用paypal的sanbox環境測試。

安裝php


安裝curl

wget http://curl.haxx.se/download/curl-7.39.0.zip
unzip curl-7.39.0.zip
cd curl-7.39.0
configure
make
make install


安裝curl擴展

../../../php/bin/phpize

./configure  --with-php-config=../../../php/bin/php-config
make
make install

生成 /home/pig/php/lib/php/extensions/no-debug-non-zts-20131226/curl.so

複製,修改php.ini

cp /home/pig/php-5.6.3/php.ini-development /home/pig/php/lib/php.ini

extension=curl.so


測試curl擴展安裝是否成功
/home/pig/php/bin/php -r "var_dump(curl_init());"
resource(4) of type (curl)


安裝openssl擴展,否則fopensocket不支持ssl

cd php-5.6.3/ext/openssl/
mv config0.m4 config.m4
/home/pig/php/bin/phpize
./configure --with-php-config=/home/pig/php/bin/php-config
make
make install

修改php.ini, 加上extension=openssl.so


檢查openssl擴展是否裝好:

/home/dog/php/bin/php -r 'var_dump(fsockopen("tls://www.sandbox.paypal.com", 443, $errno, $errstr, 30));'
resource(4) of type (stream)


啓動server:

/home/pig/php/bin/php -S 0.0.0.0:5000 -t ./


配置nginx:

         location ^~ /paytest/ {
             proxy_pass_header Server;
             proxy_set_header Host $http_host;
             proxy_redirect off;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_set_header X-Scheme $scheme;
             proxy_pass http://localhost:5000;
         }

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


運用paypal的sandbox環境測試paypent,測試IPN和PDT,思路是寫一個程序部署到外網環境,把請求的參數全部記錄到日誌裏面,然後過程一目瞭然。


<?php
error_reporting(7);
ini_set("display_errors", 1);
date_default_timezone_set('PRC');

define("DEBUG", 1);
define("USE_SANDBOX", 1);
define("LOG_FILE", "./ipn.log");

$act= $_REQUEST['act'];

if($act== 'ok'){
    p('ok');
    if(isset($_GET['tx'])){
      $tx = $_GET['tx'];
      $data= get_payment_data($tx);
       p('pdt', $data);
    }
}

elseif($act== 'err'){
    p('err');
}

elseif($act== 'ipn'){
    p('ipn');
    header('HTTP/1.1 200 OK'); 
    // 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);
            }
            curl_close($ch);
    }

    // Inspect IPN validation result and act accordingly

    // Split response headers and payload, a better way for strcmp
    $tokens = explode("\r\n\r\n", trim($res));
    $res = trim(end($tokens));

    if (strcmp ($res, "VERIFIED") == 0) {
        // 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) {
            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) {
            error_log(date('[Y-m-d H:i e] '). "Invalid IPN: $req" . PHP_EOL, 3, LOG_FILE);
        }
    }
}

elseif($act== 'return'){
    p('return');
}

else{

print <<<EOT
<form action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="PVL538Z86ED9N">
<input type="hidden" name="uid" value="678">
<input type="image" src="https://www.sandbox.paypal.com/en_US/C2/i/btn/btn_buynowCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
<img alt="" border="0" src="https://www.sandbox.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1">
</form>


EOT;
}


function p($name, $var= null){
    $t= date('Y-m-d H:i:s');
    $name= $name.".txt";
    if($var== null){
        file_put_contents($name, var_export($_REQUEST, true)."\n".$t."\n\n\n", FILE_APPEND);
    }else{
        file_put_contents($name, var_export($var, true)."\n".$t."\n\n\n", FILE_APPEND);
    }
}

/**
 * Get PayPal Payment Data
 * Read more at http://ethanblog.com/tech/webdev/php-for-paypal-payment-data-transfer.html
 * @param   $tx Transaction ID
 * @return      PayPal Payment Data or FALSE
 */
function get_payment_data($tx)
{
    // PDT Identity Token
    $at_token = 'cwO4mbBZybR0-fbijkszjeoeTxe9XB16HjuvvdbmDIBOTTxuNxDBzKwBpp8';

    // Init cURL
    $request = curl_init();

    // Set request options
    curl_setopt_array($request, array
        (
            CURLOPT_URL => 'https://www.sandbox.paypal.com/cgi-bin/webscr',
            CURLOPT_POST => TRUE,
            CURLOPT_POSTFIELDS => http_build_query(array
                (
                    'cmd' => '_notify-synch',
                    'tx' => $tx,
                    'at' => $at_token,
                    )),
            CURLOPT_RETURNTRANSFER => TRUE,
            CURLOPT_HEADER => FALSE//,
            // CURLOPT_SSL_VERIFYPEER => TRUE,
            // CURLOPT_CAINFO => 'cacert.pem',
            ));

    // Execute request and get response and status code
    $response = curl_exec($request);
    $status   = curl_getinfo($request, CURLINFO_HTTP_CODE);

    // Close connection
    curl_close($request);

    // Validate response
    if($status == 200 AND strpos($response, 'SUCCESS') === 0)
    {
        // Remove SUCCESS part (7 characters long)
        $response = substr($response, 7);

        // Urldecode it
        $response = urldecode($response);

        // Turn it into associative array
        preg_match_all('/^([^=\r\n]++)=(.*+)/m', $response, $m, PREG_PATTERN_ORDER);
        $response = array_combine($m[1], $m[2]);

        // Fix character encoding if needed
        if(isset($response['charset']) AND strtoupper($response['charset']) !== 'UTF-8')
        {
            foreach($response as $key => &$value)
            {
                $value = iconv($response['charset'], 'UTF-8', $value);
            }

            $response['charset_original'] = $response['charset'];
            $response['charset'] = 'UTF-8';
        }

        // Sort on keys
        ksort($response);

        // Done!
        return $response;
    }

    return FALSE;
}


輸出如下:

[pig@ip-10-236-139-149 paytest]$ cat ok.txt
array (
  'act' => 'ok',
  'tx' => '8NG39315CL727724E',
  'st' => 'Completed',
  'amt' => '55.90',
  'cc' => 'USD',
  'cm' => '',
  'item_number' => '',
)
2014-12-06 20:41:43


[pig@ip-10-236-139-149 paytest]$ cat pdt.txt
array (
  'address_city' => 'Shanghai',
  'address_country' => 'China',
  'address_country_code' => 'CN',
  'address_name' => 'Buyer Test',
  'address_state' => 'Shanghai',
  'address_status' => 'unconfirmed',
  'address_street' => 'NO 1 Nan Jin Road',
  'address_zip' => '200000',
  'btn_id' => '3042078',
  'business' => '[email protected]',
  'charset' => 'UTF-8',
  'charset_original' => 'gb2312',
  'custom' => '',
  'discount' => '0.00',
  'first_name' => 'Test',
  'handling_amount' => '0.00',
  'insurance_amount' => '0.00',
  'item_name' => 'sandbox_item111',
  'item_number' => '',
  'last_name' => 'Buyer',
  'mc_currency' => 'USD',
  'mc_fee' => '2.20',
  'mc_gross' => '55.90',
  'payer_email' => '[email protected]',
  'payer_id' => 'JARYJK2TES6C6',
  'payer_status' => 'unverified',
  'payment_date' => '04:26:00 Dec 06, 2014 PST',
  'payment_fee' => '2.20',
  'payment_gross' => '55.90',
  'payment_status' => 'Completed',
  'payment_type' => 'instant',
  'protection_eligibility' => 'Eligible',
  'quantity' => '1',
  'receiver_email' => '[email protected]',
  'receiver_id' => '2XP27KEMUVN8A',
  'residence_country' => 'CN',
  'shipping' => '10.00',
  'shipping_discount' => '0.00',
  'shipping_method' => 'Default',
  'tax' => '0.90',
  'transaction_subject' => '',
  'txn_id' => '8NG39315CL727724E',
  'txn_type' => 'web_accept',
)
2014-12-06 20:41:44



[pig@ip-10-236-139-149 paytest]$ cat ipn.txt
array (
  'act' => 'ipn',
  'mc_gross' => '55.90',
  'protection_eligibility' => 'Eligible',
  'address_status' => 'unconfirmed',
  'payer_id' => 'JARYJK2TES6C6',
  'tax' => '0.90',
  'address_street' => 'NO 1 Nan Jin Road',
  'payment_date' => '04:49:05 Dec 06, 2014 PST',
  'payment_status' => 'Completed',
  'charset' => 'gb2312',
  'address_zip' => '200000',
  'first_name' => 'Test',
  'mc_fee' => '2.20',
  'address_country_code' => 'CN',
  'address_name' => 'Buyer Test',
  'notify_version' => '3.8',
  'custom' => '',
  'payer_status' => 'unverified',
  'business' => '[email protected]',
  'address_country' => 'China',
  'address_city' => 'Shanghai',
  'quantity' => '1',
  'verify_sign' => 'A7SNeSYl88fJlq0RDkCQ4EljfLsAAMJ6OYFDH1nYVB0-NYyynmZyPh.1',
  'payer_email' => '[email protected]',
  'txn_id' => '61P15910PR196164M',
  'payment_type' => 'instant',
  'btn_id' => '3042078',
  'last_name' => 'Buyer',
  'address_state' => 'Shanghai',
  'receiver_email' => '[email protected]',
  'payment_fee' => '2.20',
  'shipping_discount' => '0.00',
  'insurance_amount' => '0.00',
  'receiver_id' => '2XP27KEMUVN8A',
  'txn_type' => 'web_accept',
  'item_name' => 'sandbox_item111',
  'discount' => '0.00',
  'mc_currency' => 'USD',
  'item_number' => '',
  'residence_country' => 'CN',
  'test_ipn' => '1',
  'shipping_method' => 'Default',
  'handling_amount' => '0.00',
  'transaction_subject' => '',
  'payment_gross' => '55.90',
  'shipping' => '10.00',
  'ipn_track_id' => '755ef8ff304e1',
)
2014-12-06 20:49:16


[pig@ip-10-236-139-149 paytest]$ cat ipn.log
[2014-12-06 22:21 PRC] HTTP request of validation request:POST /cgi-bin/webscr HTTP/1.1
Host: www.sandbox.paypal.com
Accept: */*
Connection: Close
Content-Length: 1089
Content-Type: application/x-www-form-urlencoded
Expect: 100-continue

 for IPN payload: cmd=_notify-validate&mc_gross=55.90&protection_eligibility=Eligible&address_status=unconfirmed&payer_id=JARYJK2TES6C6&tax=0.90&address_street=NO+1+Nan+Jin+Road&payment_date=06%3A21%3A54+Dec+06%2C+2014+PST&payment_status=Completed&charset=gb2312&address_zip=200000&first_name=Test&mc_fee=2.20&address_country_code=CN&address_name=Buyer+Test&notify_version=3.8&custom=&payer_status=unverified&business=yxw.2013.03-facilitator%40gmail.com&address_country=China&address_city=Shanghai&quantity=1&verify_sign=AUaxvSojqajxsiGA9qXfGuCulUctAIsI7u6BJGTRbntLsB6UI3lGIXb0&payer_email=yxw.2013.03-buyer%40gmail.com&txn_id=1TM13495A76848512&payment_type=instant&btn_id=3042078&last_name=Buyer&address_state=Shanghai&receiver_email=yxw.2013.03-facilitator%40gmail.com&payment_fee=2.20&shipping_discount=0.00&insurance_amount=0.00&receiver_id=2XP27KEMUVN8A&txn_type=web_accept&item_name=sandbox_item111&discount=0.00&mc_currency=USD&item_number=&residence_country=CN&test_ipn=1&shipping_method=Default&handling_amount=0.00&transaction_subject=&payment_gross=55.90&shipping=10.00&ipn_track_id=a6f9e0f859c1c
[2014-12-06 22:21 PRC] HTTP response of validation request: HTTP/1.1 100 Continue

HTTP/1.1 200 OK
Date: Sat, 06 Dec 2014 14:22:01 GMT
Server: Apache
X-Frame-Options: SAMEORIGIN
Set-Cookie: c9MWDuvPtT9GIMyPc3jwol1VSlO=cHblkEi54DzGTLa5JlkZ5k5rwA9ZRS9I13Waw_UNEnN3n4qBax3-drCD_5VrYo1lvRJWmHQOPn7bYide5LEYmFvSQ-CEsd2RJH6JycTVU3-AiEY9dBVxSVYXMxP6eEtKoknENSGh-ppAYRKLbw40OnC7_FO57RDSBMB3ttpAXqan8xSmdvjcfpezvl3810OK51XEyiIkyXHYQiLTIVqDBJhpgPSAz5jcqGZSF-ZvJIXohmvOJekwuyAgf_R7-QmdEiZgjrG5-msjx2kn6ATUC4Cm-NFOsQgmKa0ecWhOgFEqzjgS8juVMHizUC786G3D0krGR0e5SLzNS9GwwzXk-fIkEzEO75dEoEre9VFK4TfMnygkrdtJV637BSwzqNYyULaF6dHFCTxeEeJ1Xrq9TI5sRssDxQdzcmfE8sCwKZ1L4bgH71CjkI0SU1i; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: cookie_check=yes; expires=Tue, 03-Dec-2024 14:22:02 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: navcmd=_notify-validate; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: navlns=0.0; expires=Mon, 05-Dec-2016 14:22:02 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: Apache=10.72.108.11.1417875722013081; path=/; expires=Mon, 28-Nov-44 14:22:02 GMT
Vary: Accept-Encoding,User-Agent
Connection: close
Set-Cookie: X-PP-SILOVER=name%3DSANDBOX3.WEB.1%26silo_version%3D880%26app%3Dslingshot%26TIME%3D168919892; 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.1417875721998036; path=/; expires=Mon, 28-Nov-44 14:22:01 GMT
Strict-Transport-Security: max-age=14400
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8

VERIFIED
[2014-12-06 22:21 PRC] Verified IPN: cmd=_notify-validate&mc_gross=55.90&protection_eligibility=Eligible&address_status=unconfirmed&payer_id=JARYJK2TES6C6&tax=0.90&address_street=NO+1+Nan+Jin+Road&payment_date=06%3A21%3A54+Dec+06%2C+2014+PST&payment_status=Completed&charset=gb2312&address_zip=200000&first_name=Test&mc_fee=2.20&address_country_code=CN&address_name=Buyer+Test&notify_version=3.8&custom=&payer_status=unverified&business=yxw.2013.03-facilitator%40gmail.com&address_country=China&address_city=Shanghai&quantity=1&verify_sign=AUaxvSojqajxsiGA9qXfGuCulUctAIsI7u6BJGTRbntLsB6UI3lGIXb0&payer_email=yxw.2013.03-buyer%40gmail.com&txn_id=1TM13495A76848512&payment_type=instant&btn_id=3042078&last_name=Buyer&address_state=Shanghai&receiver_email=yxw.2013.03-facilitator%40gmail.com&payment_fee=2.20&shipping_discount=0.00&insurance_amount=0.00&receiver_id=2XP27KEMUVN8A&txn_type=web_accept&item_name=sandbox_item111&discount=0.00&mc_currency=USD&item_number=&residence_country=CN&test_ipn=1&shipping_method=Default&handling_amount=0.00&transaction_subject=&payment_gross=55.90&shipping=10.00&ipn_track_id=a6f9e0f859c1c



發佈了62 篇原創文章 · 獲贊 13 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章