Codeigniter的一些優(yōu)秀特性總結(jié)
最近準(zhǔn)備接手改進(jìn)一個(gè)別人用Codeigniter寫(xiě)的項(xiàng)目,雖然之前也有用過(guò)CI,但是是完全按著自己的意思寫(xiě)的,沒(méi)按CI的一些套路。用在公眾的項(xiàng)目,最好還是按框架規(guī)范來(lái),所以還是總結(jié)一下,免得以后別人再接手的時(shí)候貽笑大方。
1. 首先是 MVC
如果你還不知道 MVC ,應(yīng)該盡快的學(xué)習(xí),你會(huì)很快的體會(huì)到在 Model 中數(shù)據(jù)訪問(wèn),在 Controller 中進(jìn)行業(yè)務(wù)邏輯,在 Views 中編寫(xiě) HTML 代碼的價(jià)值。如果你之前沒(méi)有使用過(guò)這種模式寫(xiě)過(guò)程序,你也許會(huì)皺起額頭,不過(guò)你應(yīng)該給自己嘗試這樣做的機(jī)會(huì)。
一條實(shí)踐準(zhǔn)則是把更少的東西放進(jìn) Controller ,記住 DRY 準(zhǔn)則:不要重復(fù)造輪子。當(dāng)在超過(guò)一個(gè)地方編寫(xiě)相同的代碼時(shí),應(yīng)該根據(jù)它的類(lèi)型來(lái)嘗試編寫(xiě)一個(gè) library, helper,或 model。比如數(shù)據(jù)庫(kù)連接類(lèi),用得很頻繁,就把它做成 model(系統(tǒng)已提供)。
一旦領(lǐng)悟了 MVC 的精髓,這將會(huì)成為一種習(xí)慣,你會(huì)從 MVC 簡(jiǎn)潔的代碼中受益良多。
一個(gè)原則就是:復(fù)雜的操作都交給Model。Controller更像個(gè)建筑師。 Model是苦工。 View 是粉刷工。Controller 只需要把東西丟進(jìn)Model里就可以了,不需要在意數(shù)據(jù)是否異常,然后返回一個(gè)標(biāo)志位以及相應(yīng)的數(shù)據(jù)。這樣MVC 的 架構(gòu)就體現(xiàn)出來(lái)了。
Model其實(shí)就像一個(gè)電器如:微波爐一樣,使用方法越簡(jiǎn)單越讓人喜歡,(把食物放進(jìn)去 -按啟動(dòng) -ok,飯熟了。)接口少的好處是,Model升級(jí)代碼優(yōu)化的時(shí)候,對(duì)外界的耦合度不高。即使你內(nèi)部寫(xiě)得很爛,接口也很干凈,用起來(lái)也簡(jiǎn)單。
2. Application 和 System 路徑
最好是把 system 和 application 文件夾放在 webroot 以外的地方,如果 index.php 放在 FTP 服務(wù)器的 /public_html/ 路徑下,應(yīng)該嘗試把 System 放在根目錄下 /system ,這樣的話,只能通過(guò) index.php 訪問(wèn)你的PHP文件。
不要忘記在index.php文件中修改 $system_folder 和 $application_folder 的值,$system_folder 的值應(yīng)該是相對(duì)于 index.php 文件,而 $application_folder 的值是相對(duì)于 system 目錄。
3. 錯(cuò)誤報(bào)告和調(diào)試
常常犯的一個(gè)錯(cuò)誤是忘記關(guān)閉 PHP 錯(cuò)誤和數(shù)據(jù)庫(kù)錯(cuò)誤報(bào)告,這樣做是有風(fēng)險(xiǎn)的。在任何一個(gè)公開(kāi)的站點(diǎn),error_reporting 應(yīng)該設(shè)置為0 ,最多只能設(shè)置為 E_ERROR,數(shù)據(jù)庫(kù)設(shè)置 db_debug 應(yīng)該設(shè)置為 false,基于其他安全考慮,設(shè)置不顯示出錯(cuò)信息 ini_set('display_errors', 'Off');
在你編碼和調(diào)試時(shí),應(yīng)該把 error_reporting 設(shè)置為 E_ALL ,并且在把應(yīng)用程序發(fā)布前解決每一個(gè)注意和警告。
一種簡(jiǎn)易的方法是在 application/config/database.php 文件設(shè)置 db_debug 的值為一個(gè)常量 MP_DB_DEBUG,當(dāng)網(wǎng)站在運(yùn)行中,如下設(shè)置:
ini_set('display_errors', 'Off');
error_reporting(0);
define('MP_DB_DEBUG', false);
在編碼和調(diào)試中設(shè)置為:
ini_set('display_errors', 'On');
error_reporting(E_ALL);
define('MP_DB_DEBUG', true);
4. 安全問(wèn)題很重要
在接收任何數(shù)據(jù)到你的程序之前,不管是表單提交的 POST 數(shù)據(jù)、COOKIE 數(shù)據(jù)、URI 數(shù)據(jù)、XML-RPC 數(shù)據(jù)、還是 SERVER 數(shù)組中的數(shù)據(jù),我們都推薦你實(shí)踐下面的三個(gè)步驟:
過(guò)濾不良數(shù)據(jù).
驗(yàn)證數(shù)據(jù)以確保符合正確的類(lèi)型, 長(zhǎng)度, 大小等. (有時(shí)這一步驟也可取代第一步驟)
在提交數(shù)據(jù)到你的數(shù)據(jù)庫(kù)之前將其轉(zhuǎn)換.
關(guān)于SQL注入,XSS,以及 CSRF ,你應(yīng)該先了解它們,再?zèng)Q定是否采用方法來(lái)防止它們??梢詤⒖糃I手冊(cè)上的安全指南 以及 輸入和安全類(lèi)。也許最重要的原則是在把數(shù)據(jù)提交到數(shù)據(jù)庫(kù)或文件系統(tǒng)之前檢查所有用戶(hù)的輸入。
SQL注入。使用 CI 自帶的 Active Record 可以解決這個(gè)問(wèn)題。
XSS (跨站腳本)。通過(guò)設(shè)置 $config['global_xss_filtering'] = TRUE; 開(kāi)啟自動(dòng)過(guò)濾POST和COOKIE中的跨站腳本攻擊,但需要消耗一些資源。也可以在每次處理POST和COOKIE的時(shí)候單獨(dú)使用,把第二個(gè)參數(shù)設(shè)為T(mén)RUE,如 $this->input->post('some_data', TRUE); 表單驗(yàn)證類(lèi)也提供了 XSS 過(guò)濾選項(xiàng),如 $this->form_validation->set_rules('username', 'Username', 'trim|required|xss_clean');
CSRF (跨站請(qǐng)求偽造)。CI 2.0 將內(nèi)置 CSRF 檢查,在 Google 上搜索 "CSRF tokens" 學(xué)習(xí)更多關(guān)于在保護(hù)表單提交和 URL 鏈接的知識(shí),在 Ajax 應(yīng)用方面可以搜索 "double cookie submission" 或 "雙提交 cookie"。
SPAM (垃圾留言和惡意注冊(cè))。通過(guò)保護(hù)你的郵件表單,評(píng)論表單,以及其他各種免費(fèi)用戶(hù)提交的數(shù)據(jù)來(lái)防止垃圾信息,一個(gè)簡(jiǎn)單的方法是只允許一個(gè)IP/User客戶(hù)端在一分鐘之內(nèi)只能提交一次,一個(gè)比較好的方式是使用 Captcha ,CI2中內(nèi)置了一個(gè)CAPTCHA的輔助函數(shù)。
5. 數(shù)據(jù)庫(kù) 和 ORM
CodeIgniter 有一個(gè)自帶的庫(kù) Active Record 能夠幫助你在不使用 SQL 語(yǔ)句的情況下寫(xiě)查詢(xún)語(yǔ)句。這在你不太精通 SQL 語(yǔ)句或不知道怎樣防止SQL注入的情況下是一個(gè)很好的方法。
當(dāng)你需要更強(qiáng)大的工具時(shí),你可以考慮使用 Object Relational Mapper ,就是鼎鼎大名的 ORM 了,遺憾的是,CodeIgniter 沒(méi)有自帶 ORM 庫(kù),不過(guò)也有一些其他很好的選擇。
最流行的或許是 DataMapper OverZealous Edition (DMZ),還可以使用 Doctrine (這里有一個(gè)教程),另一個(gè)選擇 RapidDataMapper 是作者自己的作品。
6. 代碼實(shí)踐
編寫(xiě)簡(jiǎn)潔的代碼,并且理解你的代碼,不要只是復(fù)制粘貼別人的代碼,并且不斷提高編碼能力。手冊(cè)上的開(kāi)發(fā)規(guī)范是一個(gè)能學(xué)習(xí)怎樣更好編寫(xiě)代碼的地方。
1. DRY。不要總是重復(fù)造輪子,把能重用的代碼放在它應(yīng)該在的地方,比如libraries, helpers 或者是 models,而不是controllers,一個(gè)經(jīng)驗(yàn)準(zhǔn)則:當(dāng)你復(fù)制代碼的時(shí)候,也許你已經(jīng)第二次把它放在了錯(cuò)誤的地方。
2. Caching (緩存)。緩存是一個(gè)提高性能的很好的方式,尤其是減少數(shù)據(jù)庫(kù)的訪問(wèn)??梢詤⒖季W(wǎng)頁(yè)緩存和數(shù)據(jù)庫(kù)緩存,或者在論壇上搜索其他的可選方案,比如 MP_Cache 是作者自己的作品。
3. HTTP headers (HTTP頭部)。在客戶(hù)端你能夠通過(guò)單獨(dú)發(fā)送HTTP頭部使瀏覽器緩存頁(yè)面來(lái)提高性能,當(dāng)你使用 AJAX 的時(shí)候你也需要了解它來(lái)禁止瀏覽器緩存。
一個(gè)禁止緩存的例子:
$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");
一個(gè)長(zhǎng)時(shí)間保持緩存的例子(比如 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. 模板渲染不必每次都調(diào)用 header 與 footer
在 MY_Controller 頭部和 __construct 函數(shù)中添加以下內(nèi)容,用于設(shè)定默認(rèn)的模版信息,其中 SITE_NAME 需要自己在 application/config/constants.php 里面自己定義:
class MY_Controller extends CI_Controller {
protected $_data; // 模版?zhèn)髦禂?shù)組
protected $_tplext; // 默認(rèn)模版后綴
protected $_header; // 默認(rèn)頭部模版
protected $_footer; // 默認(rèn)底部模版
public function __construct () {
parent::__construct();
$this->_data['title'] = SITE_NAME;
$this->_tplext = '.php';
$this->_header = 'templates/header';
$this->_footer = 'templates/footer';
// 開(kāi)發(fā)模式下開(kāi)啟性能分析
if (ENVIRONMENT === 'development') {
$this->output->enable_profiler(TRUE);
}
}
}
8. 不必所有的類(lèi)都繼承 CI_Controller
新增的控制器不再繼承 CI_Controller,而改繼承 MY_Controller:
class Index extends MY_Controller {
public function __construct () {
parent::__construct();
}
/**
* 前臺(tái)首頁(yè)
*/
public function index () {
$this->_data['title'] = '首頁(yè)'; // 不指定則使用默認(rèn)標(biāo)題 SITE_NAME
$this->_view('index/index');
}
}
末了,再補(bǔ)充兩個(gè):
9. CodeIgniter的文件結(jié)構(gòu)
cache用以存儲(chǔ)緩存文件,codeigniter文件夾包含了CI的基類(lèi)CI_Base,為了兼容php4和php5,CI_Base有兩個(gè)版本,其中php4版本的CI_Base繼承于CI_Loader。libraries里存放了大部分常用的類(lèi)庫(kù),最主要的三個(gè)類(lèi):Model,View和Cotronller,自己寫(xiě)的任何mvc都要繼承于已有的mvc類(lèi);helpers里是一些函數(shù)(方法)集合,用以輔助其他模塊的方便工作。language是一個(gè)語(yǔ)言包,用以支持多語(yǔ)言。
application文件夾用以存儲(chǔ)您的應(yīng)用程序,CI已經(jīng)在內(nèi)部為您增加了一些子文件,包括models、views、controllers、config、errors、hooks和libraries。其中前三個(gè)文件夾是用以創(chuàng)建模型、視圖和控制器的。您的大部分工作都應(yīng)該是創(chuàng)建屬于自己的MVC,并可在config里加入配置文件,libraries里加入一些對(duì)象和方法,用來(lái)輔助您的模型和控制器工作。而hooks也是對(duì)CI_Hooks的擴(kuò)展,具體內(nèi)容見(jiàn)下面的章節(jié)。
10. CodeIgniter的工作過(guò)程
當(dāng)有一個(gè)http請(qǐng)求時(shí),如http://www.google.com/blog/,首先進(jìn)入CI的引導(dǎo)文件index.php。接下來(lái)我們看看index.php里做了哪些事情。
index首先設(shè)置了應(yīng)用程序的文件夾名稱(chēng)為application,系統(tǒng)的文件夾名稱(chēng)為system,然后做了一系列嚴(yán)格的判斷并轉(zhuǎn)換為unix風(fēng)格的服務(wù)器絕對(duì)文件路徑,具體說(shuō)來(lái)定義了兩個(gè)比較重要的常量,APPPATH,應(yīng)用程序的文件夾路徑,根據(jù)分析可知,該路徑可以和system同級(jí):htdocs/application/,也可以放到system文件夾里面,作為其子文件夾:htdocs/system/application/,但推薦采用第二種方式,這樣顯得比較整齊;BASEPATH,網(wǎng)站文檔的基本文件路徑,寫(xiě)出來(lái)大概是htdoc/system/;到最后,index引導(dǎo)文件引入了codeigniter/codeigniter.php里。接下來(lái)我們看看codeigniter里做了什么事情。
codeigniter.php一上來(lái)就引入了三個(gè)文件:Common.php,Compat.php和config/constants.php,其中Common里包含了一些函數(shù),用于載入類(lèi)庫(kù)的load_class,記錄日志的log_message,和引入錯(cuò)誤頁(yè)面的show_404是幾個(gè)重要的函數(shù);Compat主要解決了php4和php5中的函數(shù)不兼容問(wèn)題,而constants則定義了一些讀寫(xiě)文件權(quán)限的常量。
緊接著codeigniter載入了第一個(gè)類(lèi)庫(kù),Benchmark,這個(gè)類(lèi)庫(kù)最簡(jiǎn)單的一個(gè)應(yīng)用就是計(jì)算網(wǎng)頁(yè)從開(kāi)始到編譯結(jié)束所花掉的時(shí)間,所以您在編譯開(kāi)始的地方打上一個(gè)標(biāo)記,渲染結(jié)束后再打上一個(gè)標(biāo)記,就可以算出其中花費(fèi)的時(shí)間了。
接著載入了第二個(gè)類(lèi)庫(kù),Hooks,這個(gè)類(lèi)庫(kù)和Benchmark一樣都是在system\libraries下,這個(gè)類(lèi)庫(kù)的作用是在程序開(kāi)始編譯之前給您提供一個(gè)執(zhí)行其他事情的機(jī)會(huì),Hooks會(huì)您執(zhí)行其他任務(wù)提供了大約8個(gè)機(jī)會(huì),具體參見(jiàn)用戶(hù)指南。在這里,它導(dǎo)入了第一個(gè)鉤子。
然后分別載入了Config,URI,Router,Output等類(lèi)庫(kù),接著,檢查是否有cache_override的鉤子,這個(gè)鉤子可以允許您調(diào)度自己的函數(shù)來(lái)替代Output類(lèi)的_display_cache方法,如果沒(méi)有,直接調(diào)用Output的_display_cache,檢查是否有緩存內(nèi)容,如果有,則直接輸出緩存,退出;如果沒(méi)有,則接著往下執(zhí)行。
此后,繼續(xù)載入Input,Language,注意此前載入的類(lèi)庫(kù)都是一個(gè)引用;然后又一個(gè)重要的載入,那就是CI_Base對(duì)象的載入,首先會(huì)判斷php的版本,如果是php4版本的,則會(huì)首先載入Loader,然后載入Base4,因?yàn)锽ase4中CI_Base繼承于CI_Loader,而B(niǎo)ase5中,CI_Base與CI_Loader沒(méi)有繼承關(guān)系。
下一步,也是真正關(guān)鍵的一步了,這一步開(kāi)始載入了一個(gè)Controller類(lèi),這個(gè)是個(gè)實(shí)例,而不是引用;然后通過(guò)Router來(lái)解析http地址,獲得控制器和方法的名字,接著看application\controllers里是否存在這樣的控制器和方法,如果沒(méi)有,則報(bào)錯(cuò);如果有,則開(kāi)始判斷。
小結(jié)
先總結(jié)這么多,以后有再補(bǔ)充。希望大家能投喜歡。
相關(guān)文章
使用php重新實(shí)現(xiàn)PHP腳本引擎內(nèi)置函數(shù)
使用php重新實(shí)現(xiàn)PHP腳本引擎內(nèi)置函數(shù)...2007-03-03ThinkPHP入口文件設(shè)置及相關(guān)注意事項(xiàng)分析
這篇文章主要介紹了ThinkPHP入口文件設(shè)置及相關(guān)注意事項(xiàng),以注釋的形式詳細(xì)分析了入口文件設(shè)置時(shí)相關(guān)設(shè)置項(xiàng)的含義與設(shè)置技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-12-12關(guān)于擴(kuò)展 Laravel 默認(rèn) Session 中間件導(dǎo)致的 Session 寫(xiě)入失效問(wèn)題分析
這篇文章主要介紹了關(guān)于擴(kuò)展 Laravel 默認(rèn) Session 中間件導(dǎo)致的 Session 寫(xiě)入失效問(wèn)題分析的相關(guān)資料,需要的朋友可以參考下2016-01-01codeigniter教程之上傳視頻并使用ffmpeg轉(zhuǎn)flv示例
這篇文章主要介紹了codeigniter上傳視頻并使用ffmpeg轉(zhuǎn)成flv的示例,需要的朋友可以參考下2014-02-02Swoole?webSocket消息服務(wù)系統(tǒng)壓力測(cè)試解析
這篇文章主要為大家介紹了Swoole?webSocket消息服務(wù)系統(tǒng)壓力測(cè)試解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03DWZ+ThinkPHP開(kāi)發(fā)時(shí)遇到的問(wèn)題分析
這篇文章主要介紹了DWZ+ThinkPHP開(kāi)發(fā)時(shí)遇到的問(wèn)題,結(jié)合實(shí)例形式分析了DWZ+ThinkPHP在ajax調(diào)用中出現(xiàn)錯(cuò)誤問(wèn)題的解決方法,需要的朋友可以參考下2016-12-12PHP長(zhǎng)網(wǎng)址與短網(wǎng)址的實(shí)現(xiàn)方法
這篇文章主要介紹了PHP長(zhǎng)網(wǎng)址與短網(wǎng)址的實(shí)現(xiàn)方法,需要的朋友可以參考下2017-10-10