Codeigniter

最近準備接手改進一個別人用Codeigniter寫的項目,雖然以前也有用過CI,可是是徹底按着本身的意思寫的,沒按CI的一些套路。用在公衆的項目,最好仍是按框架規範來,因此仍是總結一下,省得之後別人再接手的時候貽笑大方。javascript

1. 首先是 MVC

若是你還不知道 MVC ,應該儘快的學習,你會很快的體會到在 Model 中數據訪問,在 Controller 中進行業務邏輯,在 Views 中編寫 HTML 代碼的價值。若是你以前沒有使用過這種模式寫過程序,你也許會皺起額頭,不過你應該給本身嘗試這樣作的機會。php

一條實踐準則是把更少的東西放進 Controller ,記住 DRY 準則:不要重複造輪子。當在超過一個地方編寫相同的代碼時,應該根據它的類型來嘗試編寫一個 library, helper,或 model。好比數據庫鏈接類,用得很頻繁,就把它作成 model(系統已提供)。css

一旦領悟了 MVC 的精髓,這將會成爲一種習慣,你會從 MVC 簡潔的代碼中受益良多。html

一個原則就是:複雜的操做都交給Model。Controller更像個建築師。 Model是苦工。 View 是粉刷工。Controller 只須要把東西丟進Model裏就能夠了,不須要在乎數據是否異常,而後返回一個標誌位以及相應的數據。這樣MVC 的 架構就體現出來了。java

Model其實就像一個電器如:微波爐同樣,使用方法越簡單越讓人喜歡,(把食物放進去 -按啓動 -ok,飯熟了。)接口少的好處是,Model升級代碼優化的時候,對外界的耦合度不高。即便你內部寫得很爛,接口也很乾淨,用起來也簡單。web

2. Application 和 System 路徑

最好是把 system 和 application 文件夾放在 webroot 之外的地方,若是 index.php 放在 FTP 服務器的 /public_html/ 路徑下,應該嘗試把 System 放在根目錄下 /system ,這樣的話,只能經過 index.php 訪問你的PHP文件。數據庫

不要忘記在index.php文件中修改 $system_folder 和 $application_folder 的值,$system_folder 的值應該是相對於 index.php 文件,而 $application_folder 的值是相對於 system 目錄。api

3. 錯誤報告和調試

經常犯的一個錯誤是忘記關閉 PHP 錯誤和數據庫錯誤報告,這樣作是有風險的。在任何一個公開的站點,error_reporting 應該設置爲0 ,最多隻能設置爲 E_ERROR,數據庫設置 db_debug 應該設置爲 false,基於其餘安全考慮,設置不顯示出錯信息 ini_set('display_errors', 'Off');數組

在你編碼和調試時,應該把 error_reporting 設置爲 E_ALL ,而且在把應用程序發佈前解決每個注意和警告。瀏覽器

一種簡易的方法是在 application/config/database.php 文件設置 db_debug 的值爲一個常量 MP_DB_DEBUG,當網站在運行中,以下設置:

ini_set('display_errors', 'Off');
error_reporting(0);
define('MP_DB_DEBUG', false);  
 

在編碼和調試中設置爲:

ini_set('display_errors', 'On');
error_reporting(E_ALL);
define('MP_DB_DEBUG', true);  

4. 安全問題很重要

在接收任何數據到你的程序以前,不論是表單提交的 POST 數據、COOKIE 數據、URI 數據、XML-RPC 數據、仍是 SERVER 數組中的數據,咱們都推薦你實踐下面的三個步驟:

  1. 過濾不良數據.
  2. 驗證數據以確保符合正確的類型, 長度, 大小等. (有時這一步驟也可取代第一步驟)
  3. 在提交數據到你的數據庫以前將其轉換.

關於SQL注入,XSS,以及 CSRF ,你應該先了解它們,再決定是否採用方法來防止它們。能夠參考CI手冊上的安全指南 以及 輸入和安全類。也許最重要的原則是在把數據提交到數據庫或文件系統以前檢查全部用戶的輸入。

  • SQL注入。使用 CI 自帶的 Active Record 能夠解決這個問題。
  • XSS (跨站腳本)。經過設置 $config['global_xss_filtering'] = TRUE; 開啓自動過濾POST和COOKIE中的跨站腳本攻擊,但須要消耗一些資源。也能夠在每次處理POST和COOKIE的時候單獨使用,把第二個參數設爲TRUE,如 $this->input->post('some_data', TRUE); 表單驗證類也提供了 XSS 過濾選項,如 $this->form_validation->set_rules('username', 'Username', 'trim|required|xss_clean');
  • CSRF (跨站請求僞造)。CI 2.0 將內置 CSRF 檢查,在 Google 上搜索 "CSRF tokens" 學習更多關於在保護表單提交和 URL 連接的知識,在 Ajax 應用方面能夠搜索 "double cookie submission" 或 "雙提交 cookie"。
  • SPAM (垃圾留言和惡意註冊)。經過保護你的郵件表單,評論表單,以及其餘各類免費用戶提交的數據來防止垃圾信息,一個簡單的方法是隻容許一個IP/User客戶端在一分鐘以內只能提交一次,一個比較好的方式是使用 Captcha ,CI2中內置了一個CAPTCHA的輔助函數。

5. 數據庫 和 ORM

CodeIgniter 有一個自帶的庫 Active Record 可以幫助你在不使用 SQL 語句的狀況下寫查詢語句。這在你不太精通 SQL 語句或不知道怎樣防止SQL注入的狀況下是一個很好的方法。

當你須要更強大的工具時,你能夠考慮使用 Object Relational Mapper ,就是鼎鼎大名的 ORM 了,遺憾的是,CodeIgniter 沒有自帶 ORM 庫,不過也有一些其餘很好的選擇。

最流行的或許是 DataMapper OverZealous Edition (DMZ),還可使用 Doctrine (這裏有一個教程),另外一個選擇 RapidDataMapper 是做者本身的做品。

6. 代碼實踐

編寫簡潔的代碼,而且理解你的代碼,不要只是複製粘貼別人的代碼,而且不斷提升編碼能力。手冊上的開發規範是一個能學習怎樣更好編寫代碼的地方。

1. DRY。不要老是重複造輪子,把能重用的代碼放在它應該在的地方,好比libraries, helpers 或者是 models,而不是controllers,一個經驗準則:當你複製代碼的時候,也許你已經第二次把它放在了錯誤的地方。

2. Caching (緩存)。緩存是一個提升性能的很好的方式,尤爲是減小數據庫的訪問。能夠參考網頁緩存和數據庫緩存,或者在論壇上搜索其餘的可選方案,好比 MP_Cache 是做者本身的做品。

3. HTTP headers (HTTP頭部)。在客戶端你可以經過單獨發送HTTP頭部使瀏覽器緩存頁面來提升性能,當你使用 AJAX 的時候你也須要了解它來禁止瀏覽器緩存。

一個禁止緩存的例子:

$this->output->set_header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
$this->output->set_header("Cache-Control: no-store, no-cache, must-revalidate");
$this->output->set_header("Cache-Control: post-check=0, pre-check=0", false);
$this->output->set_header("Pragma: no-cache");  
 

一個長時間保持緩存的例子(好比 css, javascript):

$this->output->set_header('Cache-Control: private, pre-check=0, post-check=0, max-age=2592000');
$this->output->set_header('Expires: ' . gmstrftime("%a, %d %b %Y %H:%M:%S GMT", time() + 2592000));
$this->output->set_header('Last-Modified: ' . gmstrftime("%a, %d %b %Y %H:%M:%S GMT", time() - 20));  

7. 模板渲染沒必要每次都調用 header 與 footer

在 MY_Controller 頭部和 __construct 函數中添加如下內容,用於設定默認的模版信息,其中 SITE_NAME 須要本身在 application/config/constants.php 裏面本身定義:

class MY_Controller extends CI_Controller {

    protected $_data;    // 模版傳值數組
    protected $_tplext;  // 默認模版後綴
    protected $_header;  // 默認頭部模版
    protected $_footer;  // 默認底部模版


    public function __construct () {
        parent::__construct();

        $this->_data['title'] = SITE_NAME;
        $this->_tplext = '.php';
        $this->_header = 'templates/header';
        $this->_footer = 'templates/footer';

        // 開發模式下開啓性能分析
        if (ENVIRONMENT === 'development') {
            $this->output->enable_profiler(TRUE);
        }
    }

}

8. 沒必要全部的類都繼承 CI_Controller

新增的控制器再也不繼承 CI_Controller,而改繼承 MY_Controller:

class Index extends MY_Controller {

    public function __construct () {
        parent::__construct();
    }


    /**
     * 前臺首頁
     */
    public function index () {
        $this->_data['title'] = '首頁';  // 不指定則使用默認標題 SITE_NAME
        $this->_view('index/index');
    }

}

末了,再補充兩個:

9. CodeIgniter的文件結構

cache用以存儲緩存文件,codeigniter文件夾包含了CI的基類CI_Base,爲了兼容php4和php5,CI_Base有兩個版本,其中php4版本的CI_Base繼承於CI_Loader。libraries裏存放了大部分經常使用的類庫,最主要的三個類:Model,View和Cotronller,本身寫的任何mvc都要繼承於已有的mvc類;helpers裏是一些函數(方法)集合,用以輔助其餘模塊的方便工做。language是一個語言包,用以支持多語言。

application文件夾用以存儲您的應用程序,CI已經在內部爲您增長了一些子文件,包括models、views、controllers、config、errors、hooks和libraries。其中前三個文件夾是用以建立模型、視圖和控制器的。您的大部分工做都應該是建立屬於本身的MVC,並可在config里加入配置文件,libraries里加入一些對象和方法,用來輔助您的模型和控制器工做。而hooks也是對CI_Hooks的擴展,具體內容見下面的章節。

10. CodeIgniter的工做過程

當有一個http請求時,如http://www.google.com/blog/,首先進入CI的引導文件index.php。接下來咱們看看index.php裏作了哪些事情。

index首先設置了應用程序的文件夾名稱爲application,系統的文件夾名稱爲system,而後作了一系列嚴格的判斷並轉換爲unix風格的服務器絕對文件路徑,具體說來定義了兩個比較重要的常量,APPPATH,應用程序的文件夾路徑,根據分析可知,該路徑能夠和system同級:htdocs/application/,也能夠放到system文件夾裏面,做爲其子文件夾:htdocs/system/application/,但推薦採用第二種方式,這樣顯得比較整齊;BASEPATH,網站文檔的基本文件路徑,寫出來大概是htdoc/system/;到最後,index引導文件引入了codeigniter/codeigniter.php裏。接下來咱們看看codeigniter裏作了什麼事情。

codeigniter.php一上來就引入了三個文件:Common.php,Compat.php和config/constants.php,其中Common裏包含了一些函數,用於載入類庫的load_class,記錄日誌的log_message,和引入錯誤頁面的show_404是幾個重要的函數;Compat主要解決了php4和php5中的函數不兼容問題,而constants則定義了一些讀寫文件權限的常量。

緊接着codeigniter載入了第一個類庫,Benchmark,這個類庫最簡單的一個應用就是計算網頁從開始到編譯結束所花掉的時間,因此您在編譯開始的地方打上一個標記,渲染結束後再打上一個標記,就能夠算出其中花費的時間了。

接着載入了第二個類庫,Hooks,這個類庫和Benchmark同樣都是在system\libraries下,這個類庫的做用是在程序開始編譯以前給您提供一個執行其餘事情的機會,Hooks會您執行其餘任務提供了大約8個機會,具體參見用戶指南。在這裏,它導入了第一個鉤子。

而後分別載入了Config,URI,Router,Output等類庫,接着,檢查是否有cache_override的鉤子,這個鉤子能夠容許您調度本身的函數來替代Output類的_display_cache方法,若是沒有,直接調用Output的_display_cache,檢查是否有緩存內容,若是有,則直接輸出緩存,退出;若是沒有,則接着往下執行。

此後,繼續載入Input,Language,注意此前載入的類庫都是一個引用;而後又一個重要的載入,那就是CI_Base對象的載入,首先會判斷php的版本,若是是php4版本的,則會首先載入Loader,而後載入Base4,由於Base4中CI_Base繼承於CI_Loader,而Base5中,CI_Base與CI_Loader沒有繼承關係。

下一步,也是真正關鍵的一步了,這一步開始載入了一個Controller類,這個是個實例,而不是引用;而後經過Router來解析http地址,得到控制器和方法的名字,接着看application\controllers裏是否存在這樣的控制器和方法,若是沒有,則報錯;若是有,則開始判斷。

小結

先總結這麼多,之後有再補充。

相關文章
相關標籤/搜索