探索:CodeIgniter集成MD5簽名版本支付寶方案(持續(xù)更新中)

本文使用的支付寶即時到賬業(yè)務(wù)接口,API文檔下載地址:支付寶即時到賬接口文檔

1. 集成支付寶的CI目錄結(jié)構(gòu)

├─config 配置文件目錄
│ ├─alipay.php 支付寶配置文件
│ └─...
├─...
├─libraries 擴展類庫目錄
│ ├─MY_AlipayNotify.php 支付寶返回通知
│ ├─MY_AlipaySubmit.php 支付提交
│ ├─Payment 各種支付類庫目錄
│ │ ├─Alipaylib 支付寶類庫包目錄
│ │ │ ├─alipay_core.function.php
│ │ │ ├─alipay_md5.function.php
│ │ │ ├─alipay_submit.class.php
│ │ │ ├─alipay_notify.class.php
│ │ │ └─cacert.pem
│ │ ├─Wechatpay 微信支付類庫目錄
│ │ └─... 更多支付類庫目錄
│ └─... 更多第三方類庫目錄
└─...

2. alipay.php 支付寶配置文件
<?php defined('BASEPATH') OR exit('No direct script access allowed');
/**
 * Alipay 配置文件
 */
//↓↓↓↓↓↓↓↓↓↓請在這里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
//合作身份者ID,簽約賬號渺鹦,以2088開頭由16位純數(shù)字組成的字符串赁酝,查看地址:https://b.alipay.com/order/pidAndKey.htm
$config['partner']       = '';

//收款支付寶賬號路星,以2088開頭由16位純數(shù)字組成的字符串并蝗,一般情況下收款賬號就是簽約賬號
$config['seller_id'] = $config['partner'];

// MD5密鑰卧檐,安全檢驗碼克懊,由數(shù)字和字母組成的32位字符串忱辅,查看地址:https://b.alipay.com/order/pidAndKey.htm
$config['key']           = '';

// 服務(wù)器異步通知頁面路徑  需http://格式的完整路徑七蜘,不能加?id=123這類自定義參數(shù),必須外網(wǎng)可以正常訪問
$config['notify_url'] = site_url('pay/alipaynotify');

// 頁面跳轉(zhuǎn)同步通知頁面路徑 需http://格式的完整路徑墙懂,不能加?id=123這類自定義參數(shù)橡卤,必須外網(wǎng)可以正常訪問
$config['return_url'] = site_url('pay/alipayreturn');

//簽名方式
$config['sign_type']    = strtoupper('MD5');

//字符編碼格式 目前支持 gbk 或 utf-8
$config['input_charset']= strtolower('utf-8');

//ca證書路徑地址,用于curl中ssl校驗
//請保證cacert.pem文件在當前文件夾目錄中
$config['cacert']    = getcwd().'\\cacert.pem';

//訪問模式,根據(jù)自己的服務(wù)器是否支持ssl訪問损搬,若支持請選擇https碧库;若不支持請選擇http
$config['transport']    = 'http';

// 支付類型 ,無需修改
$config['payment_type'] = "1";
        
// 產(chǎn)品類型巧勤,無需修改
$config['service'] = "create_direct_pay_by_user";

//↑↑↑↑↑↑↑↑↑↑請在這里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑


//↓↓↓↓↓↓↓↓↓↓ 請在這里配置防釣魚信息嵌灰,如果沒開通防釣魚功能,為空即可 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    
// 防釣魚時間戳  若要使用請調(diào)用類文件submit中的query_timestamp函數(shù)
$config['anti_phishing_key'] = "";
    
// 客戶端的IP地址 非局域網(wǎng)的外網(wǎng)IP地址颅悉,如:221.0.0.1
$config['exter_invoke_ip'] = "";
        
//↑↑↑↑↑↑↑↑↑↑請在這里配置防釣魚信息沽瞭,如果沒開通防釣魚功能,為空即可 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
?>
3. MY_AlipaySubmit.php 支付寶支付
<?php defined('BASEPATH') OR exit('No direct script access allowed');

// 加載支付寶支付提交類
require_once APPPATH.'libraries/Payment/Alipaylib/alipay_submit.class.php';

/**
 * MY_AlipaySubmit 
 * @author Mike Lee
 */
class MY_AlipaySubmit extends AlipaySubmit {
    
    protected $_CI;

    public function  __construct($config = array()){
        // 獲得 _CI 超級對象
        $this->_CI = & get_instance();
        
        // 判斷是否存在配置文件
        if (empty($config)) {
            // 加載 Alipay 配置文件
            $this->_CI->load->config('alipay', TRUE);
            $config = $this->_CI->config->item('alipay');
        }

        parent::__construct($config);
    }

    /**
     * submit 支付提交
     * @access public
     * @param string $out_trade_no 商戶訂單號 商戶網(wǎng)站訂單系統(tǒng)中唯一訂單號
     * @param string $subject 訂單名稱
     * @param float $total_fee 付款金額
     * @param string $body 商品描述 可空
     * @return void
     * @author Mike Lee
     */
    public function submit($order_code){
        $this->_CI->load->model('order_model');
        $order_info = $this->_CI->order_model->getOrderByID($order_code, true);
        if ( ! is_array($order_info) || ! $order_info) return false;
        $subject = 'XXXX訂單';
        $total_fee = $order_info['order_amount'];
        $body = 'XXXX網(wǎng)站商品購買';
        // 構(gòu)造要請求的參數(shù)數(shù)組
        $parameter = array(
            "service"           => $this->alipay_config['service'],
            "partner"           => $this->alipay_config['partner'],
            "seller_id"         => $this->alipay_config['seller_id'],
            "payment_type"      => $this->alipay_config['payment_type'],
            "notify_url"        => $this->alipay_config['notify_url'],
            "return_url"        => $this->alipay_config['return_url'],

            "anti_phishing_key" => $this->alipay_config['anti_phishing_key'],
            "exter_invoke_ip"   => $this->alipay_config['exter_invoke_ip'],
            "out_trade_no"      => $order_code,
            "subject"           => $subject,
            "total_fee"         => $total_fee,
            "body"              => $body,
            "_input_charset"    => trim(strtolower($this->alipay_config['input_charset']))
        );

        $html_text = $this->buildRequestForm($parameter, 'get', '確認');
        return $html_text;
    }


}

/* End of file MY_AlipaySubmit.php */
/* Location: ./application/libraries/MY_AlipaySubmit.php */
?>
4. MY_AlipayReturn.php 支付寶返回通知
<?php defined('BASEPATH') OR exit('No direct script access allowed');

// 加載支付寶通知類
require_once APPPATH.'libraries/Payment/Alipaylib/alipay_notify.class.php';

/**
 * MY_AlipayNotify
 * @author Mike Lee
 */
class MY_AlipayNotify extends AlipayNotify {
    
    protected $_CI;

    public function  __construct($config = array()){
        // 獲得 CI 超級對象 使得自定義類可以使用Controller類的方法
        $this->_CI = & get_instance();
        
        // 判斷是否存在配置文件
        if (empty($config)) {
            // 加載 Alipay 配置文件
            $this->_CI->load->config('alipay', TRUE);
            $config = $this->_CI->config->item('alipay');
        }

        parent::__construct($config);
    }

    /**
     * asynNotify 異步通知
     * @access public
     * @param void
     * @return void
     * @author Mike Lee
     */
    public function asynNotify(){
        $verify_result = $this->verifyNotify();
        if($verify_result) {    //驗證成功
            $notify_data = $this->_CI->input->post(null, true);
            //交易狀態(tài)
            $trade_status = $notify_data['trade_status'];
            // 根據(jù)交易狀態(tài)處理訂單支付狀態(tài)
            if($trade_status == 'TRADE_FINISHED' || $trade_status == 'TRADE_SUCCESS') {
                // 更新訂單支付信息
                $this->updateOrderPay($notify_data);
            }
            echo 'success';     //請不要修改或刪除

        } else {    //驗證失敗
            echo 'fail';    //請不要修改或刪除
        }
    }

    /**
     * syncReturn 頁面跳轉(zhuǎn)同步通知
     * @access public
     * @param void
     * @return void
     * @author Mike Lee
     */
    public function syncReturn(){
        $verify_result = $this->verifyReturn();
        if($verify_result) {    // 驗證成功
            $return_data = $this->_CI->input->get(null, true);
            // 交易狀態(tài)
            $trade_status = $return_data['trade_status'];
            if($trade_status == 'TRADE_FINISHED' || $trade_status == 'TRADE_SUCCESS') {
                // 更新訂單支付信息
                $this->updateOrderPay($return_data);
                return true;
            } else {
                return false;
            }
            return true;
        } else {
            // 驗證失敗
            return false;
        }
    }

    /**
     * updateOrderPay 更新訂單支付信息
     * @access private
     * @param string $order_code
     * @return mixed
     * @author Mike Lee
     */
    public function updateOrderPay($alipay_data){
        $this->_CI->load->model('order_model');
        // 根據(jù)訂單號獲取訂單信息
        $order_code = $alipay_data['out_trade_no'];
        $order_info = $this->_CI->order_model->getOrderByID($order_code, true);
        // 判斷訂單狀態(tài)以及是否已經(jīng)支付
        if ($order_info['order_status'] == 0 && $order_info['pay_status'] != '1') {
            // 更新訂單的支付狀態(tài)及支付方式
            // pay_status => 1 表示支付成功
            // pay_method => 3 表示支付方式為支付寶支付
            $pay_info = array('pay_status' => '1', 'pay_method' => 3);
            $pay_result = $this->_CI->order_model->updateOrderPayStatus($order_code, $pay_info, true);
            // 添加訂單支付信息
            // user_id 用戶ID
            // order_id 訂單ID
            // total_fee 支付總額
            // openid 用戶支付寶ID buyer_id
            $order_pay_info = array(
                'user_id'   => $order_info['user_id'],
                'order_id'  => $order_info['id'],
                'total_fee' => $alipay_data['total_fee'],
                #'total_fee' => $alipay_data['price'],
                'buyer_id'    => $alipay_data['buyer_id'],
                'time'      => time()
            );
            $this->_CI->order_model->addOrderPayLog($order_pay_info);
            // 添加用戶收支日志
            // correlation_id 關(guān)聯(lián)ID 這里為訂單ID
            // action_type => 1 表示為XXXX商品購買事件
            // point_type => 5 表示為支付寶支付
            $payment_log = array(
                'user_id'        => $order_info['user_id'],
                'correlation_id' => $order_info['id'],
                'action_type'    => 1,
                'pay_type'     => 5,
                'total_fee'  => $alipay_data['total_fee'],
                'remark'         => 'XXX網(wǎng)站商品購買:支付寶支付'.$alipay_data['total_fee'],
                'action_ip'      => $_SERVER['REMOTE_ADDR'],
                'add_time'       => time()
            );
            $this->_CI->order_model->addUserPayLog($payment_log);
        }
        
        return true;
    }


}

/* End of file MY_AlipayNotify.php */
/* Location: ./application/libraries/MY_AlipayNotify.php */
5. Pay.php 控制器
<?php defined('BASEPATH') OR exit('No direct script access allowed');
/**
 * pay 支付控制器
 */
class Pay extends MY_Controller {

    public function __construct(){
        $this->isNeedLogin = FALSE;
        parent::__construct();
    }

    /**
     * submitPaymentToAlipay 提交支付寶支付
     * @access public
     * @param string $order_code
     * @return void
     * @author Mike Lee
     */
    public function submitPaymentToAlipay($order_code){
        $this->load->library('MY_AlipaySubmit');
        $result = $this->my_alipaysubmit->submit($order_code);
        if ($result === false) {
            // 無效訂單跳轉(zhuǎn)
            // 請注意這里的跳轉(zhuǎn)方法是自己寫的
            $this->jumpNoticePage('無訂單信息剩瓶!', $_SERVER['HTTP_REFERER'], 'ERROR');
        }

        $this->assign('html_text', $result);
        $this->display('order/alipay.html');
    }

    /**
     * aliPayNotify 支付寶異步回調(diào)
     * notify_url http://www.xxxx.com/index.php/pay/alipaynotify
     * @access public
     * @param void
     * @return void
     * @author Mike Lee
     */
    public function aliPayNotify(){
        $this->load->library('MY_AlipayNotify');
        $this->my_alipaynotify->asynNotify();
    }

    /**
     * aliPayReturn 支付寶同步通知
     * return_url http://www.xxxx.com/index.php/pay/alipayreturn
     * @access public
     * @param void
     * @return void
     * @author Mike Lee
     */
    public function aliPayReturn(){
        $this->load->library('MY_AlipayNotify');
        if ($this->my_alipaynotify->syncReturn()) {
            // 驗證成功 這里可以執(zhí)行你想要的跳轉(zhuǎn)
            $this->jumpNoticePage('訂單支付成功驹溃!', site_url('order'));
        } else {
            // 驗證失敗跳轉(zhuǎn)
            $this->jumpNoticePage('訂單支付失敗儒搭!', site_url('order'), 'ERROR');
        }
    }
6. 小結(jié)

總體來說吠架,支付寶支付的使用還是很簡單的,目前支付寶即時到賬有密退款DEMO還沒有去研究搂鲫,有時間肯定會繼續(xù)更新的。另外我覺得支付寶即時到賬DEMO中庫文件太多磺平,后期準備將這些庫文件整理成一個文件一個類魂仍,這樣可以讓整個集成結(jié)構(gòu)更加清晰。
在調(diào)用支付寶支付成功后支付寶的同步跳轉(zhuǎn)中出現(xiàn)了一個不明原因的驗證錯誤拣挪,經(jīng)過調(diào)試發(fā)現(xiàn)擦酌,在執(zhí)行verifyReturn驗證方法的過程中有個去除空值及簽名參數(shù)的函數(shù)paraFilter執(zhí)行后會使得$_GET中的第一個參數(shù)丟失,比如$para_temp['body']為第一個參數(shù)且不為空菠劝,執(zhí)行paraFilter($para_temp)后body丟失了赊舶,但這個函數(shù)本身是沒有問題的,這就導致我至今還沒有找到造成參數(shù)丟失的原因赶诊,只好按照支付寶技術(shù)支持的方法在丟失參數(shù)的地方手動加上這個參數(shù)笼平,這才驗證通過。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末舔痪,一起剝皮案震驚了整個濱河市寓调,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锄码,老刑警劉巖夺英,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晌涕,死亡現(xiàn)場離奇詭異,居然都是意外死亡痛悯,警方通過查閱死者的電腦和手機余黎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來载萌,“玉大人驯耻,你說我怎么就攤上這事〕纯迹” “怎么了可缚?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長斋枢。 經(jīng)常有香客問我帘靡,道長,這世上最難降的妖魔是什么瓤帚? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任描姚,我火速辦了婚禮,結(jié)果婚禮上戈次,老公的妹妹穿的比我還像新娘轩勘。我一直安慰自己,他們只是感情好怯邪,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布绊寻。 她就那樣靜靜地躺著,像睡著了一般悬秉。 火紅的嫁衣襯著肌膚如雪澄步。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天和泌,我揣著相機與錄音村缸,去河邊找鬼。 笑死武氓,一個胖子當著我的面吹牛梯皿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播县恕,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼东羹,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了弱睦?” 一聲冷哼從身側(cè)響起百姓,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎况木,沒想到半個月后垒拢,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旬迹,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年求类,在試婚紗的時候發(fā)現(xiàn)自己被綠了奔垦。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡尸疆,死狀恐怖椿猎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情寿弱,我是刑警寧澤犯眠,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站症革,受9級特大地震影響筐咧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜噪矛,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一量蕊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧艇挨,春花似錦残炮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至楷怒,卻和暖如春蛋勺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留附较,地道東北人孩灯。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像碉怔,于是被迫代替她去往敵國和親烘贴。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 最近做系統(tǒng)撮胧,需要實現(xiàn)在線支付功能桨踪,毫不猶豫,選擇的是支付寶的接口支付功能芹啥。這里我用的是即時到帳的接口锻离,具體實現(xiàn)的步...
    geeooooz閱讀 9,839評論 0 3
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,103評論 25 707
  • 現(xiàn)支付寶的通知有兩類铺峭。A服務(wù)器通知,對應(yīng)的參數(shù)為notify_url汽纠,支付寶通知使用POST方式B頁面跳轉(zhuǎn)通知卫键,對...
    hx永恒之戀閱讀 19,355評論 0 15
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件虱朵、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,102評論 4 62
  • 最近微博上一段視頻引起廣大網(wǎng)友的廣泛刷屏莉炉。內(nèi)容大致是因受臺風天鴿的影響,廣州飛機場臨時決定延遲飛機的起風時間碴犬。 前...
    順水河畔閱讀 326評論 0 1