不多说,直接上代码,让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; }
这才算解决了签名不正确的问题。