不多说,直接上代码,让CI框架集成支付宝即时到账
第一步,下载支付宝即时支付demo,我以utf8版本为例,下载下来的文件目录如下
第二步,在CodeIgniter中 application/third_party 目录下,新建文件夹alipay,将支付宝lib文件夹下的4个子文件全部放到alipay中
第三步,配置文件
在CodeIgniter中 application/config,新建alipay.php,将支付宝alipay.config.php的内容,全部搬进来,并且将数组$alipay_config重命名为$config
第四步,新建一个订单控制器,代码如下
load->view('order_show');
}
// 提交订单,付款
public function pay() {
$order=$this->input->post();
//商户订单号,商户网站订单系统中唯一订单号,必填
$out_trade_no = $order['WIDout_trade_no'];
//订单名称,必填
$subject = $order['WIDsubject'];
//付款金额,必填
$total_fee = $order['WIDtotal_fee'];
//商品描述,可空
$body = $order['WIDbody'];
// 加载支付宝配置
$this->config->load('alipay', TRUE);
// 加载支付宝支付请求类库
require_once(APPPATH."third_party/alipay/alipay_submit.class.php");
$submit = new AlipaySubmit($this->config->item('alipay'));
//构造要请求的参数数组,无需改
$html_text = $submit->buildRequestForm(array(
"service" =>$this->config->item('service', 'alipay'),
"partner" => $this->config->item('partner', 'alipay'),
"seller_id" => $this->config->item('seller_id', 'alipay'),
"payment_type" => $this->config->item('payment_type', 'alipay'),
"notify_url" => $this->config->item('notify_url', 'alipay'),
"return_url" => $this->config->item('return_url', 'alipay'),
"anti_phishing_key"=>$this->config->item('anti_phishing_key', 'alipay'),
"exter_invoke_ip"=>$this->config->item('exter_invoke_ip', 'alipay'),
"out_trade_no" => $out_trade_no,
"subject" => $subject,
"total_fee" => $total_fee,
"body" => $body,
'_input_charset' => $this->config->item('input_charset', 'alipay')
));
// 渲染模板,原生的这么写,我自己另外用smarty3
echo $html_text;
}
//支付宝付款后回调
// $method参数只能是'return'或'notify',对应URL
public function callback ($method) {
// 加载支付宝配置
$this->config->load('alipay', TRUE);
// 加载支付宝返回通知类库
require_once(APPPATH."third_party/alipay/alipay_notify.class.php");
// 初始化支付宝返回通知类
$alipayNotify = new AlipayNotify($this->config->item('alipay'));
$input = array();
$is_ajax = FALSE;
$notify_status = 'success';
// 这里做同步还是异步的判断并获取返回数据验证请求
switch ($method) {
case 'notify':
$result = $alipayNotify->verifyNotify();
$input = $this->input->post();
$is_ajax = TRUE;
break;
case 'return':
$result = $alipayNotify->verifyReturn();
$input = $this->input->get();
break;
default:
return $this->out_not_found();
break;
}
var_dump($input);exit;
// 支付宝返回支付成功和交易结束标志
if ($result && ($input['trade_status'] == 'TRADE_FINISHED' || $input['trade_status'] == 'TRADE_SUCCESS')) {
$id = $input['out_trade_no'];
// 验证成功则更新订单信息(略)
// ...
} else {
// 否则置状态为失败
$notify_status = 'fail';
}
if ($is_ajax) {
// 异步方式调用模板输出状态
// $this->view->load('alipay', array('status' => $notify_status));
// echo "异步成功";
} else {
// 同步方式跳转到订单详情控制器,redirect方法要你自己写
//return $this->redirect("order/view/$id#status:$notify_status");
//echo "同步成功";//
}
}
}
订单显示页面,参考支付宝原来的就可以了,至此,就支付宝即时付款就集成好了,当然中间业务逻辑还没有写,各位根据自己的网站需要进行编写吧
这才是真正坑爹的问题!之前测试一直是支付成功但返回调用验证失败,直到我一步一步跟到SDK的源码里去对比要验证的签名串,才发现这根本就是SDK的一个BUG!请看alipay_core.function.php文件的paraFilter函数,这个函数的作用是过滤掉签名参数和空值参数,以便生成签名串。原来的SDK是这么写的:
function paraFilter($para) { $para_filter = array(); // 问题就在这 while (list ($key, $val) = each ($para)) { if($key == "sign" || $key == "sign_type" || $val == "")continue; else $para_filter[$key] = $para[$key]; } return $para_filter; }
问题就出在while循环的条件里,每次过滤参数,这里直接就把第一个返回参数body=xxx给过滤掉了,一旦我加上body=xxx变成完整的签名参数,生成的MD5签名就能对上。我百思不得其解的时候去查了PHP的文档,根据each方法说明,每调用一次游标就会发生改变,而首次调用之前没有调用reset()的话,就很可能被之前调用过这个数组的each()给弄错游标。而每次代码中每次都是从第二个参数开始,说明数组可能已经被其他程序调用过了(这个数组实际上是系统变量$_GET,但我实在没在CI框架代码中找到哪里调用的)。所以我想说的是: 好!好!写!个!foreach!循环会死么! 修改后的代码如下:
function paraFilter($para) { // 增加这一行 reset($para); $para_filter = array(); while (list ($key, $val) = each ($para)) { if($key == "sign" || $key == "sign_type" || $val == "")continue; else $para_filter[$key] = $para[$key]; } return $para_filter; }
这才算解决了签名不正确的问题。