paypal的工作流程
1:首先,用户将paypal所需的参数,诸如该次交易的目的账号,金额,货物名,个数等等一并按paypal提供的参数手册写成一个NVP字符串大概如下面这样
$nvpstr=
"&AMT=".$payAmount //总金额
."&PAYMENTACTION=".$payType //交易类型,一般是‘sale’,也可以是捐助的类型
."&RETURNURL=".$returnURL //如果交易成功,返回到的URL
."&CANCELURL=".$cancelURL //如果交易失败,返回到的url
."&CURRENCYCODE=".$currency //货币类型
."&DESC=".$desc; //货物描述
这些参数为最基本的,也有一些其他可选的参数,具体可参考官方文档
写完后,将这字符串发送给paypal生成一个token,具体做法就是将其与提供的生成token的url连起来发送一个http请求,我是用php的curl库来实现的
define('API_ENDPOINT', 'https://api-3t.sandbox.paypal.com/nvp');
$API_Endpoint =API_ENDPOINT;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$API_Endpoint);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_POST, 1);
$nvpreq="METHOD=".urlencode($methodName)."//方法名(有三种,这里是取得token所以是SetExpressCheckout)
&VERSION=".urlencode($version)."//api的版本号
&PWD=".urlencode($API_Password)."//商户的密码,该参数为商家在paypal注册后通过申请获得
&USER=".urlencode($API_UserName)."//商户的用户名,该参数为商家在paypal注册后通过申请获得
&SIGNATURE=".urlencode($API_Signature)//商户的签名证书,该参数为商家在paypal注册后通过申请获得
.$nvpStr; //之前生成的商品交易信息字符串
curl_setopt($ch,CURLOPT_POSTFIELDS,$nvpreq);
$response = curl_exec($ch);
token是一个杂乱的字符串,可能是paypal通过某种算法算出来的,也可能是随机生成的,但不管怎么样,你必须将这个token附加到paypal的支付页面的URL的最后的token=后面,然后访问该URL便可开始交易
define('PAYPAL_URL', 'https://www.sandbox.paypal.com/cgi-bin/webscr&cmd=_express-checkout&useraction=commit&token=');
$token = urldecode($resArray["TOKEN"]);//获取token
$payPalURL = PAYPAL_URL.$token;//
header($payPalURL);//访问paypal页面进行交易
2:这个时候,应该进入paypal支付页面了,当买家登陆并确认了订单,页面将返回你之前在NVP字符串中设置的returnURL页面,如果买家点了取消,跳到cancelURL
在returnURL我们将调用paypal提供的第二个函数GetExpressCheckoutDetails来取得一些购买者的信息,比如说,送货地址,这个函数一般做实物交易的用的比较多。同时,token也被传输回来,应为在接下来需要这个。
3:以上的步骤仅仅只是paypal获取交易所有信息,买家卖家做准备的过程,最后一步,调用DoExpressCheckoutPayment后,paypal才真正的将钱从买家账户转移到卖家账户并收取它的服务费用。
以上大致为paypal的支付过程,整个过程中,paypal的token作为整个交易的唯一标示,从将参数发往api-endpiont获得开始,一直参与其中直到交易的完成,这个token是有时效的。
以下为我使用的完整的paypal nvp类
<?php
//以下URL为sanbox,亦即沙盒,表明属于测试环境,真实环境为https://api-3t.paypal.com/nvp和https://www.paypal.com/cgi-bin/webscr&cmd=_express-checkout&useraction=commit&token=
define('API_ENDPOINT', 'https://api-3t.sandbox.paypal.com/nvp');
define('PAYPAL_URL', 'https://www.sandbox.paypal.com/cgi-bin/webscr&cmd=_express-checkout&useraction=commit&token=');
$API_Endpoint =API_ENDPOINT;
class paypal {
public $errMsg = array();
function __construct() {
}
//获取token的函数
function SetExpressCheckout($params) {
$token = '';
$serverName = $_SERVER['SERVER_NAME'];
$serverPort = $_SERVER['SERVER_PORT'];
$url = dirname('https://'.$serverName.':'.$serverPort.$_SERVER['REQUEST_URI']);
$payAmount = $params['amount'];
$currency = $params['currency'];
$payType = $params['payType'];
$desc = $params['DESC'];
$returnURL = urlencode($url.'/'.$params['returnPage'].'?cmd=paypal¤cy='.$currency.'&payType='.$payType.'&payAmount='.$payAmount);
$cancelURL = urlencode($url.'/'.$params['cancelPage'].'?cmd=cancel');
$nvpstr = "&AMT=".$payAmount."&PAYMENTACTION=".$payType."&RETURNURL=".$returnURL."&CANCELURL=".$cancelURL."&CURRENCYCODE=".$currency."&DESC=".$desc;
$resArray=self::makeCall("SetExpressCheckout", $nvpstr);
if(!$resArray) {
return false;
}
if(array_key_exists('ACK', $resArray) AND strtoupper($resArray['ACK']) == 'SUCCESS') {
if (array_key_exists("TOKEN",$resArray)) {
$token = urldecode($resArray["TOKEN"]);
}
$payPalURL = PAYPAL_URL.$token;
echo $payPalURL;
return $payPalURL;
}
//插入你的异常处理
}
//
function GetExpressCheckoutDetails($params) {
$token = urlencode($params['token']);
$nvpstr = "&TOKEN=".$token;
$resArray = self::makeCall("GetExpressCheckoutDetails",$nvpstr);
if(!$resArray) {
return false;
}
if(array_key_exists('ACK', $resArray) AND strtoupper($resArray['ACK']) == 'SUCCESS') {
return $resArray;
} else {
//插入你的异常处理
}
}
//确定执行交易
function DoExpressCheckoutPayment($params) {
$token = urlencode( $params['token']);
$payAmount = urlencode ($params['payAmount']);
$payType = urlencode($params['payType']);
$payerID = urlencode($params['PayerID']);
$nvpstr = '&TOKEN='.$token.'&PAYERID='.$payerID.'&PAYMENTACTION='.$payType.'&AMT='.$payAmount ;
$resArray = self::makeCall("DoExpressCheckoutPayment",$nvpstr);
if(!$resArray) {
return false;
}
if(array_key_exists('ACK', $resArray) AND strtoupper($resArray['ACK']) == 'SUCCESS') {
return $resArray;
} else {
//插入你的异常处理
}
}
function RefundTransaction($params) {
$type = $params['type'];
$transactionId = $params['transactionId'];
$amount = urlencode($params['amount']);
$nvpstr = '&TRANSACTIONID='.$transactionId.'&REFUNDTYPE='.$type;
if($type == 'Full')
$nvpstr .= '&AMT='.$amount;
$resArray = self::makeCall("RefundTransaction", $nvpstr);
if(!$resArray){
return false;
}
if(array_key_exists('ACK', $resArray) AND strtoupper($resArray['ACK']) == 'SUCCESS') {
return $resArray;
} else {
//插入你的异常处理
}
}
通过curl库来发送请求,被以上的函数调用
function makeCall($methodName,$nvpStr) {
global $API_Endpoint;
$version = '82.0';
//获取商家,亦即卖家的账户名,密码和签名,我将这些放在一个xml文件中读取,读者可自行决定如何取这些
$xml = new DOMDocument ( );
$xml->load("xml/xmlforpaypal.xml");
$item = $xml->getElementsByTagName("root")->item(0);
$item = $xml->getElementsByTagName("paypal")->item(0);
$username = $item->getElementsByTagName("username")->item(0)->textContent;
$password = $item->getElementsByTagName("password")->item(0)->textContent;
$signature = $item->getElementsByTagName("signature")->item(0)->textContent;
$API_UserName = $username;
$API_Password = $password;
$API_Signature = $signature;
// $nvp_Header;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$API_Endpoint);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
/* if(USE_PROXY)//如果使用代理
{
curl_setopt ($ch, CURLOPT_PROXY, PROXY_HOST.":".PROXY_PORT);
}*/
$nvpreq = "METHOD=".urlencode($methodName)."&VERSION=".urlencode($version)."&PWD=".urlencode($API_Password)."&USER=".urlencode($API_UserName)."&SIGNATURE=".urlencode($API_Signature).$nvpStr;
curl_setopt($ch, CURLOPT_POSTFIELDS, $nvpreq);
$response = curl_exec($ch);
$nvpResArray=self::deformatNVP($response);
if (!$response) {
//插入你的异常处理函数
return false;
} else {
curl_close($ch);
}
return $nvpResArray;
}
//关于字符串的你懂的
function deformatNVP($nvpstr) {
$intial = 0;
$nvpArray = array();
while(strlen($nvpstr)) {
$keypos = strpos($nvpstr, '=');
$valuepos = strpos($nvpstr,'&') ? strpos($nvpstr,'&') : strlen($nvpstr);
$keyval = substr($nvpstr, $intial, $keypos);
$valval = substr($nvpstr, $keypos+1, $valuepos-$keypos-1);
$nvpArray[urldecode($keyval)] = urldecode($valval);
$nvpstr = substr($nvpstr, $valuepos+1, strlen($nvpstr));
}
return $nvpArray;
}
}
?>