*CodeIgniter框架集成支付寶即時到帳SDK

客戶的網站須要支付功能,咱們選擇了業界用的最多的支付寶即時到帳支付。申請了兩次將近兩週的時間終於下來了,因而我開始着手測試SDK整合支付流程。php

SDK中的代碼並不複雜,就是構造請求發送,接收並驗證簽名而已。SDK根目錄中的文件基本是示例,開發的時候用於參照, lib 目錄中是核心庫文件,在CodeIgniter中須要把這個目錄放到 application/third_party 目錄下,並將目錄名改成 alipay 方便標識,證書文件 cacert.pem 也放進去。其實更好的方式是把類文件放到 application/libraries 目錄並使用Loader加載類庫,可是其中有兩個公共函數文件引用,省的加載麻煩就直接 require_once() 了。html

配置文件也須要單獨增長一個 alipay.php 在 application/config 目錄中,主要能夠照搬示例中的 alipay.config.php 的內容,我是這麼寫的:git

$config['partner'] = '商戶id'; $config['key'] = '商戶API key'; $config['seller_email'] = '商戶支付寶郵箱帳號'; $config['payment_type'] = 1; $config['transport'] = 'http'; $config['input_charset'] = 'utf-8'; $config['sign_type'] = 'MD5'; $config['notify_url'] = 'http://'.$_SERVER['HTTP_HOST'].'/order/callback/notify'; $config['return_url'] = 'http://'.$_SERVER['HTTP_HOST'].'/order/callback/return'; $config['cacert'] = APPPATH.'third_party/alipay/cacert.pem'; 

以後就是在訂單控制器中處理支付了,當建立了一個商品訂單後,給用戶一個連接按鈕,跳轉到 /order/pay 控制器進行支付寶請求中轉,主要能夠參照示例 alipayapi.php 文件內容,調用SDK函數生成一個提交表單,渲染在模板中由JS控制自動提交。程序員

// 訂單控制器類 class Order extends CI_Controller{  // ...  public function pay($id) {   // 獲取訂單數據示例   $order = $this->model->get($id);   // 加載支付寶配置   $this->config->load('alipay', TRUE);   // 加載支付寶支付請求類庫   require_once(APPPATH."third_party/alipay/alipay_submit.class.php");   $submit = new AlipaySubmit($this->config->item('alipay'));   $body = $submit->buildRequestForm(array(    'service' => 'create_direct_pay_by_user',    'partner' => $this->config->item('partner', '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'),    'seller_email' => $this->config->item('seller_email', 'alipay'),    'out_trade_no' => $id,    'subject' => $order['product']['name'],    'total_fee' => $order['price'],    'body' => $order['product']['name'],    'show_url' => 'http://'.$_SERVER['HTTP_HOST'].'/product/view/'.$order['productId'],    'anti_phishing_key' => '',    'exter_invoke_ip' => '',    '_input_charset' => $this->config->item('input_charset', 'alipay')   ));   // 渲染模板,原生的這麼寫,我本身另外用smarty3   $this->load->view('pay', array('body' => $body));  }  // ... } 

正常的話用戶瀏覽器會跳轉到支付寶完成支付,以後再跳轉回以前配置了的 return_url 上,這個控制器方法我命名爲 /order/callback/<method> ,經過參數指定是同步返回仍是異步通知,但裏面的業務邏輯處理差很少。github

// 仍是訂單控制器類 class Order extends CI_Controller{  // $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;   }   // 支付寶返回支付成功和交易結束標誌   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));   } else {    // 同步方式跳轉到訂單詳情控制器,redirect方法要你本身寫    return $this->redirect("order/view/$id#status:$notify_status");   }  } } 

到這正常的話數據庫已經更新訂單信息,後臺管理也就能夠根據支付狀況去後面的配送流程。但問題是,在CI中正常狀況根本到不了這裏!因此我要開始吐槽支付寶的SDK!ajax

會遇到的問題

PHP cURL模塊未安裝

VPS用的ubuntu系統,默認PHP的cURL模塊沒有,須要命令行安裝:sql

$ sudo apt-get install curl php5-curl 

好吧,這是我沒有看 readme.txt 文檔,而後 var_dump() 花了三分錢才找到這個問題。數據庫

MD5簽名驗證不經過

這纔是真正坑爹的問題!以前測試一直是支付成功但返回調用驗證失敗,直到我一步一步跟到SDK的源碼裏去對比要驗證的簽名串,才發現這根本就是SDK的一個BUG!請看 alipay_core.function.php 文件的 paraFilter 函數,這個函數的做用是過濾掉簽名參數和空值參數,以便生成簽名串。原來的SDK是這麼寫的:ubuntu

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 !循環會死麼! 修改後的代碼以下:api

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; } 

這纔算解決了簽名不正確的問題。

另外,看了SDK源碼才發現,支付寶的PHP程序員英文真是爛,各類拼寫錯誤,好比:verify寫成veryfy,sign寫成sgin……實在是無力吐槽。

好了,我把修改過的SDK包放在GitHub上了: https://github.com/mytharcher/alipay-php-sdk ,有須要請自取。

-EOF-

 

http://yanjunyi.com/blog/posts/alipay-integration-in-codeigniter.html?utm_source=tuicool

相關文章
相關標籤/搜索