1 
實戰 
CodeIgniter PHP Framework 
Bo-Yi Wu (appleboy) 
2014.09.26 
成功大學電算中心
2 
關於我 
Bo-Yi Wu (appleboy) 
– Blog: http://blog.wu-boy.com/ 
– Github: https://github.com/appleboy 
– CodeIgniter站長 
– Laravel站長
3 
為什麼要使用Framework 
Why should I use a framework ?
4 
不用重新造輪子 
Not having to reinvent the wheel
5 
容易升級與維護 
upgradability and maintenance
6 
既定開發流程 
Develop Flow
7 
網站安全性 
Web Security
8 
網站安全性 
• 管理介面 URL 
● 目錄 (Index of) 
● 錯誤訊息 
● 暫存測試資訊 
● 版本控管 
● SQL Injection
9 
Joomla管理介面
10 
早期phpMyAdmin有漏洞風險
11 
常用管理介面路徑 
● /admin/ 
● /phpMyAdmin/ 
● /adminLogin/ 
● /manage/ 
● /management/ 
● /root/ 
● /wp-admin/ 
政府機關、學校機構、電信業者
12 
如何防禦 
● 限制存取IP(Apache, Nginx) 
● 隱藏管理介面(複雜目錄名稱) 
● 增加後台防禦(Captcha …)
13 
網站安全性 
● 管理介面 URL 
• 目錄 (Index of) 
● 錯誤訊息 
● 暫存測試資訊 
● 版本控管 
● SQL Injection
14
15 
Index of 
● 網路目錄結構曝光 
● 存取敏感檔案 
– .bak 
– config.php.bak 
– .svn, .git, 
– database.yml
16 
如何防禦 
關閉Index功能(Apache) 
<Directory /> 
Options -Indexes 
</Directory>
17 
網站安全性 
● 管理介面 URL 
● 目錄 (Index of) 
• 錯誤訊息 
● 暫存測試資訊 
● 版本控管 
● SQL Injection
SQL 錯誤訊息18
19 
如何防禦 
● 關閉錯誤顯示 
– php.ini 
– display_errors = off 
● 使用 Framework 都可以直接設定在專案裡
20 
網站安全性 
● 管理介面 URL 
● 目錄 (Index of) 
● 錯誤訊息 
• 暫存測試資訊 
● 版本控管 
● SQL Injection
21 
暫存測試資訊 
● 開發者求方便使用檔名備份 
– .bak, xxx.php2 
● 編輯器自動備份 
– index.php~, index.php.swp 
● 看系統資訊 
– phpinfo.php
22 
不要在Production機器上 
改程式碼 
set vim :set nobackup
23 
如何防禦 
● 不要在正式產品環境中進行開發 
● 關閉編輯器自動備份 
● 伺服器過濾檔案下載 
– Nginx 
# Prevent clients from accessing to backup/config/source files 
location ~* (?:.(?:bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)|~)$ { 
deny all; 
}
24 
網站安全性 
● 管理介面 URL 
● 目錄 (Index of) 
● 錯誤訊息 
● 暫存測試資訊 
• 版本控管 
● SQL Injection
25 
版本控管 
http://xxxx.com/.git/config 
http://xxxx.com/.git 
http://xxxx.com/.svn
26
27 
如何防禦 
● 開發環境跟正式環境切開 
● 禁止版本控制資料夾存取 
● 導入Deploy流程(Continuous Integration)
28 
網站安全性 
● 管理介面 URL 
● 目錄 (Index of) 
● 錯誤訊息 
● 暫存測試資訊 
● 版本控管 
• SQL Injection
29 
SQL Injection 
SELECT id FROM users WHERE email = 
‘$email‘ and password = ‘$password’; 
SELECT id FROM users WHERE email = 
‘$email‘ and password = ‘anything' OR ‘1’ 
= ‘1’;
30 
如何防禦 
● 請不要相信使用者任何輸入字串 
● 正規比對格式 
– preg_match(‘/^(w)+$/’, $string); 
– 使用framework提供escape函式 
● 型態轉換Typecasting
31 
型態轉換Typecasting 
$var = (array) $var; 
$var = (binary) $var; 
$var = (bool) $var; 
$var = (boolean) $var; 
$var = (double) $var; 
$var = (float) $var; 
$var = (int) $var; 
$var = (integer) $var; 
$var = (object) $var; 
$var = (real) $var; 
$var = (string) $var;
32 
選擇 
PHP Framework
33
34
35 
為什麼要選擇 CodeIgniter 
● 安裝容易 
● 輕易上手 
● 繁中文件
36 
安裝容易 
wget + unzip = done
37 
輕易上手 
只要會一點點物件導向即可
38 
繁中文件 
目前只有CodeIgniter、Laravel有繁中文件 
http://codeigniter.org.tw/user_guide/ 
http://bit.ly/ci-userguide
39 
CodeIgniter3.0發展 
目前最新為2.2.0版本
40 
EllisLab Seeking New Owner for CodeIgniter 
http://bit.ly/ci-seek-new-owner
41
42 
3.0版本有超過 
100個bug fixed 
100個feature commit 
http://bit.ly/ci-changelog
43 
CodeIgniter 
架構
44 
CodeIgniter架構 
● application開發MVC程式碼 
● system系統程式碼 
● user_guide線上文件 
● index.php主檔案
45 
index.php 
● $application_folder = 'application'; 
● $system_path = 'system';
更動Web架構 
46
47 
CodeIgniter架構 
● application 
● system 
● public/index.php 
● public/robots.txt 
● Public/.htaccess
48 
index.php 
● $application_folder = ‘../application'; 
● $system_path = ‘../system';
49 
使用者無法存取 
index.php以外的檔案 
Apache: DocumentRoot /xxx/public 
Nginx: root /xxx/public
50 
隱藏URL index.php字串
51 
Apache 
RewriteEngine on 
RewriteBase / 
RewriteCond $1 !^(index.php|robots.txt|$) 
RewriteRule ^(.*)$ index.php/$1 [L,QSA]
52 
Nginx 
location / { 
try_files $uri $uri/ /index.php?$query_string; 
}
使用此架構好處 
53 
● 避免.git 曝露 
● 根目錄可以放其他設定檔 
– .editorconfig 
– .gitignore 
– gulpfile.coffee 
– bower.js 
– package.json
54 
作業一 
● 建立一個virtual host: ci.localhost 
● 安裝codeigniter 2.2.0 
● 移除url的index.php字串 
– http://ci.localhost/welcome
55 
CodeIgniter核心架構
56 
核心架構 
● core 
– Controller, Model, Router, Loader, Input … 
● database 
– MySQL, ODBC, MSSQL, Sqlite … 
● helpers 
– email, url, text, number, language … 
● language 
– zh-tw, zh-cn, english … 
● libraries 
– Form, Image, Session, Email, Pagination
57 
核心函式不夠用 
擴充核心函式庫
58 
擴充核心函式庫 
● core 
– MY_Model, MY_Controller, MY_Input …. 
● libraries 
– MY_Email, MY_Upload …. 
● helpers 
– MY_array_helper ….
59 
$this->load->library('email'); 
系統讀取流程
60 
讀取優先順序 
● application/libraries/MY_Email.php 
● application/libraries/Email.php 
● system/libraries/Email.php 
● application/libraries/MY_email.php 
● application/libraries/email.php 
● system/libraries/email.php
61 
擴充Native Session 
支援原生$_SESSION 
http://bit.ly/ci-native-session
62 
3.0 版本已經支援 
Native Session
63 
安裝 
$ cp config/session.php application/config/ 
$ cp libraries/Session.php application/libraries/
64 
多個Application請設定config 
$config['sess_namespace'] = '';
65 
多國語系i18n 
http://bit.ly/ci-i18n
擴充Core Language 
$ cp application/config/language.php app/application/config/ 
$ cp application/core/MY_Lang.php app/application/core/ 
66
67 
設定 
$config['language_field'] = 'lang'; 
$config['language_key'] = 'en-us'; 
$config['language_list'] = array( 
'en-us' => 'english', 
'zh-tw' => 'zh-tw‘ 
);
68 
使用方式 
$this->load->helper('language'); 
$this->lang->load('welcome'); 
echo lang('welcome.title');
69 
作業二 
● 將Welcome controller加入 
– Native Session 
– 多國語言
70 
PHP ORM Model 
CodeIgniter沒有ORM 
只有ActiveRecord
Codeigniter Base Model 
71 
http://bit.ly/ci-base-model
72 
簡介 
class Topic_model extends MY_Model { } 
$this->load->model('topic_model', 'topic'); 
$this->topic->get_all(); 
$this->topic->get(1); 
$this->topic->get_by('title', 'Pigs CAN Fly!'); 
$this->topic->get_many_by('status', 'open'); 
$this->topic->insert(array( 
'status' => 'open', 
'title' => "I'm too sexy for my shirt" 
)); 
$this->topic->update(1, array( 'status' => 'closed' )); 
$this->topic->delete(1);
擴充核心Model 
下載MY_Model.php 放到 
73 
application/core
74 
命名原則 
class Topic_model extends MY_Model { } 
class Topic_m extends MY_Model { }
75 
指定資料表 
class Topic_model extends MY_Model 
{ 
public $_table = ‘topics’; 
}
76 
指定Primary Key 
// 預設為id 
class Topic_model extends MY_Model 
{ 
public $primary_key = ‘topic_id'; 
}
77 
Callbacks 
● $before_create 
● $after_create 
● $before_update 
● $after_update 
● $before_get 
● $after_get 
● $before_delete 
● $after_delete
78 
範例 
class Topic_model extends MY_Model 
{ 
public $before_create = array( 'timestamps' ); 
protected function timestamps($topic) 
{ 
$topic['created_at'] = date('Y-m-d H:i:s'); 
$topic['updated_at'] = date('Y-m-d H:i:s'); 
return $topic; 
} 
}
79 
參數處理 
public $before_create = array('data_process(name)'); 
public $before_update = array('data_process(date)'); 
protected function data_process($row) 
{ 
$row[$this->callback_parameters[0]] = $this- 
>_process($row[$this->callback_parameters[0]]); 
return $row; 
}
80 
驗證Validation 
class User_model extends MY_Model 
{ 
public $validate = array( 
array( 'field' => 'email', 
'label' => 'email', 
'rules' => 'required|valid_email|is_unique[users.email]' ), 
array( 'field' => 'password', 
'label' => 'password', 
'rules' => 'required' ), 
array( 'field' => 'password_confirmation', 
'label' => 'confirm password', 
'rules' => 'required|matches[password]' ), 
); 
}
81 
新增修改資料 
都會觸發驗證
82 
忽略資料驗證 
$this->user_model->skip_validation(); 
$this->user_model->insert(['email' => 'blah'], true);
83 
保護欄位 
class Topic_model extends MY_Model 
{ 
public $protected_attributes = ['id']; 
}
84 
$this->topic_model->insert(array( 
'id' => 2, 
'title' => 'A new topic' 
)); 
// INSERT INTO topics (title) VALUES ('A 
new topic')
85 
Object vs. Array 
class Topic_model extends MY_Model 
{ 
protected $return_type = 'array'; 
}
$this->topic_model 
->as_array() 
->get(1); 
$this->topic_model 
->as_object() 
->get_by('column', 'value'); 
86
87 
Soft Delete 
class Topic_model extends MY_Model 
{ 
protected $soft_delete = true; 
protected $soft_delete_key = 'deleted'; 
}
88 
$this->topic_model->get(1); 
// SELECT * FROM topics WHERE id = 1 and 
deleted = 0 
$this->topic_model->only_deleted()->get(1); 
// SELECT * FROM topics WHERE id = 1 AND 
deleted = 1 
$this->topic_model->with_deleted()->get(1); 
// SELECT * FROM topics WHERE id = 1
89 
內建Observers 
class Topic_model extends MY_Model 
{ 
public $before_create = ['created_at', 
'updated_at']; 
public $before_update = ['updated_at']; 
}
90 
資料庫連線 
class Topic_model extends MY_Model 
{ 
public $_db_group = 'group_name'; 
}
91 
作業三 
● 實做最新消息系統 
– 建立 topics 資料表 
● id, title, description, is_feature, created_at, 
updated_at 
● 實做CRUD (新增, 刪除, 修改, 查詢) 
● 實做置頂功能
92 
Relationships 
class Topic_model extends MY_Model 
{ 
public $belongs_to = ['user']; 
public $has_many = ['comments']; 
}
93 
新增相關 Model 
● class User_model extends MY_Model { } 
● class Comment_model extends MY_Model { }
94 
指定相關資料表 
class Topic_model extends MY_Model 
{ 
public $belongs_to = ['user' => ['model' => 
'user_m']]; 
public $has_many = ['comments' => ['model' 
=> 'model_comments']]; 
}
95 
讀取資料 
$topic = $this->topic_model 
->with(user') 
->with('comments') 
->get(1); 
echo $topic->user->name; 
foreach ($topic->comments as $comment) { 
echo $message; 
}
96 
SQL 表示 
● SELECT * FROM users WHERE id = $topic- 
>user_id 
● SELECT * FROM comments WHERE 
topic_id = $topic->id
97 
更換Primary Key 
class Topic_model extends MY_Model 
{ 
public $belongs_to = ['user' => ['primary_key' => 'post_user_id']]; 
public $has_many = ['comments' => ['primary_key' => 'parent_topic_id']]; 
}
98 
作業四 
● 實做最新消息系統 
– 建立 Users 資料表 
● id, username 
– 增加欄位在Topic資料表 
● user_id 
– 顯示使用者帳號在Topic列表
99 
會員模組 
http://bit.ly/ci-ion-auth
100 
功能列表 
● 會員登入 (支援帳號或電子郵件) 
● 會員登出 
● 會員註冊 
● 會員更新 
● 忘記密碼 
● 電子郵件認證 
● 會員群組權限 
● 驗證登入錯誤次數
101 
安裝方式 
複製相關檔案到對應目錄
102 
設定檔資料表 
$config['tables']['users'] = 'users'; 
$config['tables']['groups'] = 'groups'; 
$config['tables']['users_groups'] = 'users_groups'; 
$config['tables']['login_attempts'] = 'login_attempts'; 
$config['join']['users'] = 'user_id'; 
$config['join']['groups'] = 'group_id';
103 
會員認證設定 
$config['admin_email'] = "admin@example.com"; 
$config['default_group'] = 'members'; 
$config['admin_group'] = 'admin'; 
$config['identity'] = 'email'; 
$config['min_password_length'] = 8; 
$config['max_password_length'] = 20; 
$config['email_activation'] = FALSE; 
$config['manual_activation'] = FALSE; 
$config['remember_users'] = TRUE; 
$config['user_expire'] = 86500; 
$config['user_extend_on_login'] = FALSE; 
$config['track_login_attempts'] = FALSE; 
$config['track_login_ip_address'] = TRUE; 
$config['maximum_login_attempts'] = 3; 
$config['lockout_time'] = 600; 
$config['forgot_password_expiration'] = 0;
104 
電子郵件表單 
$config['email_templates'] = 'auth/email/'; 
$config['email_activate'] = 'activate.tpl.php'; 
$config['email_forgot_password'] = 
'forgot_password.tpl.php'; 
$config['email_forgot_password_complete'] = 
'new_password.tpl.php';
105 
自訂錯誤訊息 
● $config['message_start_delimiter'] = '<p>'; 
● $config['message_end_delimiter'] = '</p>'; 
● $config['error_start_delimiter'] = '<p>'; 
● $config['error_end_delimiter'] = '</p>';
Template模組 
106 
A Lightweight Codeigniter Template Libray 
http://bit.ly/ci-template
107 
安裝方式 
$ php tools/spark install -v1.0.4 codeigniter-template
108 
預設模板 
$config['template_layout'] = 'template/layout';
新增CSS連結 
$this->template->add_css("/min.css", "screen"); 
// <link href="/min.css" rel="stylesheet" type="text/css" media="screen" /> 
109
新增JavaScript連結 
$this->template->add_js("/index.js", true); 
// <script src="/index.js" type="text/javascript"></script> 
110
111 
動態新增Meta Tag 
$this->template->add_meta_tag("og:title", "Test Title", 
'property'); 
//output <meta property="og:title" content="Test Title" /> 
$this->template->add_meta_tag("keywords", "some 
keywords"); 
// output <meta name="keywords" content="some 
keywords" />
112 
動態標題 
$this->template->add_title_segment('test'); 
// output <title>test | your site title</title>
113 
動態設定值 
$this->template->set("is_login", false); 
or 
$this->template->is_login = false;
114 
輸出畫面 
$this->template->render('index', $data);
115 
作業五 
● 整合會員到最新消息系統 
– 登入後才可以修改及發表 
– 管理者才可以刪除文章 
● 整合Template模組 
– 加入jQuery元件http://jquery.com/ 
– 加入Bootstraphttp://getbootstrap.com/
116 
CodeIgniter RESTful API Design
117 
RESTful 
Representational State Transfer 
各大網站Google Amazone Yahoo都提供 
RESTful API
118 
HTTP Methods 
● GET => 讀取 
● PUT => 更新 
● POST => 新增 
● DELETE => 刪除
119 
格式Format 
JSON, XML 
你不可不知的 JSON 基本介紹
120 
JSON usage in JavaScript 
var output = { 
‘title’: ‘I am appleboy.’, 
‘desctiption’: ‘CodeIgniter in Action.’ 
};
121 
JSON usage in PHP 
json_encode 
* http://bit.ly/php-json-encode 
json_decode 
* http://bit.ly/php-json-decode
122 
傳統 
● /topic/create 
● /topic/show/1 
● /topic/update/1 
● /topic/destroy/1
123 
傳統 
● /topic/create 
● /topic/show/1 
● /topic/update/1 
● /topic/destroy/1 
現在 
● POST /topic 
● GET /topic/1 
● PUT /topic/1 
● DELETE /topic/1
CodeIgniter RESTful Server 
124 
http://bit.ly/ci-reset-server
安裝方式 
125 
● application/libraries/Format.php 
● application/libraries/REST_Controller.php 
● application/config/rest.php
範例 
126 
class Topic extends REST_Controller 
{ 
public function index_get() 
{ 
// Display all topics 
} 
public function index_post() 
{ 
// Create a new topic 
} 
}
參數 
127 
● $this->get('blah'); // GET 
● $this->post('blah'); // POST 
● $this->put('blah'); // PUT 
● $this->delete('blah'); // DELETE
Response回覆 
128 
public function index_delete($id) 
{ 
$this->response([ 
'returned from delete:' => $id, 
]); 
}
Response回覆 
129 
● // Send an HTTP 201 Created 
● $this->response($book, 201); 
● // HTTP 404 Not Found 
● $this->response([]);
支援API Keys 
● $config['rest_enable_keys'] = TRUE; 
130
建立API KEY資料表 
CREATE TABLE `keys` ( 
`id` int(11) NOT NULL AUTO_INCREMENT, 
`key` varchar(40) NOT NULL, 
`level` int(2) NOT NULL, 
`ignore_limits` tinyint(1) NOT NULL DEFAULT '0', 
`date_created` int(11) NOT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
131
測試API KEY 
$ curl -X POST -H "X-API-KEY: 
some_key_here" http://example.com/topics 
132
133 
作業六 
● 實作Topic RESTful API 撰寫 
– /api/topic GET新聞列表 
– /api/topic/{id} GET單一新聞列表 
– /api/topic/{id} PUT更新新聞 
– /api/topic POST建立新聞 
– /api/topic/{id} DELETE刪除新聞 
● 用jQuery AJAX搭配後端CRUD功能 
● 整合Facebook登入API
作業程式碼 
134 
https://github.com/appleboy/CodeIgniter-App
參考文獻 
135 
● CodeIgniter 台灣官網 
– http://codeigniter.org.tw/ 
● 被遺忘的資訊洩漏-重點回顧 
– http://goo.gl/UO7Akz
136 
謝謝大家參與 
謝謝主辦單位

You must know about CodeIgniter Popular Library