不多說,直接上代碼,讓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; }
這才算解決了簽名不正確的問題。