-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Filters system
Filters allow you to execute code before, after or 'around' a controller; modifing a controllers execution path ** without modifying the controller itself **. Filters permit customization of an application to specific deployment requirements using CI hooks.
The filters system is similar to servlet filters in Java or filters in Rails. A filter is a class that is called right before calling the controller method and / or just after returning back from the controller.
Common usage:
- to redirect a user before calling controller action if he is not logged in
- to implement access rights verification (similar to detecting users not logged in)
- to implement cache easily (check if cached version exists and return it before calling controller, store its results after returning from the controller)
- benchmarking (store action execution data into the database or send email to admin if execution seems to be slow)
The filter system is not limited to only one filter per request - you can configure as many filters as you like. A filter can be applied to the request many times.
The filter configuration is stored in system/application/config/filters.php.
Filter classes should be placed in the system/application/filters folder.
The filter system is implemented by 2 classes (hooks/filters/Pipe.php and hooks/filters/Filter.php).
Pipe is the filter manager - it does all the rules matching and runs filters specified in the configuration file.
Filter is the base class for user defined filters. You should extend it to implement your own request interception logic.
Filter name used in config file should be written in lowercase. Examples: auth, xss_remove, force_login
Filter class name - the same like filter name, but first letter uppercase and with _filter suffix appended. Examples: Auth_filter, Xss_remove_filter, Force_login_filter
Filter class file name - the same like filter name with .php suffix. File should be located in system/application/filters/. Examples: auth.php, xss_remove.php, force_login.php
Filter system is based on CI hooks. Initialization code is defined in hooks/filters/init.php. It contains factory function get_pipe() which returns Pipe singleton.
Pipe will first read your system/config/filters.php and look for named filters under the 'system/application/filters' directory.
If slashes are used in the filter name, Pipe will search for the filter in the given directory. For example, if the filter name is 'security/auth', Pipe will search for the 'auth.php' in the 'system/application/filters/security'.
Each filter can define one or both filtering methods - before() and after(). The before() method is executed just before calling controller action (and before scaffolding code). The after() method is executed right after finishing controller action (but before displaying any output)
Note that if you use redirect() in the controller action or in the before() filter method, the after() method will ** NOT ** be called.
The diagram below shows the way the request is executed in CI with the filters system.
Image:Request_processing_with_filters_v2.png
$filter['auth'] = array(
'exclude', // filter is executed for ALL controllers/action EXCLUDING those below
array('login/*', 'about/*'), // filter matching rules
array('login_timeout' => 15) // additional option, for example: login timeout in minutes
);
$filter['cache'] = array(
'include',
array('login/index', 'about/*', 'register/form,rules,privacy'),
array('cache_timeout' => 60, 'cache_storage' => '/tmp/ci_cache')
);
Those lines define two filters - 'auth' and 'cache'.
Filter 'auth' will be applied to each request excluding all requests to the 'login' and 'about' controller. It also defines additional parameter (login_timeout), that will be accessible from the filter code.
Requests passing the first filter will be processed by the 'cache' filter only if they are 'login/index', any of the 'about' controller methods or 'form', 'rules' or 'privacy' methods in the 'register' controller. Here, 2 filter parameters are defined (cache_timeout and cache_storage).
First parameter of the array containing filter definition determines the way the following array is interpreted:
- 'exclude' - filter will be applied to all requests excluding those matching given patterns
- 'include' - filter will be applied only to the requests matching given patterns
Next element is an array containing the list of controller and method patterns.
Last entry is an array containing the list of filter parameters.
You can use following patterns: / - requests to the front page
-
- all requests - use VERY carefully! ctrl/* - requests to the controller 'ctrl' ctrl/meth - requests to the method 'meth' of the controller 'ctrl' ctrl/meth1,meth2 - requests to the methods 'meth1' and 'meth2' of the controller 'ctrl'
The combination of 'exclude' and '*' means that the filter will be never applied.
To apply specified filter twice or more times in one filter chain use the following syntax:
$filter['cache'][] = array('include', array('/'), array('cache_timeout' => 60));
$filter['cache'][] = array('include', array('/news'), array('cache_timeout' => 1));
To enable the filter system you have to :
- enable hooks in system/application/config/config.php (see below)
- unpack File:filters_hook_v2.1b.zip into the top directory of your CI installation (the directory containing /system)
- you should get following files in the system/application/ directory:
- config/filters.php
- config/hooks.php
- filters/perfmon.php
- filters/test.php
- hooks/filters/Filter.php
- hooks/filters/init.php
- hooks/filters/Pipe.php
Now, you are ready to go.
You need to change your application config to enable hooks. Change the appropriate line in the system/application/config/config.php to:
$config['enable_hooks'] = TRUE;
Here is hooks configuration required to enable filters system (system/application/config/hooks.php):
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/*
| -------------------------------------------------------------------------
| Hooks
| -------------------------------------------------------------------------
| This file lets you define "hooks" to extend CI without hacking the core
| files. Please see the user guide for info...
|
*/
$hook['post_controller_constructor'][] = array(
'class' => '',
'function' => 'pre_filter',
'filename' => 'init.php',
'filepath' => 'hooks/filters',
'params' => array()
);
$hook['post_controller'][] = array(
'class' => '',
'function' => 'post_filter',
'filename' => 'init.php',
'filepath' => 'hooks/filters',
'params' => array()
);
?>
Example filter configuration file (system/application/config/filter.php):
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/*
| -------------------------------------------------------------------
| Filters configuration
| -------------------------------------------------------------------
|
| Note: The filters will be applied in the order that they are defined
|
| Example configuration:
|
| $filter['auth'] = array('exclude', array('login/*', 'about/*'));
| $filter['cache'] = array('include', array('login/index', 'about/*', 'register/form,rules,privacy'));
|
*/
$filter['auth'] = array('exclude', array('/', 'login/*'), array());
?>
Example filter (system/application/filters/test.php):
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* Test filter - logs message on filter enter and exit
*/
class Test_filter extends Filter {
function before() {
log_message('debug', 'Before '.$this->controller.' -> '.$this->method);
}
function after() {
log_message('debug', 'After '.$this->controller.' -> '.$this->method);
}
}
?>
I've found a bug on the way filters are applied, discussion is over here.
Temporary fix: http://codeigniter.com/forums/viewthread/46009/P30/#270877
The source code of Pipe, Filter and hook initialization can be found in the ZIP file below.