月度归档:2012年06月

paypal支付开发解析(二)

在注册完成开发账户,虚拟的买家账户以及卖家账户后,即可准备开始开发,不过在此需要明白IPN与PDT是什么。

IPN(Instant Payment Notify) 即时付款传输

什么事即时付款通知,pdf文档里面说得很明白,一张图更加的有助于理解。

其中1到5这个动作过程就是即时付款通知的整个流程。详细解释如下

注意这里的IPN,是由paypal服务器主动把数据post到你指定的url页面,这里的url怎么设置?即IPN是如何启用的呢?

pdf文档里面说明了有两种方法,一是在卖家paypal登录账户后,在“用户信息”右边列表栏“即时付款通知习惯设定”点击那个“选择框” 输入通知的url地址

二是在表单中加入name为notify_url的隐藏域地址来启用IPN。

在这里我们采用第二种方法。

直观的示例代码:

// paypal发送至的$_POST数据
if(!empty($_POST)) {
$notify = $_POST;
$location = TRUE;
} else {
exit('Access Denied');
}
// 加上cmd命令 数据原样返回
$tmpAr = array_merge($_POST, array("cmd" => "_notify-validate"));
$postFieldsAr = array();
foreach ($tmpAr as $name => $value) {
$postFieldsAr[] = "$name=$value";
}
// $custom 自定义值
$customs = explode( '|', $notify['custom']);
// 订单编号
$orderid = $customs[1];
// 使用curl 发送至paypal服务器,返回VERIFIED或者是INVALID
$ppResponseAr = PPHttpPost(PAYPAL_URL, implode("&", $postFieldsAr), false);

$notifydata= array();
if( strcmp($ppResponseAr['httpResponse'], 'VERIFIED') == 0){
         // 数据验证成功,检测处理的订单数据,如订单状态是否完成,卖家商户邮箱是否一致,此次订单货币是否与表单提交一致等
if( ($notify['payment_status'] == 'Completed') && ($notify['receiver_email'] == DEFAULT_EMAIL_ADDRESS) && ($notify['mc_currency'] == 'USD') ){
$notifydata= array(
'validator'    => TRUE,
'status'    => 'completed',
'order_no'     => $orderid,
'price'     => $notify['mc_gross'] ? $notify['mc_gross'] : $notify['payment_gross'],
'trade_no'    => $notify['txn_id'],
'notify'    => 'success',
'location'    => $location
);
}
}else if( strcmp($ppResponseAr['httpResponse'], 'INVALID') == 0) {
$notifydata= array(
'validator'    => FALSE,
'notify'    => 'fail',
'location'    => $location
);
}

    /**
     * 结合discuzx的具体业务逻辑实现数据内容的更新
     */

// 订单数据paypal验证成功情况下
if($notifydata['validator']) {

$orderid = $notifydata['order_no'];
$postprice = $notifydata['price'];
$order = DB::fetch_first("SELECT o.*, m.username FROM ".DB::table('forum_order')." o LEFT JOIN ".DB::table('common_member')." m USING (uid) WHERE o.orderid='$orderid'");
if($order && floatval($postprice) == floatval($order['price']) ) {
        // 更新订单状态
if($order['status'] == 1) {
DB::query("UPDATE ".DB::table('forum_order')." SET status='2', buyer='$notifydata[trade_no]\tpaypal', paytype='paypal', confirmdate='$_G[timestamp]' WHERE orderid='$orderid'");
            // 更新用户的虚拟货币
updatemembercount($order['uid'], array($_G['setting']['creditstrans'] => $order['amount']), 1, 'AFD', $order['uid']);
updatecreditbyaction($action, $uid = 0, $extrasql = array(), $needle = '', $coef = 1, $update = 1, $fid = 0);
            // 清理过期的订单
DB::query("DELETE FROM ".DB::table('forum_order')." WHERE submitdate<'$_G[timestamp]'-60*86400");

$submitdate = dgmdate($order['submitdate']);
$confirmdate = dgmdate(TIMESTAMP);
            // 向用户发送充值成功的消息
notification_add($order['uid'], 'credit', 'addfunds_d', array(
'orderid' => $order['orderid'],
'price' => $order['price'],
'value' => $_G['setting']['extcredits'][$_G['setting']['creditstrans']]['title'].' '.$order['amount'].' '.$_G['setting']['extcredits'][$_G['setting']['creditstrans']]['unit']
), 1);
}

}

}

// 充值成功,跳转
if($notifydata['location']) {
$url = rawurlencode('home.php?mod=spacecp&ac=credit');

dheader('location: '.$_G['siteurl'].'forum.php?mod=misc&action=paysucceed');
} else {
    // 充值失败,显示提示信息
exit($notifydata['notify']);
}

至此IPN作用完成,同时整个充值过程也就完成了,不过用户这时还停留在paypal的支付完成的页面,不会自动跳转至商户或者用户已充值记录页面。这时,PDT的作用就出现了。

PDT(Payment Data Transfer)付款数据传输

同样PDT示意图

怎样启用PDT呢,方式一需要卖家账户登录,在“用户信息”; “网站付款习惯设定”; 设置auto return 为“on”;同时在return url中设置返回的url地址;设置“Payment Data Transfer”为“on” ;点击“save”保存,这时“身份标记”就永久的显示在网页上面了。

方式二 订单或充值表单中添加hidden隐藏域

代码显示


// PDT 付款数据传输 ,DEFAULT_IDENTITY_TOKEN为刚才点击“save”生成的token值,这个值可以保存到数据库中
if( DEFAULT_IDENTITY_TOKEN){
// 获取返回的tx 交易流水号
$url = PAYPAL_URL;
$postFields =    "cmd=".urlencode("_notify-synch").
"&tx=".urlencode(htmlspecialchars($_GET["tx"])).
"&at=".urlencode(DEFAULT_IDENTITY_TOKEN);

// 请求paypal或者 付款信息明细
$ppResponseAr = PPHttpPost($url, $postFields, true);

// 不存在该交易付款信息明细
if( !$ppResponseAr['status']){
$ppResponseAr["error_msg"] = '抱歉,支付失败';

}else {
// 存在该交易
$response = $ppResponseAr['httpParsedResponseAr'];
// var_dump( $response);exit;
$tradeno = $response['txn_id'];        // paypal的交易订单

// paypal存在交易订单,且为完成状态
if( ($response['payment_status'] == 'Completed') && (urldecode($response['receiver_email']) == DEFAULT_EMAIL_ADDRESS)){

$query = DB::query("SELECT * FROM ".DB::table('forum_order')." WHERE orderid='$orderid'");

//判断数据库中是否存在该订单
if(DB::num_rows($query)) {
// 处理订单,更新用户的积分
$order = DB::fetch($query);

// 订单为未处理状态,则进行处理
if( $order['status'] == '1'){
// 设置订单
DB::query("UPDATE ".DB::table('forum_order')." SET status='2', buyer='{$tradeno}\tpaypal', paytype='paypal', confirmdate='$_G[timestamp]' WHERE orderid='$orderid'");
// 更新积分
updatemembercount($order['uid'], array($_G['setting']['creditstrans'] => $order['amount']), 1, 'AFD', $order['uid']);
updatecreditbyaction($action, $uid = 0, $extrasql = array(), $needle = '', $coef = 1, $update = 1, $fid = 0);
DB::query("DELETE FROM ".DB::table('forum_order')." WHERE submitdate<'$_G[timestamp]'-60*86400");

$submitdate = dgmdate($order['submitdate']);
$confirmdate = dgmdate(TIMESTAMP);

notification_add($order['uid'], 'credit', 'addfunds', array(
'orderid' => $order['orderid'],
'price' => $order['price'],
'value' => $_G['setting']['extcredits'][$_G['setting']['creditstrans']]['title'].' '.$order['amount'].' '.$_G['setting']['extcredits'][$_G['setting']['creditstrans']]['unit']
), 1);
}  // end

}
// 有待执行
}else if( $response['payment_status'] == 'Pending'){
$ppResponseAr['error_msg'] = '款项等待支付,请前往paypal确认接受';
}

}

}else {
$ppResponseAr["status"] = FALSE;
$ppResponseAr["error_msg"] = '正在处理,请稍后';
}

// 提示用户交易完成
showmessage( '感谢您的付款。您的交易已经完成,您可以在www.paypal.com/c2 上登录您的账户查看此次交易情况。 '.$response['payment_status'], 'home.php?mod=spacecp&ac=credit&op=log');

不过这里测试与debug调试表现的都比较简陋,其实可以在充值记录过程中,把一些状态信息都可以进行写入log文件,这样便于监测与管理。主要的逻辑结合处就是程序根据paypal支付返回的数据进行本地的业务进行处理,如充值完成后,通知店主发货,或者增加虚拟货币,积分等。discuzx把这些都api模块化了,很方便,paypal的开发也主要就是按照此处进行修改开发的。

 

paypal支付开发解析(一)

paypal开发在未接触之前感觉无从下手,不过在理解业务逻辑的实现,具体实现开发后,再次查看具体代码则可以很好的理解。要开发paypal的支付相关,paypal官方的sandbox平台是不可或缺的。这个很好对于开发者有很大的帮助。

我所理解的支付相关业务逻辑,主要包含两个部分一、用户使用在线支付平台进行表单提交,提交完成进而返回支付状态。二、根据支付返回的状态进而对网站的积分或者虚拟货币的业务逻辑具体实现,更新当前用户的信息状态。

帮助文档是关键,developer.paypal.com 上面都有下载,我主要用到的就是

PayPal_Sandbox_Guide_V1.0.pdf   paypal的sandbox测试指南,主要包括创建开发者账户,通过开发者账户创建虚拟卖家账户与虚拟的买家账户,并验证邮箱等完善信息。(注意这里的虚拟账户都不要填写真实的信息,包括邮箱)其中的“为卖家账户申请api”这个在我的代码开发中没有用到。

PayPal_IPN&PDT_Guide_V1.0.pdf  IPN(Instant Payment Notification)即时付款通知 这个是关键,主要的功能作用是用户在使用paypal表单提交充值或付款后,这时paypal会自动(不是网站的业务逻辑动作)请求你网站的一个页面,把此次的支付信息已经订单数据返回到你指定的这个页面。

PayPal_WPS_Guide_V1.0.pdf  主要内容是集成“buy now” 示例代码,测试等。

PP_PHP_WPS_Toolkit.zip  是一个简单的代码示例,包含表单提交支付,IPN,PDT,这个代码详细内容接下来介绍。

代码打包存放在百度网盘上面,需要的可以在这里下载 (qq中转站只有三十天)

无题

最近工作不算忙,也不算闲。事也不算多,话说入职快一年多大部分时间都挂在这个项目上了了。一般的功能开发,bug修改。但是心态上老是消极怠工。

公司近两星期三人离职了,来来走走很正常;不过像我这样的又不免一阵唏嘘了。其中一位是技术总监,没谈上关系有多好,但是也还是从他那里学到一些东西。不过可惜没有共事过一个项目,我想那样学到的可能会更多一点。

 

昨天把笔记本上的ubuntu重装一下,但是很不小心的把盘符删除错误了,E盘被华丽丽的格式化了。4、50G的东东没有了,当然像我这样不爱学习的人,一般以上是电影、音乐等。还有一半呢是些程序、图片、各种学习资料以及以前工作中的项目,可能是许久没有动过了,都不知道丢了哪些东西,一点都不心疼。即时这样,我也是知道这里面很多都是读书时的练习笔记,老师的课件,曾经做过的一些项目…现在都华丽丽的不见了,就当是从头开始了,数据备份真的很重要。

 

额。还有一点,wordpress现在的这个主题太丑了,也不想去另找其他的主题,正在写一款主题,争取下个星期前换上来。