Added KH 3.3.0
This commit is contained in:
72
includes/kohana/system/guide/kohana/autoloading.md
Normal file
72
includes/kohana/system/guide/kohana/autoloading.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# Loading Classes
|
||||
|
||||
Kohana supports the [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) autoloading specification as of version 3.3. This allows you to take advantage of PHP [autoloading](http://php.net/manual/language.oop5.autoload.php), removing the need to call [include](http://php.net/include) or [require](http://php.net/require) before using a class. When you use a class Kohana will find and include the class file for you. For instance, when you want to use the [Cookie::set] method, you simply call:
|
||||
|
||||
Cookie::set('mycookie', 'any string value');
|
||||
|
||||
Or to load an [Encrypt] instance, just call [Encrypt::instance]:
|
||||
|
||||
$encrypt = Encrypt::instance();
|
||||
|
||||
Classes are loaded via the [Kohana::auto_load] method, which makes a simple conversion from class name to file name:
|
||||
|
||||
1. Classes are placed in the `classes/` directory of the [filesystem](files)
|
||||
2. Any underscore characters in the class name are converted to slashes
|
||||
2. The filename must match the case of the class
|
||||
|
||||
When calling a class that has not been loaded (eg: `Session_Cookie`), Kohana will search the filesystem using [Kohana::find_file] for a file named `classes/Session/Cookie.php`.
|
||||
|
||||
If your classes do not follow this convention, they cannot be autoloaded by Kohana. You will have to manually included your files, or add your own [autoload function.](http://us3.php.net/manual/en/function.spl-autoload-register.php)
|
||||
|
||||
## Custom Autoloaders
|
||||
|
||||
Kohana's default autoloader is enabled in `application/bootstrap.php` using [spl_autoload_register](http://php.net/spl_autoload_register):
|
||||
|
||||
spl_autoload_register(array('Kohana', 'auto_load'));
|
||||
|
||||
This allows [Kohana::auto_load] to attempt to find and include any class that does not yet exist when the class is first used as long as it follows the PSR-0 specification. If you wish to support the previous Kohana filename convention (using lowercase filesnames), an additional autoloader is provided by Kohana:
|
||||
|
||||
spl_autoload_register(array('Kohana', 'auto_load_lowercase'));
|
||||
|
||||
|
||||
### Example: Zend
|
||||
|
||||
You can easily gain access to other libraries if they include an autoloader. For example, here is how to enable Zend's autoloader so you can use Zend libraries in your Kohana application.
|
||||
|
||||
#### Download and install the Zend Framework files
|
||||
|
||||
- [Download the latest Zend Framework files](http://framework.zend.com/download/latest).
|
||||
- Create a `vendor` directory at `application/vendor`. This keeps third party software separate from your application classes.
|
||||
- Move the decompressed Zend folder containing Zend Framework to `application/vendor/Zend`.
|
||||
|
||||
|
||||
#### Include Zend's Autoloader in your bootstrap
|
||||
|
||||
Somewhere in `application/bootstrap.php`, copy the following code:
|
||||
|
||||
/**
|
||||
* Enable Zend Framework autoloading
|
||||
*/
|
||||
if ($path = Kohana::find_file('vendor', 'Zend/Loader'))
|
||||
{
|
||||
ini_set('include_path',
|
||||
ini_get('include_path').PATH_SEPARATOR.dirname(dirname($path)));
|
||||
|
||||
require_once 'Zend/Loader/Autoloader.php';
|
||||
Zend_Loader_Autoloader::getInstance();
|
||||
}
|
||||
|
||||
#### Usage example
|
||||
|
||||
You can now autoload any Zend Framework classes from inside your Kohana application.
|
||||
|
||||
if ($validate($this->request->post()))
|
||||
{
|
||||
$mailer = new Zend_Mail;
|
||||
|
||||
$mailer->setBodyHtml($view)
|
||||
->setFrom(Kohana::$config->load('site')->email_from)
|
||||
->addTo($email)
|
||||
->setSubject($message)
|
||||
->send();
|
||||
}
|
111
includes/kohana/system/guide/kohana/bootstrap.md
Normal file
111
includes/kohana/system/guide/kohana/bootstrap.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# Bootstrap
|
||||
|
||||
The bootstrap is located at `application/bootstrap.php`. It is responsible for setting up the Kohana environment and executing the main response. It is included by `index.php` (see [Request flow](flow))
|
||||
|
||||
[!!] The bootstrap is responsible for the flow of your application. In previous versions of Kohana the bootstrap was in `system` and was somewhat of an unseen, uneditible force. In Kohana 3 the bootstrap takes on a much more integral and versatile role. Do not be afraid to edit and change your bootstrap however you see fit.
|
||||
|
||||
## Environment setup
|
||||
|
||||
The bootstrap first sets the timezone and locale, and then adds Kohana's autoloader so the [cascading filesystem](files) works. You could add any other settings that all your application needed here.
|
||||
|
||||
~~~
|
||||
// Sample excerpt from bootstrap.php with comments trimmed down
|
||||
|
||||
// Set the default time zone.
|
||||
date_default_timezone_set('America/Chicago');
|
||||
|
||||
// Set the default locale.
|
||||
setlocale(LC_ALL, 'en_US.utf-8');
|
||||
|
||||
// Enable the Kohana auto-loader.
|
||||
spl_autoload_register(array('Kohana', 'auto_load'));
|
||||
|
||||
// Enable the Kohana auto-loader for unserialization.
|
||||
ini_set('unserialize_callback_func', 'spl_autoload_call');
|
||||
~~~
|
||||
|
||||
## Initialization and Configuration
|
||||
|
||||
Kohana is then initialized by calling [Kohana::init], and the log and [config](files/config) reader/writers are enabled.
|
||||
|
||||
~~~
|
||||
// Sample excerpt from bootstrap.php with comments trimmed down
|
||||
|
||||
Kohana::init(array('
|
||||
base_url' => '/kohana/',
|
||||
index_file => false,
|
||||
));
|
||||
|
||||
// Attach the file writer to logging. Multiple writers are supported.
|
||||
Kohana::$log->attach(new Kohana_Log_File(APPPATH.'logs'));
|
||||
|
||||
// Attach a file reader to config. Multiple readers are supported.
|
||||
Kohana::$config->attach(new Kohana_Config_File);
|
||||
~~~
|
||||
|
||||
You can add conditional statements to make the bootstrap have different values based on certain settings. For example, detect whether we are live by checking `$_SERVER['HTTP_HOST']` and set caching, profiling, etc. accordingly. This is just an example, there are many different ways to accomplish the same thing.
|
||||
|
||||
~~~
|
||||
// Excerpt from http://github.com/isaiahdw/kohanaphp.com/blob/f2afe8e28b/application/bootstrap.php
|
||||
... [trimmed]
|
||||
|
||||
/**
|
||||
* Set the environment status by the domain.
|
||||
*/
|
||||
if (strpos($_SERVER['HTTP_HOST'], 'kohanaphp.com') !== FALSE)
|
||||
{
|
||||
// We are live!
|
||||
Kohana::$environment = Kohana::PRODUCTION;
|
||||
|
||||
// Turn off notices and strict errors
|
||||
error_reporting(E_ALL ^ E_NOTICE ^ E_STRICT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Kohana, setting the default options.
|
||||
... [trimmed]
|
||||
*/
|
||||
Kohana::init(array(
|
||||
'base_url' => Kohana::$environment === Kohana::PRODUCTION ? '/' : '/kohanaphp.com/',
|
||||
'caching' => Kohana::$environment === Kohana::PRODUCTION,
|
||||
'profile' => Kohana::$environment !== Kohana::PRODUCTION,
|
||||
'index_file' => FALSE,
|
||||
));
|
||||
|
||||
... [trimmed]
|
||||
|
||||
~~~
|
||||
|
||||
[!!] Note: The default bootstrap will set `Kohana::$environment = $_ENV['KOHANA_ENV']` if set. Docs on how to supply this variable are available in your web server's documentation (e.g. [Apache](http://httpd.apache.org/docs/1.3/mod/mod_env.html#setenv), [Lighttpd](http://redmine.lighttpd.net/wiki/1/Docs:ModSetEnv#Options)). This is considered better practice than many alternative methods to set `Kohana::$enviroment`, as you can change the setting per server, without having to rely on config options or hostnames.
|
||||
|
||||
## Modules
|
||||
|
||||
**Read the [Modules](modules) page for a more detailed description.**
|
||||
|
||||
[Modules](modules) are then loaded using [Kohana::modules()]. Including modules is optional.
|
||||
|
||||
Each key in the array should be the name of the module, and the value is the path to the module, either relative or absolute.
|
||||
~~~
|
||||
// Example excerpt from bootstrap.php
|
||||
|
||||
Kohana::modules(array(
|
||||
'database' => MODPATH.'database',
|
||||
'orm' => MODPATH.'orm',
|
||||
'userguide' => MODPATH.'userguide',
|
||||
));
|
||||
~~~
|
||||
|
||||
## Routes
|
||||
|
||||
**Read the [Routing](routing) page for a more detailed description and more examples.**
|
||||
|
||||
[Routes](routing) are then defined via [Route::set()].
|
||||
|
||||
~~~
|
||||
// The default route that comes with Kohana 3
|
||||
Route::set('default', '(<controller>(/<action>(/<id>)))')
|
||||
->defaults(array(
|
||||
'controller' => 'Welcome',
|
||||
'action' => 'index',
|
||||
));
|
||||
~~~
|
193
includes/kohana/system/guide/kohana/config.md
Normal file
193
includes/kohana/system/guide/kohana/config.md
Normal file
@@ -0,0 +1,193 @@
|
||||
# Configuration
|
||||
|
||||
By default Kohana is setup to load configuration values from [config files](files/config) in the
|
||||
cascading filesystem. However, it is very easy to adapt it to load config values in other
|
||||
locations/formats.
|
||||
|
||||
## Sources
|
||||
|
||||
The system is designed around the concept of **Config Sources**, which loosely means a method of
|
||||
storing configuration values.
|
||||
|
||||
To read config from a source you need a **Config Reader**. Similarly, to write config to a source
|
||||
you need a **Config Writer**.
|
||||
|
||||
Implementing them is as simple as extending the
|
||||
[Kohana_Config_Reader] / [Kohana_Config_Writer] interfaces:
|
||||
|
||||
class Kohana_Config_Database_Reader implements Kohana_Config_Reader
|
||||
class Kohana_Config_Database_Writer extends Kohana_Config_Database_Reader implements Kohana_Config_Writer
|
||||
|
||||
You'll notice in the above example that the Database Writer extends the Database Reader.
|
||||
This is the convention with config sources, the reasoning being that if you can write to a
|
||||
source chances are you can also read from it as well. However, this convention is not enforced
|
||||
and is left to the developer's discretion.
|
||||
|
||||
## Groups
|
||||
|
||||
In order to aid organisation config values are split up into logical "groups". For example,
|
||||
database related settings go in a `database` group, and session related settings go in a
|
||||
`session` group.
|
||||
|
||||
How these groups are stored/organised is up to the config source. For example, the file source
|
||||
puts different config groups into different files (`database.php`, `session.php`) whereas
|
||||
the database source uses a column to distinguish between groups.
|
||||
|
||||
To load a config group simply call `Kohana::$config->load()` with the name of the group you wish to load:
|
||||
|
||||
$config = Kohana::$config->load('my_group');
|
||||
|
||||
`load()` will return an instance of [Config_Group] which encapsulates the config values and ensures
|
||||
that any modifications made will be passed back to the config writers.
|
||||
|
||||
To get a config value from a [Config_Group] object simply call [Config_Group::get]:
|
||||
|
||||
$config = Kohana::$config->load('my_group');
|
||||
$value = $config->get('var');
|
||||
|
||||
To modify a value call [Config_Group::set]:
|
||||
|
||||
$config = Kohana::$config->load('my_group');
|
||||
$config->set('var', 'new_value');
|
||||
|
||||
### Alternative methods for getting / setting config
|
||||
|
||||
In addition to the methods described above you can also access config values using dots to outline a path
|
||||
from the config group to the value you want:
|
||||
|
||||
// Config file: database.php
|
||||
return array(
|
||||
'default' => array(
|
||||
'connection' => array(
|
||||
'hostname' => 'localhost'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Code which needs hostname:
|
||||
$hostname = Kohana::$config->load('database.default.connection.hostname');
|
||||
|
||||
|
||||
Which is equivalent to:
|
||||
|
||||
$config = Kohana::$config->load('database')->get('default');
|
||||
|
||||
$hostname = $config['connection']['hostname'];
|
||||
|
||||
Obviously this method is a lot more compact than the original. However, please bear in mind that using
|
||||
`dot.notation` is a _lot_ slower than calling `get()` and traversing the array yourself. Dot notation
|
||||
can be useful if you only need one specific variable, but otherwise it's best to use `get()`.
|
||||
|
||||
As [Config_Group] extends [Array_Object](http://php.net/manual/en/class.arrayobject.php) you can also use array
|
||||
syntax to get/set config vars:
|
||||
|
||||
$config = Kohana::$config->load('database');
|
||||
|
||||
// Getting the var
|
||||
$hostname = $config['default']['connection']['hostname'];
|
||||
|
||||
// Setting the var
|
||||
$config['default']['connection']['hostname'] = '127.0.0.1';
|
||||
|
||||
Again, this syntax is more costly than calling `get()` / `set()`.
|
||||
|
||||
## Config Merging
|
||||
|
||||
One of the useful features of the config system is config group merging. This works in a similar way
|
||||
to the cascading filesystem, with configuration from lower sources lower down the source stack being
|
||||
merged with sources further up the stack.
|
||||
|
||||
If two sources contain the same config variables then the one from the source further up the stack will
|
||||
override the one from the "lower" source. However, if the source from higher up the stack does not contain
|
||||
a particular config variable but a source lower down the stack does then the value from the lower source will
|
||||
be used.
|
||||
|
||||
The position of sources in the stack is determined by how they are loaded in your bootstrap.
|
||||
By default when you load a source it is pushed to the top of a stack:
|
||||
|
||||
// Stack: <empty>
|
||||
Kohana::$config->attach(new Config_File);
|
||||
// Stack: Config_File
|
||||
Kohana::$config->attach(new Config_Database);
|
||||
// Stack: Config_Database, Config_File
|
||||
|
||||
In the example above, any config values found in the database will override those found in the filesystem.
|
||||
For example, using the setup outlined above:
|
||||
|
||||
// Configuration in the filesystem:
|
||||
email:
|
||||
sender:
|
||||
email: my.awesome.address@example.com
|
||||
name: Unknown
|
||||
method: smtp
|
||||
|
||||
// Configuration in the database:
|
||||
email:
|
||||
sender:
|
||||
email: my.supercool.address@gmail.com
|
||||
name: Kohana Bot
|
||||
|
||||
// Configuration returned by Kohana::$config->load('email')
|
||||
email:
|
||||
sender:
|
||||
email: my.supercool.address@gmail.com
|
||||
name: Kohana Bot
|
||||
method: smtp
|
||||
|
||||
[!!] **Note:** The above syntax is simply pseudo code to illustrate the concept of config merging.
|
||||
|
||||
On some occasions you may want to append a config source to the bottom of the stack, to do this pass `FALSE`
|
||||
as the second parameter to `attach()`:
|
||||
|
||||
// Stack: <empty>
|
||||
Kohana::$config->attach(new Config_File);
|
||||
// Stack: Config_File
|
||||
Kohana::$config->attach(new Config_Database, FALSE);
|
||||
// Stack: Config_File, Config_Database
|
||||
|
||||
In this example, any values found in the filesystem will override those found in the db. For example:
|
||||
|
||||
// Configuration in the filesystem:
|
||||
email:
|
||||
sender:
|
||||
email: my.awesome.address@example.com
|
||||
name: Unknown
|
||||
method: smtp
|
||||
|
||||
// Configuration in the database:
|
||||
email:
|
||||
sender:
|
||||
email: my.supercool.address@gmail.com
|
||||
name: Kohana Bot
|
||||
|
||||
// Configuration returned by Kohana::$config->load('email')
|
||||
email:
|
||||
sender:
|
||||
email: my.awesome.address@example.com
|
||||
name: Unknown
|
||||
method: smtp
|
||||
|
||||
## Using different config sources based on the environment
|
||||
|
||||
In some situations you'll need to use different config values depending on which state `Kohana::$environment`
|
||||
is in. Unit testing is a prime example of such a situation. Most setups have two databases; one for normal
|
||||
development and a separate one for unit testing (to isolate the tests from your development).
|
||||
|
||||
In this case you still need access to the config settings stored in the `config` directory as it contains generic
|
||||
settings that are needed whatever environment your application is in (e.g. encryption settings),
|
||||
so replacing the default `Config_File` source isn't really an option.
|
||||
|
||||
To get around this you can attach a separate config file reader which loads its config from a subdir of `config` called
|
||||
"testing":
|
||||
|
||||
Kohana::$config->attach(new Config_File);
|
||||
|
||||
Kohana::$config->attach(new Config_Database);
|
||||
|
||||
if (Kohana::$environment === Kohana::TESTING)
|
||||
{
|
||||
Kohana::$config->attach(new Config_File('config/testing'));
|
||||
}
|
||||
|
||||
During normal development the config source stack looks like `Config_Database, Config_File('config')`. However,
|
||||
when `Kohana::$environment === Kohana::TESTING` the stack looks like `Config_File('config/testing'), Config_Database, Config_File('config')`
|
1
includes/kohana/system/guide/kohana/controllers.md
Normal file
1
includes/kohana/system/guide/kohana/controllers.md
Normal file
@@ -0,0 +1 @@
|
||||
This will discuss controller basics, like before() and after(), private function, and about extending controllers like the Controller_Template, or using a parent::before() for authentication.
|
418
includes/kohana/system/guide/kohana/conventions.md
Normal file
418
includes/kohana/system/guide/kohana/conventions.md
Normal file
@@ -0,0 +1,418 @@
|
||||
# Conventions and Coding Style
|
||||
|
||||
It is encouraged that you follow Kohana's coding style. This makes code more readable and allows for easier code sharing and contributing.
|
||||
|
||||
## Class Names and File Location
|
||||
|
||||
Class names in Kohana follow a strict convention to facilitate [autoloading](autoloading). Class names should have uppercase first letters with underscores to separate words. Underscores are significant as they directly reflect the file location in the filesystem.
|
||||
|
||||
The following conventions apply:
|
||||
|
||||
1. CamelCased class names should be used when it is undesirable to create a new directory level.
|
||||
2. All class file names and directory names must match the case of the class as per [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md).
|
||||
3. All classes should be in the `classes` directory. This may be at any level in the [cascading filesystem](files).
|
||||
|
||||
### Examples {#class-name-examples}
|
||||
|
||||
Remember that in a class, an underscore means a new directory. Consider the following examples:
|
||||
|
||||
Class Name | File Path
|
||||
----------------------|-------------------------------
|
||||
Controller_Template | classes/Controller/Template.php
|
||||
Model_User | classes/Model/User.php
|
||||
Model_BlogPost | classes/Model/BlogPost.php
|
||||
Database | classes/Database.php
|
||||
Database_Query | classes/Database/Query.php
|
||||
Form | classes/Form.php
|
||||
|
||||
## Coding Standards
|
||||
|
||||
In order to produce highly consistent source code, we ask that everyone follow the coding standards as closely as possible.
|
||||
|
||||
### Brackets
|
||||
|
||||
Please use [BSD/Allman Style](http://en.wikipedia.org/wiki/Indent_style#BSD.2FAllman_style) bracketing.
|
||||
|
||||
#### Curly Brackets
|
||||
|
||||
Curly brackets are placed on their own line, indented to the same level as the control statement.
|
||||
|
||||
// Correct
|
||||
if ($a === $b)
|
||||
{
|
||||
...
|
||||
}
|
||||
else
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
// Incorrect
|
||||
if ($a === $b) {
|
||||
...
|
||||
} else {
|
||||
...
|
||||
}
|
||||
|
||||
#### Class Brackets
|
||||
|
||||
The only exception to the curly bracket rule is, the opening bracket of a class goes on the same line.
|
||||
|
||||
// Correct
|
||||
class Foo {
|
||||
|
||||
// Incorrect
|
||||
class Foo
|
||||
{
|
||||
|
||||
#### Empty Brackets
|
||||
|
||||
Don't put any characters inside empty brackets.
|
||||
|
||||
// Correct
|
||||
class Foo {}
|
||||
|
||||
// Incorrect
|
||||
class Foo { }
|
||||
|
||||
#### Array Brackets
|
||||
|
||||
Arrays may be single line or multi-line.
|
||||
|
||||
array('a' => 'b', 'c' => 'd')
|
||||
|
||||
array(
|
||||
'a' => 'b',
|
||||
'c' => 'd',
|
||||
)
|
||||
|
||||
##### Opening Parenthesis
|
||||
|
||||
The opening array parenthesis goes on the same line.
|
||||
|
||||
// Correct
|
||||
array(
|
||||
...
|
||||
)
|
||||
|
||||
// Incorrect:
|
||||
array
|
||||
(
|
||||
...
|
||||
)
|
||||
|
||||
##### Closing parenthesis
|
||||
|
||||
###### Single Dimension
|
||||
|
||||
The closing parenthesis of a multi-line single dimension array is placed on its own line, indented to the same level as the assignment or statement.
|
||||
|
||||
// Correct
|
||||
$array = array(
|
||||
...
|
||||
)
|
||||
|
||||
// Incorrect
|
||||
$array = array(
|
||||
...
|
||||
)
|
||||
|
||||
###### Multidimensional
|
||||
|
||||
The nested array is indented one tab to the right, following the single dimension rules.
|
||||
|
||||
// Correct
|
||||
array(
|
||||
'arr' => array(
|
||||
...
|
||||
),
|
||||
'arr' => array(
|
||||
...
|
||||
),
|
||||
)
|
||||
|
||||
array(
|
||||
'arr' => array(...),
|
||||
'arr' => array(...),
|
||||
)
|
||||
|
||||
##### Arrays as Function Arguments
|
||||
|
||||
|
||||
// Correct
|
||||
do(array(
|
||||
...
|
||||
))
|
||||
|
||||
// Incorrect
|
||||
do(array(
|
||||
...
|
||||
))
|
||||
|
||||
As noted at the start of the array bracket section, single line syntax is also valid.
|
||||
|
||||
// Correct
|
||||
do(array(...))
|
||||
|
||||
// Alternative for wrapping long lines
|
||||
do($bar, 'this is a very long line',
|
||||
array(...));
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
Kohana uses under_score naming, not camelCase naming.
|
||||
|
||||
#### Classes
|
||||
|
||||
// Controller class, uses Controller_ prefix
|
||||
class Controller_Apple extends Controller {
|
||||
|
||||
// Model class, uses Model_ prefix
|
||||
class Model_Cheese extends Model {
|
||||
|
||||
// Regular class
|
||||
class Peanut {
|
||||
|
||||
When creating an instance of a class, don't use parentheses if you're not passing something on to the constructor:
|
||||
|
||||
// Correct:
|
||||
$db = new Database;
|
||||
|
||||
// Incorrect:
|
||||
$db = new Database();
|
||||
|
||||
#### Functions and Methods
|
||||
|
||||
Functions should be all lowercase, and use under_scores to separate words:
|
||||
|
||||
function drink_beverage($beverage)
|
||||
{
|
||||
|
||||
#### Variables
|
||||
|
||||
All variables should be lowercase and use under_score, not camelCase:
|
||||
|
||||
// Correct:
|
||||
$foo = 'bar';
|
||||
$long_example = 'uses underscores';
|
||||
|
||||
// Incorrect:
|
||||
$weDontWantThis = 'understood?';
|
||||
|
||||
### Indentation
|
||||
|
||||
You must use tabs to indent your code. Using spaces for tabbing is strictly forbidden.
|
||||
|
||||
Vertical spacing (for multi-line) is done with spaces. Tabs are not good for vertical alignment because different people have different tab widths.
|
||||
|
||||
$text = 'this is a long text block that is wrapped. Normally, we aim for '
|
||||
.'wrapping at 80 chars. Vertical alignment is very important for '
|
||||
.'code readability. Remember that all indentation is done with tabs,'
|
||||
.'but vertical alignment should be completed with spaces, after '
|
||||
.'indenting with tabs.';
|
||||
|
||||
### String Concatenation
|
||||
|
||||
Do not put spaces around the concatenation operator:
|
||||
|
||||
// Correct:
|
||||
$str = 'one'.$var.'two';
|
||||
|
||||
// Incorrect:
|
||||
$str = 'one'. $var .'two';
|
||||
$str = 'one' . $var . 'two';
|
||||
|
||||
### Single Line Statements
|
||||
|
||||
Single-line IF statements should only be used when breaking normal execution (e.g. return or continue):
|
||||
|
||||
// Acceptable:
|
||||
if ($foo == $bar)
|
||||
return $foo;
|
||||
|
||||
if ($foo == $bar)
|
||||
continue;
|
||||
|
||||
if ($foo == $bar)
|
||||
break;
|
||||
|
||||
if ($foo == $bar)
|
||||
throw new Exception('You screwed up!');
|
||||
|
||||
// Not acceptable:
|
||||
if ($baz == $bun)
|
||||
$baz = $bar + 2;
|
||||
|
||||
### Comparison Operations
|
||||
|
||||
Please use OR and AND for comparison:
|
||||
|
||||
// Correct:
|
||||
if (($foo AND $bar) OR ($b AND $c))
|
||||
|
||||
// Incorrect:
|
||||
if (($foo && $bar) || ($b && $c))
|
||||
|
||||
Please use elseif, not else if:
|
||||
|
||||
// Correct:
|
||||
elseif ($bar)
|
||||
|
||||
// Incorrect:
|
||||
else if($bar)
|
||||
|
||||
### Switch Structures
|
||||
|
||||
Each case, break and default should be on a separate line. The block inside a case or default must be indented by 1 tab.
|
||||
|
||||
switch ($var)
|
||||
{
|
||||
case 'bar':
|
||||
case 'foo':
|
||||
echo 'hello';
|
||||
break;
|
||||
case 1:
|
||||
echo 'one';
|
||||
break;
|
||||
default:
|
||||
echo 'bye';
|
||||
break;
|
||||
}
|
||||
|
||||
### Parentheses
|
||||
|
||||
There should be one space after statement name, followed by a parenthesis. The ! (bang) character must have a space on either side to ensure maximum readability. Except in the case of a bang or type casting, there should be no whitespace after an opening parenthesis or before a closing parenthesis.
|
||||
|
||||
// Correct:
|
||||
if ($foo == $bar)
|
||||
if ( ! $foo)
|
||||
|
||||
// Incorrect:
|
||||
if($foo == $bar)
|
||||
if(!$foo)
|
||||
if ((int) $foo)
|
||||
if ( $foo == $bar )
|
||||
if (! $foo)
|
||||
|
||||
### Ternaries
|
||||
|
||||
All ternary operations should follow a standard format. Use parentheses around expressions only, not around just variables.
|
||||
|
||||
$foo = ($bar == $foo) ? $foo : $bar;
|
||||
$foo = $bar ? $foo : $bar;
|
||||
|
||||
All comparisons and operations must be done inside of a parentheses group:
|
||||
|
||||
$foo = ($bar > 5) ? ($bar + $foo) : strlen($bar);
|
||||
|
||||
When separating complex ternaries (ternaries where the first part goes beyond ~80 chars) into multiple lines, spaces should be used to line up operators, which should be at the front of the successive lines:
|
||||
|
||||
$foo = ($bar == $foo)
|
||||
? $foo
|
||||
: $bar;
|
||||
|
||||
### Type Casting
|
||||
|
||||
Type casting should be done with spaces on each side of the cast:
|
||||
|
||||
// Correct:
|
||||
$foo = (string) $bar;
|
||||
if ( (string) $bar)
|
||||
|
||||
// Incorrect:
|
||||
$foo = (string)$bar;
|
||||
|
||||
When possible, please use type casting instead of ternary operations:
|
||||
|
||||
// Correct:
|
||||
$foo = (bool) $bar;
|
||||
|
||||
// Incorrect:
|
||||
$foo = ($bar == TRUE) ? TRUE : FALSE;
|
||||
|
||||
When casting type to integer or boolean, use the short format:
|
||||
|
||||
// Correct:
|
||||
$foo = (int) $bar;
|
||||
$foo = (bool) $bar;
|
||||
|
||||
// Incorrect:
|
||||
$foo = (integer) $bar;
|
||||
$foo = (boolean) $bar;
|
||||
|
||||
### Constants
|
||||
|
||||
Always use uppercase for constants:
|
||||
|
||||
// Correct:
|
||||
define('MY_CONSTANT', 'my_value');
|
||||
$a = TRUE;
|
||||
$b = NULL;
|
||||
|
||||
// Incorrect:
|
||||
define('MyConstant', 'my_value');
|
||||
$a = True;
|
||||
$b = null;
|
||||
|
||||
Place constant comparisons at the end of tests:
|
||||
|
||||
// Correct:
|
||||
if ($foo !== FALSE)
|
||||
|
||||
// Incorrect:
|
||||
if (FALSE !== $foo)
|
||||
|
||||
This is a slightly controversial choice, so I will explain the reasoning. If we were to write the previous example in plain English, the correct example would read:
|
||||
|
||||
if variable $foo is not exactly FALSE
|
||||
|
||||
And the incorrect example would read:
|
||||
|
||||
if FALSE is not exactly variable $foo
|
||||
|
||||
Since we are reading left to right, it simply doesn't make sense to put the constant first.
|
||||
|
||||
### Comments
|
||||
|
||||
#### One-line Comments
|
||||
|
||||
Use //, preferably above the line of code you're commenting on. Leave a space after it and start with a capital. Never use #.
|
||||
|
||||
// Correct
|
||||
|
||||
//Incorrect
|
||||
// incorrect
|
||||
# Incorrect
|
||||
|
||||
### Regular Expressions
|
||||
|
||||
When coding regular expressions please use PCRE rather than the POSIX flavor. PCRE is considered more powerful and faster.
|
||||
|
||||
// Correct:
|
||||
if (preg_match('/abc/i', $str))
|
||||
|
||||
// Incorrect:
|
||||
if (eregi('abc', $str))
|
||||
|
||||
Use single quotes around your regular expressions rather than double quotes. Single-quoted strings are more convenient because of their simplicity. Unlike double-quoted strings they don't support variable interpolation nor integrated backslash sequences like \n or \t, etc.
|
||||
|
||||
// Correct:
|
||||
preg_match('/abc/', $str);
|
||||
|
||||
// Incorrect:
|
||||
preg_match("/abc/", $str);
|
||||
|
||||
When performing a regular expression search and replace, please use the $n notation for backreferences. This is preferred over \\n.
|
||||
|
||||
// Correct:
|
||||
preg_replace('/(\d+) dollar/', '$1 euro', $str);
|
||||
|
||||
// Incorrect:
|
||||
preg_replace('/(\d+) dollar/', '\\1 euro', $str);
|
||||
|
||||
Finally, please note that the $ character for matching the position at the end of the line allows for a following newline character. Use the D modifier to fix this if needed. [More info](http://blog.php-security.org/archives/76-Holes-in-most-preg_match-filters.html).
|
||||
|
||||
$str = "email@example.com\n";
|
||||
|
||||
preg_match('/^.+@.+$/', $str); // TRUE
|
||||
preg_match('/^.+@.+$/D', $str); // FALSE
|
100
includes/kohana/system/guide/kohana/cookies.md
Normal file
100
includes/kohana/system/guide/kohana/cookies.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# Cookies
|
||||
|
||||
Kohana provides classes that make it easy to work with both cookies and sessions. At a high level both sessions and cookies provide the same functionality. They allow the developer to store temporary or persistent information about a specific client for later retrieval, usually to make something persistent between requests.
|
||||
|
||||
[Cookies](http://en.wikipedia.org/wiki/HTTP_cookie) should be used for storing non-private data that is persistent for a long period of time. For example storing a user preference or a language setting. Use the [Cookie] class for getting and setting cookies.
|
||||
|
||||
[!!] Kohana uses "signed" cookies. Every cookie that is stored is combined with a secure hash to prevent modification of the cookie. If a cookie is modified outside of Kohana the hash will be incorrect and the cookie will be deleted. This hash is generated using [Cookie::salt()], which uses the [Cookie::$salt] property. You must define this setting in your bootstrap.php:
|
||||
|
||||
Cookie::$salt = 'foobar';
|
||||
|
||||
Or define an extended cookie class in your application:
|
||||
|
||||
class Cookie extends Kohana_Cookie
|
||||
{
|
||||
public static $salt = 'foobar';
|
||||
}
|
||||
|
||||
You should set the salt to a secure value. The example above is only for demonstrative purposes.
|
||||
|
||||
Nothing stops you from using `$_COOKIE` like normal, but you can not mix using the Cookie class and the regular `$_COOKIE` global, because the hash that Kohana uses to sign cookies will not be present, and Kohana will delete the cookie.
|
||||
|
||||
## Storing, Retrieving, and Deleting Data
|
||||
|
||||
[Cookie] and [Session] provide a very similar API for storing data. The main difference between them is that sessions are accessed using an object, and cookies are accessed using a static class.
|
||||
|
||||
### Storing Data
|
||||
|
||||
Storing session or cookie data is done using the [Cookie::set] method:
|
||||
|
||||
// Set cookie data
|
||||
Cookie::set($key, $value);
|
||||
|
||||
// Store a user id
|
||||
Cookie::set('user_id', 10);
|
||||
|
||||
### Retrieving Data
|
||||
|
||||
Getting session or cookie data is done using the [Cookie::get] method:
|
||||
|
||||
// Get cookie data
|
||||
$data = Cookie::get($key, $default_value);
|
||||
|
||||
// Get the user id
|
||||
$user = Cookie::get('user_id');
|
||||
|
||||
### Deleting Data
|
||||
|
||||
Deleting session or cookie data is done using the [Cookie::delete] method:
|
||||
|
||||
// Delete cookie data
|
||||
Cookie::delete($key);
|
||||
|
||||
// Delete the user id
|
||||
Cookie::delete('user_id');
|
||||
|
||||
## Cookie Settings
|
||||
|
||||
All of the cookie settings are changed using static properties. You can either change these settings in `bootstrap.php` or by using [transparent extension](extension). Always check these settings before making your application live, as many of them will have a direct affect on the security of your application.
|
||||
|
||||
The most important setting is [Cookie::$salt], which is used for secure signing. This value should be changed and kept secret:
|
||||
|
||||
Cookie::$salt = 'your secret is safe with me';
|
||||
|
||||
[!!] Changing this value will render all cookies that have been set before invalid.
|
||||
|
||||
By default, cookies are stored until the browser is closed. To use a specific lifetime, change the [Cookie::$expiration] setting:
|
||||
|
||||
// Set cookies to expire after 1 week
|
||||
Cookie::$expiration = 604800;
|
||||
|
||||
// Alternative to using raw integers, for better clarity
|
||||
Cookie::$expiration = Date::WEEK;
|
||||
|
||||
The path that the cookie can be accessed from can be restricted using the [Cookie::$path] setting.
|
||||
|
||||
// Allow cookies only when going to /public/*
|
||||
Cookie::$path = '/public/';
|
||||
|
||||
The domain that the cookie can be accessed from can also be restricted, using the [Cookie::$domain] setting.
|
||||
|
||||
// Allow cookies only on the domain www.example.com
|
||||
Cookie::$domain = 'www.example.com';
|
||||
|
||||
If you want to make the cookie accessible on all subdomains, use a dot at the beginning of the domain.
|
||||
|
||||
// Allow cookies to be accessed on example.com and *.example.com
|
||||
Cookie::$domain = '.example.com';
|
||||
|
||||
To only allow the cookie to be accessed over a secure (HTTPS) connection, use the [Cookie::$secure] setting.
|
||||
|
||||
// Allow cookies to be accessed only on a secure connection
|
||||
Cookie::$secure = TRUE;
|
||||
|
||||
// Allow cookies to be accessed on any connection
|
||||
Cookie::$secure = FALSE;
|
||||
|
||||
To prevent cookies from being accessed using Javascript, you can change the [Cookie::$httponly] setting.
|
||||
|
||||
// Make cookies inaccessible to Javascript
|
||||
Cookie::$httponly = TRUE;
|
20
includes/kohana/system/guide/kohana/debugging.md
Normal file
20
includes/kohana/system/guide/kohana/debugging.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Debugging
|
||||
|
||||
Kohana includes several tools to help you debug your application.
|
||||
|
||||
The most basic of these is [Debug::vars]. This simple method will display any number of variables, similar to [var_export](http://php.net/var_export) or [print_r](http://php.net/print_r), but using HTML for extra formatting.
|
||||
|
||||
// Display a dump of the $foo and $bar variables
|
||||
echo Debug::vars($foo, $bar);
|
||||
|
||||
Kohana also provides a method to show the source code of a particular file using [Debug::source].
|
||||
|
||||
// Display this line of source code
|
||||
echo Debug::source(__FILE__, __LINE__);
|
||||
|
||||
If you want to display information about your application files without exposing the installation directory, you can use [Debug::path]:
|
||||
|
||||
// Displays "APPPATH/cache" rather than the real path
|
||||
echo Debug::path(APPPATH.'cache');
|
||||
|
||||
If you are having trouble getting something to work correctly, you could check your Kohana logs and your webserver logs, as well as using a debugging tool like [Xdebug](http://www.xdebug.org/).
|
64
includes/kohana/system/guide/kohana/errors.md
Normal file
64
includes/kohana/system/guide/kohana/errors.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Error/Exception Handling
|
||||
|
||||
Kohana provides both an exception handler and an error handler that transforms errors into exceptions using PHP's [ErrorException](http://php.net/errorexception) class. Many details of the error and the internal state of the application is displayed by the handler:
|
||||
|
||||
1. Exception class
|
||||
2. Error level
|
||||
3. Error message
|
||||
4. Source of the error, with the error line highlighted
|
||||
5. A [debug backtrace](http://php.net/debug_backtrace) of the execution flow
|
||||
6. Included files, loaded extensions, and global variables
|
||||
|
||||
## Example
|
||||
|
||||
Click any of the links to toggle the display of additional information:
|
||||
|
||||
<div>{{userguide/examples/error}}</div>
|
||||
|
||||
## Disabling Error/Exception Handling
|
||||
|
||||
If you do not want to use the internal error handling, you can disable it (highly discouraged) when calling [Kohana::init]:
|
||||
|
||||
Kohana::init(array('errors' => FALSE));
|
||||
|
||||
## Error Reporting
|
||||
|
||||
By default, Kohana displays all errors, including strict mode warnings. This is set using [error_reporting](http://php.net/error_reporting):
|
||||
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
When you application is live and in production, a more conservative setting is recommended, such as ignoring notices:
|
||||
|
||||
error_reporting(E_ALL & ~E_NOTICE);
|
||||
|
||||
If you get a white screen when an error is triggered, your host probably has disabled displaying errors. You can turn it on again by adding this line just after your `error_reporting` call:
|
||||
|
||||
ini_set('display_errors', TRUE);
|
||||
|
||||
Errors should **always** be displayed, even in production, because it allows you to use [exception and error handling](debugging.errors) to serve a nice error page rather than a blank white screen when an error happens.
|
||||
|
||||
## HTTP Exception Handling
|
||||
|
||||
Kohana comes with a robust system for handing http errors. It includes exception classes for each http status code. To trigger a 404 in your application (the most common scenario):
|
||||
|
||||
throw HTTP_Exception::factory(404, 'File not found!');
|
||||
|
||||
To register error pages for these, using 404 as an example:
|
||||
|
||||
class HTTP_Exception_404 extends Kohana_HTTP_Exception_404 {
|
||||
|
||||
public function get_response()
|
||||
{
|
||||
$response = Response::factory();
|
||||
|
||||
$view = View::factory('errors/404');
|
||||
|
||||
// We're inside an instance of Exception here, all the normal stuff is available.
|
||||
$view->message = $this->getMessage();
|
||||
|
||||
$response->body($view->render());
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
101
includes/kohana/system/guide/kohana/extension.md
Normal file
101
includes/kohana/system/guide/kohana/extension.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# Transparent Class Extension
|
||||
|
||||
The [cascading filesystem](files) allows transparent class extension. For instance, the class [Cookie] is defined in `SYSPATH/classes/Cookie.php` as:
|
||||
|
||||
class Cookie extends Kohana_Cookie {}
|
||||
|
||||
The default Kohana classes, and many extensions, use this definition so that almost all classes can be extended. You extend any class transparently, by defining your own class in `APPPATH/classes/Cookie.php` to add your own methods.
|
||||
|
||||
[!!] You should **never** modify any of the files that are distributed with Kohana. Always make modifications to classes using transparent extension to prevent upgrade issues.
|
||||
|
||||
For instance, if you wanted to create method that sets encrypted cookies using the [Encrypt] class, you would create a file at `APPPATH/classes/Cookie.php` that extends Kohana_Cookie, and adds your functions:
|
||||
|
||||
<?php defined('SYSPATH') OR die('No direct script access.');
|
||||
|
||||
class Cookie extends Kohana_Cookie {
|
||||
|
||||
/**
|
||||
* @var mixed default encryption instance
|
||||
*/
|
||||
public static $encryption = 'default';
|
||||
|
||||
/**
|
||||
* Sets an encrypted cookie.
|
||||
*
|
||||
* @uses Cookie::set
|
||||
* @uses Encrypt::encode
|
||||
*/
|
||||
public static function encrypt($name, $value, $expiration = NULL)
|
||||
{
|
||||
$value = Encrypt::instance(Cookie::$encrpytion)->encode((string) $value);
|
||||
|
||||
parent::set($name, $value, $expiration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an encrypted cookie.
|
||||
*
|
||||
* @uses Cookie::get
|
||||
* @uses Encrypt::decode
|
||||
*/
|
||||
public static function decrypt($name, $default = NULL)
|
||||
{
|
||||
if ($value = parent::get($name, NULL))
|
||||
{
|
||||
$value = Encrypt::instance(Cookie::$encryption)->decode($value);
|
||||
}
|
||||
|
||||
return isset($value) ? $value : $default;
|
||||
}
|
||||
|
||||
} // End Cookie
|
||||
|
||||
Now calling `Cookie::encrypt('secret', $data)` will create an encrypted cookie which we can decrypt with `$data = Cookie::decrypt('secret')`.
|
||||
|
||||
## How it works
|
||||
|
||||
To understand how this works, let's look at what happens normally. When you use the Cookie class, [Kohana::autoload] looks for `classes/Cookie.php` in the [cascading filesystem](files). It looks in `application`, then each module, then `system`. The file is found in `system` and is included. Of course, `system/classes/Cookie.php` is just an empty class which extends `Kohana_Cookie`. Again, [Kohana::autoload] is called this time looking for `classes/Kohana/Cookie.php` which it finds in `system`.
|
||||
|
||||
When you add your transparently extended cookie class at `application/classes/Cookie.php` this file essentially "replaces" the file at `system/classes/Cookie.php` without actually touching it. This happens because this time when we use the Cookie class [Kohana::autoload] looks for `classes/Cookie.php` and finds the file in `application` and includes that one, instead of the one in system.
|
||||
|
||||
## Example: changing [Cookie] settings
|
||||
|
||||
If you are using the [Cookie](cookies) class, and want to change a setting, you should do so using transparent extension, rather than editing the file in the system folder. If you edit it directly, and in the future you upgrade your Kohana version by replacing the system folder, your changes will be reverted and your cookies will probably be invalid. Instead, create a Cookie.php file either in `application/classes/Cookie.php` or a module (`MODPATH/<modulename>/classes/Cookie.php`).
|
||||
|
||||
class Cookie extends Kohana_Cookie {
|
||||
|
||||
// Set a new salt
|
||||
public $salt = "some new better random salt phrase";
|
||||
|
||||
// Don't allow javascript access to cookies
|
||||
public $httponly = TRUE;
|
||||
|
||||
}
|
||||
|
||||
## Example: TODO: an example
|
||||
|
||||
Just post the code and brief description of what function it adds, you don't have to do the "How it works" like above.
|
||||
|
||||
## Example: TODO: something else
|
||||
|
||||
Just post the code and brief description of what function it adds, you don't have to do the "How it works" like above.
|
||||
|
||||
## More examples
|
||||
|
||||
TODO: Provide some links to modules on github, etc that have examples of transparent extension in use.
|
||||
|
||||
## Multiple Levels of Extension
|
||||
|
||||
If you are extending a Kohana class in a module, you should maintain transparent extensions. In other words, do not include any variables or function in the "base" class (eg. Cookie). Instead make your own namespaced class, and have the "base" class extend that one. With our Encrypted cookie example we can create `MODPATH/mymod/Encrypted/Cookie.php`:
|
||||
|
||||
class Encrypted_Cookie extends Kohana_Cookie {
|
||||
|
||||
// Use the same encrypt() and decrypt() methods as above
|
||||
|
||||
}
|
||||
|
||||
And create `MODPATH/mymod/Cookie.php`:
|
||||
|
||||
class Cookie extends Encrypted_Cookie {}
|
||||
|
||||
This will still allow users to add their own extension to [Cookie] while leaving your extensions intact. To do that they would make a cookie class that extends `Encrypted_Cookie` (rather than `Kohana_Cookie`) in their application folder.
|
83
includes/kohana/system/guide/kohana/files.md
Normal file
83
includes/kohana/system/guide/kohana/files.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Cascading Filesystem
|
||||
|
||||
The Kohana filesystem is a hierarchy of similar directory structures that cascade. The hierarchy in Kohana (used when a file is loaded by [Kohana::find_file]) is in the following order:
|
||||
|
||||
1. **Application Path**
|
||||
Defined as `APPPATH` in `index.php`. The default value is `application`.
|
||||
|
||||
2. **Module Paths**
|
||||
This is set as an associative array using [Kohana::modules] in `APPPATH/bootstrap.php`. Each of the values of the array will be searched **in the order that the modules are defined**.
|
||||
|
||||
3. **System Path**
|
||||
Defined as `SYSPATH` in `index.php`. The default value is `system`. All of the main or "core" files and classes are defined here.
|
||||
|
||||
Files that are in directories higher up the include path order take precedence over files of the same name lower down the order, which makes it is possible to overload any file by placing a file with the same name in a "higher" directory:
|
||||
|
||||

|
||||
|
||||
This image is only shows certain files, but we can use it to illustrate some examples of the cascading filesystem:
|
||||
|
||||
* If Kohana catches an error, it would display the `kohana/error.php` view, So it would call `Kohana::find_file('views', 'kohana/error')`. This would return `application/views/kohana/error.php` because it takes precidence over `system/views/kohana/error.php`. By doing this we can change the error view without editing the system folder.
|
||||
|
||||
* If we used `View::factory('welcome')` it would call `Kohana::find_file('views','welcome')` which would return `application/views/welcome.php` because it takes precidence over `modules/common/views/welcome.php`. By doing this, you can overwrite things in a module without editing the modules files.
|
||||
|
||||
* If use the Cookie class, [Kohana::auto_load] will call `Kohana::find_file('classes', 'Cookie')` which will return `application/classes/Cookie.php`. Assuming Cookie extends Kohana_Cookie, the autoloader would then call `Kohana::find_file('classes','Kohana/Cookie')` which will return `system/classes/Kohana/Cookie.php` because that file does not exist anywhere higher in the cascade. This is an example of [transparent extension](extension).
|
||||
|
||||
* If you used `View::factory('user')` it would call `Kohana::find_file('views','user')` which would return `modules/common/views/user.php`.
|
||||
|
||||
* If we wanted to change something in `config/database.php` we could copy the file to `application/config/database.php` and make the changes there. Keep in mind that [config files are merged](files/config#merge) rather than overwritten by the cascade.
|
||||
|
||||
## Types of Files
|
||||
|
||||
The top level directories of the application, module, and system paths have the following default directories:
|
||||
|
||||
classes/
|
||||
: All classes that you want to [autoload](autoloading) should be stored here. This includes [controllers](mvc/controllers), [models](mvc/models), and all other classes. All classes must follow the [class naming conventions](conventions#class-names-and-file-location) including matching the case of the class i.e. Kohana_Cookie should be stored in classes/Kohana/Cookie.php and not classes/kohana/cookie.php.
|
||||
|
||||
config/
|
||||
: Configuration files return an associative array of options that can be loaded using [Kohana::$config]. Config files are merged rather than overwritten by the cascade. See [config files](files/config) for more information.
|
||||
|
||||
i18n/
|
||||
: Translation files return an associative array of strings. Translation is done using the `__()` method. To translate "Hello, world!" into Spanish, you would call `__('Hello, world!')` with [I18n::$lang] set to "es-es". I18n files are merged rather than overwritten by the cascade. See [I18n files](files/i18n) for more information.
|
||||
|
||||
messages/
|
||||
: Message files return an associative array of strings that can be loaded using [Kohana::message]. Messages and i18n files differ in that messages are not translated, but always written in the default language and referred to by a single key. Message files are merged rather than overwritten by the cascade. See [message files](files/messages) for more information.
|
||||
|
||||
views/
|
||||
: Views are plain PHP files which are used to generate HTML or other output. The view file is loaded into a [View] object and assigned variables, which it then converts into an HTML fragment. Multiple views can be used within each other. See [views](mvc/views) for more information.
|
||||
|
||||
*other*
|
||||
: You can include any other folders in your cascading filesystem. Examples include, but are not limited to, `guide`, `vendor`, `media`, whatever you want. For example, to find `media/logo.png` in the cascading filesystem you would call `Kohana::find_file('media','logo','png')`.
|
||||
|
||||
## Finding Files
|
||||
|
||||
The path to any file within the filesystem can be found by calling [Kohana::find_file]:
|
||||
|
||||
// Find the full path to "classes/Cookie.php"
|
||||
$path = Kohana::find_file('classes', 'Cookie');
|
||||
|
||||
// Find the full path to "views/user/login.php"
|
||||
$path = Kohana::find_file('views', 'user/login');
|
||||
|
||||
If the file doesn't have a `.php` extension, pass the extension as the third param.
|
||||
|
||||
// Find the full path to "guide/menu.md"
|
||||
$path = Kohana::find_file('guide', 'menu', 'md');
|
||||
|
||||
// If $name is "2000-01-01-first-post" this would look for "posts/2000-01-01-first-post.textile"
|
||||
$path = Kohana::find_file('posts', $name, '.textile');
|
||||
|
||||
|
||||
## Vendor Extensions
|
||||
|
||||
We call extensions or external libraries that are not specific to Kohana "vendor" extensions, and they go in the vendor folder, either in application or in a module. Because these libraries do not follow Kohana's file naming conventions, they cannot be autoloaded by Kohana, so you will have to manually included them. Some examples of vendor libraries are [Markdown](http://daringfireball.net/projects/markdown/), [DOMPDF](http://code.google.com/p/dompdf), [Mustache](http://github.com/bobthecow/mustache.php) and [Swiftmailer](http://swiftmailer.org/).
|
||||
|
||||
For example, if you wanted to use [DOMPDF](http://code.google.com/p/dompdf), you would copy it to `application/vendor/dompdf` and include the DOMPDF autoloading class. It can be useful to do this in a controller's before method, as part of a module's init.php, or the contstructor of a singleton class.
|
||||
|
||||
require Kohana::find_file('vendor', 'dompdf/dompdf/dompdf_config','inc');
|
||||
|
||||
Now you can use DOMPDF without loading any more files:
|
||||
|
||||
$pdf = new DOMPDF;
|
||||
|
||||
[!!] If you want to convert views into PDFs using DOMPDF, try the [PDFView](http://github.com/shadowhand/pdfview) module.
|
41
includes/kohana/system/guide/kohana/files/classes.md
Normal file
41
includes/kohana/system/guide/kohana/files/classes.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Classes
|
||||
|
||||
TODO: Brief intro to classes.
|
||||
|
||||
[Models](mvc/models) and [Controllers](mvc/controllers) are classes as well, but are treated slightly differently by Kohana. Read their respective pages to learn more.
|
||||
|
||||
## Helper or Library?
|
||||
|
||||
Kohana 3 does not differentiate between "helper" classes and "library" classes like in previous versions. They are all placed in the `classes/` folder and follow the same conventions. The distinction is that in general, a "helper" class is used statically, (for examples see the [helpers included in Kohana](helpers)), and library classes are typically instantiated and used as objects (like the [Database query builders](../database/query/builder)). The distinction is not black and white, and is irrelevant anyways, since they are treated the same by Kohana.
|
||||
|
||||
## Creating a class
|
||||
|
||||
To create a new class, simply place a file in the `classes/` directory at any point in the [Cascading Filesystem](files), that follows the [Class naming conventions](conventions#class-names-and-file-location). For example, lets create a `Foobar` class.
|
||||
|
||||
// classes/Foobar.php
|
||||
|
||||
class Foobar {
|
||||
static function magic() {
|
||||
// Does something
|
||||
}
|
||||
}
|
||||
|
||||
We can now call `Foobar::magic()` any where and Kohana will [autoload](autoloading) the file for us.
|
||||
|
||||
We can also put classes in subdirectories.
|
||||
|
||||
// classes/Professor/Baxter.php
|
||||
|
||||
class Professor_Baxter {
|
||||
static function teach() {
|
||||
// Does something
|
||||
}
|
||||
}
|
||||
|
||||
We could now call `Professor_Baxter::teach()` any where we want.
|
||||
|
||||
For examples of how to create and use classes, simply look at the 'classes' folder in `system` or any module.
|
||||
|
||||
## Namespacing your classes
|
||||
|
||||
TODO: Discuss namespacing to provide transparent extension functionality in your own classes/modules.
|
84
includes/kohana/system/guide/kohana/files/config.md
Normal file
84
includes/kohana/system/guide/kohana/files/config.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# Config Files
|
||||
|
||||
Configuration files are used to store any kind of configuration needed for a module, class, or anything else you want. They are plain PHP files, stored in the `config/` directory, which return an associative array:
|
||||
|
||||
<?php defined('SYSPATH') OR die('No direct script access.');
|
||||
|
||||
return array(
|
||||
'setting' => 'value',
|
||||
'options' => array(
|
||||
'foo' => 'bar',
|
||||
),
|
||||
);
|
||||
|
||||
If the above configuration file was called `myconf.php`, you could access it using:
|
||||
|
||||
$config = Kohana::$config->load('myconf');
|
||||
$options = $config->get('options')
|
||||
|
||||
## Merge
|
||||
|
||||
Configuration files are slightly different from most other files within the [cascading filesystem](files) in that they are **merged** rather than overloaded. This means that all configuration files with the same file path are combined to produce the final configuration. The end result is that you can overload *individual* settings rather than duplicating an entire file.
|
||||
|
||||
For example, if we wanted to change or add to an entry in the inflector configuration file, we would not need to duplicate all the other entries from the default configuration file.
|
||||
|
||||
// config/inflector.php
|
||||
|
||||
<?php defined('SYSPATH') OR die('No direct script access.');
|
||||
|
||||
return array(
|
||||
'irregular' => array(
|
||||
'die' => 'dice', // does not exist in default config file
|
||||
'mouse' => 'mouses', // overrides 'mouse' => 'mice' in the default config file
|
||||
);
|
||||
|
||||
|
||||
## Creating your own config files
|
||||
|
||||
Let's say we want a config file to store and easily change things like the title of a website, or the google analytics code. We would create a config file, let's call it `site.php`:
|
||||
|
||||
// config/site.php
|
||||
|
||||
<?php defined('SYSPATH') OR die('No direct script access.');
|
||||
|
||||
return array(
|
||||
'title' => 'Our Shiny Website',
|
||||
'analytics' => FALSE, // analytics code goes here, set to FALSE to disable
|
||||
);
|
||||
|
||||
We could now call `Kohana::$config->load('site.title')` to get the site name, and `Kohana::$config->load('site.analytics')` to get the analytics code.
|
||||
|
||||
Let's say we want an archive of versions of some software. We could use config files to store each version, and include links to download, documentation, and issue tracking.
|
||||
|
||||
// config/versions.php
|
||||
|
||||
<?php defined('SYSPATH') OR die('No direct script access.');
|
||||
|
||||
return array(
|
||||
'1.0.0' => array(
|
||||
'codename' => 'Frog',
|
||||
'download' => 'files/ourapp-1.0.0.tar.gz',
|
||||
'documentation' => 'docs/1.0.0',
|
||||
'released' => '06/05/2009',
|
||||
'issues' => 'link/to/bug/tracker',
|
||||
),
|
||||
'1.1.0' => array(
|
||||
'codename' => 'Lizard',
|
||||
'download' => 'files/ourapp-1.1.0.tar.gz',
|
||||
'documentation' => 'docs/1.1.0',
|
||||
'released' => '10/15/2009',
|
||||
'issues' => 'link/to/bug/tracker',
|
||||
),
|
||||
/// ... etc ...
|
||||
);
|
||||
|
||||
You could then do the following:
|
||||
|
||||
// In your controller
|
||||
$view->versions = Kohana::$config->load('versions');
|
||||
|
||||
// In your view:
|
||||
foreach ($versions as $version)
|
||||
{
|
||||
// echo some html to display each version
|
||||
}
|
67
includes/kohana/system/guide/kohana/files/i18n.md
Normal file
67
includes/kohana/system/guide/kohana/files/i18n.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# I18n
|
||||
|
||||
Kohana has a fairly simple and easy to use i18n system. It is slightly modeled after gettext, but is not as featureful. If you need the features of gettext, please use that :)
|
||||
|
||||
## __()
|
||||
|
||||
Kohana has a __() function to do your translations for you. This function is only meant for small sections of text, not entire paragraphs or pages of translated text.
|
||||
|
||||
To echo a translated string:
|
||||
|
||||
<?php echo __('Hello, world!');?>
|
||||
|
||||
This will echo 'Home' unless you've changed the defined language, which is explained below.
|
||||
|
||||
## Changing the displayed language
|
||||
|
||||
Use the I18n::lang() method to change the displayed language:
|
||||
|
||||
I18n::lang('fr');
|
||||
|
||||
This will change the language to 'es-es'.
|
||||
|
||||
## Defining language files
|
||||
|
||||
To define the language file for the above language change, create a `i18n/fr.php` that contains:
|
||||
|
||||
<?php
|
||||
|
||||
return array
|
||||
(
|
||||
'Hello, world!' => 'Bonjour, monde!',
|
||||
);
|
||||
|
||||
Now when you do `__('Hello, world!')`, you will get `Bonjour, monde!`
|
||||
|
||||
## I18n variables
|
||||
|
||||
You can define variables in your __() calls like so:
|
||||
|
||||
echo __('Hello, :user', array(':user' => $username));
|
||||
|
||||
Your i18n key in your translation file will need to be defined as:
|
||||
|
||||
<?php
|
||||
|
||||
return array
|
||||
(
|
||||
'Hello, :user' => 'Bonjour, :user',
|
||||
);
|
||||
|
||||
## Defining your own __() function
|
||||
|
||||
You can define your own __() function by simply defining your own i18n class:
|
||||
|
||||
<?php
|
||||
|
||||
class I18n extends Kohana_I18n
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
function __($string, array $values = NULL, $lang = 'en-us')
|
||||
{
|
||||
// Your functionality here
|
||||
}
|
||||
|
||||
This will cause the built-in __() function to be ignored.
|
36
includes/kohana/system/guide/kohana/files/messages.md
Normal file
36
includes/kohana/system/guide/kohana/files/messages.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Messages
|
||||
|
||||
Kohana has a robust key based lookup system so you can define system messages.
|
||||
|
||||
## Getting a message
|
||||
|
||||
Use the Kohana::message() method to get a message key:
|
||||
|
||||
Kohana::message('forms', 'foobar');
|
||||
|
||||
This will look in the `messages/forms.php` file for the `foobar` key:
|
||||
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'foobar' => 'Hello, world!',
|
||||
);
|
||||
|
||||
You can also look in subfolders and sub-keys:
|
||||
|
||||
Kohana::message('forms/contact', 'foobar.bar');
|
||||
|
||||
This will look in the `messages/forms/contact.php` for the `[foobar][bar]` key:
|
||||
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'foobar' => array(
|
||||
'bar' => 'Hello, world!',
|
||||
),
|
||||
);
|
||||
|
||||
## Notes
|
||||
|
||||
* Don't use __() in your messages files, as these files can be cached and will not work properly.
|
||||
* Messages are merged by the cascading file system, not overwritten like classes and views.
|
27
includes/kohana/system/guide/kohana/flow.md
Normal file
27
includes/kohana/system/guide/kohana/flow.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Request Flow
|
||||
|
||||
Every application follows the same flow:
|
||||
|
||||
1. Application starts from `index.php`.
|
||||
1. The application, module, and system paths are set. (`APPPATH`, `MODPATH`, and `SYSPATH`)
|
||||
2. Error reporting levels are set.
|
||||
3. Install file is loaded, if it exists.
|
||||
4. The bootstrap file, `APPPATH/bootstrap.php`, is included.
|
||||
2. Once we are in `bootstrap.php`:
|
||||
6. The [Kohana] class is loaded.
|
||||
7. [Kohana::init] is called, which sets up error handling, caching, and logging.
|
||||
8. [Kohana_Config] readers and [Kohana_Log] writers are attached.
|
||||
9. [Kohana::modules] is called to enable additional modules.
|
||||
* Module paths are added to the [cascading filesystem](files).
|
||||
* Includes each module's `init.php` file, if it exists.
|
||||
* The `init.php` file can perform additional environment setup, including adding routes.
|
||||
10. [Route::set] is called multiple times to define the [application routes](routing).
|
||||
11. [Request::instance] is called to start processing the request.
|
||||
1. Checks each route that has been set until a match is found.
|
||||
2. Creates the controller instance and passes the request to it.
|
||||
3. Calls the [Controller::before] method.
|
||||
4. Calls the controller action, which generates the request response.
|
||||
5. Calls the [Controller::after] method.
|
||||
* The above 5 steps can be repeated multiple times when using [HMVC sub-requests](requests).
|
||||
3. Application flow returns to index.php
|
||||
12. The main [Request] response is displayed
|
135
includes/kohana/system/guide/kohana/fragments.md
Normal file
135
includes/kohana/system/guide/kohana/fragments.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# Fragments
|
||||
|
||||
Fragments are a quick and simple way to cache HTML or other output. Fragments are not useful for caching objects or raw database results, in which case you should use a more robust caching method, which can be achieved with the [Cache module](../cache). Fragments use [Kohana::cache()] and will be placed in the cache directory (`application/cache` by default).
|
||||
|
||||
You should use Fragment (or any caching solution) when reading the cache is faster than reprocessing the result. Reading and parsing a remote file, parsing a complicated template, calculating something, etc.
|
||||
|
||||
Fragments are typically used in view files.
|
||||
|
||||
## Usage
|
||||
|
||||
Fragments are used by calling [Fragment::load()] in an `if` statement at the beginning of what you want cached, and [Fragment::save()] at the end. They use [output buffering](http://www.php.net/manual/en/function.ob-start.php) to capture the output between the two function calls.
|
||||
|
||||
You can specify the lifetime (in seconds) of the Fragment using the second parameter of [Fragment::load()]. The default lifetime is 30 seconds. You can use the [Date] helper to make more readable times.
|
||||
|
||||
Fragments will store a different cache for each language (using [I18n]) if you pass `true` as the third parameter to [Fragment::load()];
|
||||
|
||||
You can force the deletion of a Fragment using [Fragment::delete()], or specify a lifetime of 0.
|
||||
|
||||
~~~
|
||||
// Cache for 5 minutes, and cache each language
|
||||
if ( ! Fragment::load('foobar', Date::MINUTE * 5, true))
|
||||
{
|
||||
// Anything that is echo'ed here will be saved
|
||||
Fragment::save();
|
||||
}
|
||||
~~~
|
||||
|
||||
## Example: Calculating Pi
|
||||
|
||||
In this example we will calculate pi to 1000 places, and cache the result using a fragment. The first time you run this it will probably take a few seconds, but subsequent loads will be much faster, until the fragment lifetime runs out.
|
||||
|
||||
~~~
|
||||
if ( ! Fragment::load('pi1000', Date::HOUR * 4))
|
||||
{
|
||||
// Change function nesting limit
|
||||
ini_set('xdebug.max_nesting_level',1000);
|
||||
|
||||
// Source: http://mgccl.com/2007/01/22/php-calculate-pi-revisited
|
||||
function bcfact($n)
|
||||
{
|
||||
return ($n == 0 || $n== 1) ? 1 : bcmul($n,bcfact($n-1));
|
||||
}
|
||||
function bcpi($precision)
|
||||
{
|
||||
$num = 0;$k = 0;
|
||||
bcscale($precision+3);
|
||||
$limit = ($precision+3)/14;
|
||||
while($k < $limit)
|
||||
{
|
||||
$num = bcadd($num, bcdiv(bcmul(bcadd('13591409',bcmul('545140134', $k)),bcmul(bcpow(-1, $k), bcfact(6*$k))),bcmul(bcmul(bcpow('640320',3*$k+1),bcsqrt('640320')), bcmul(bcfact(3*$k), bcpow(bcfact($k),3)))));
|
||||
++$k;
|
||||
}
|
||||
return bcdiv(1,(bcmul(12,($num))),$precision);
|
||||
}
|
||||
|
||||
echo bcpi(1000);
|
||||
|
||||
Fragment::save();
|
||||
}
|
||||
|
||||
echo View::factory('profiler/stats');
|
||||
|
||||
?>
|
||||
~~~
|
||||
|
||||
## Example: Recent Wikipedia edits
|
||||
|
||||
In this example we will use the [Feed] class to retrieve and parse an RSS feed of recent edits to [http://en.wikipedia.org](http://en.wikipedia.org), then use Fragment to cache the results.
|
||||
|
||||
~~~
|
||||
$feed = "http://en.wikipedia.org/w/index.php?title=Special:RecentChanges&feed=rss";
|
||||
$limit = 50;
|
||||
|
||||
// Displayed feeds are cached for 30 seconds (default)
|
||||
if ( ! Fragment::load('rss:'.$feed)):
|
||||
|
||||
// Parse the feed
|
||||
$items = Feed::parse($feed, $limit);
|
||||
|
||||
foreach ($items as $item):
|
||||
|
||||
// Convert $item to object
|
||||
$item = (object) $item;
|
||||
|
||||
echo HTML::anchor($item->link,$item->title);
|
||||
|
||||
?>
|
||||
<blockquote>
|
||||
<p>author: <?php echo $item->creator ?></p>
|
||||
<p>date: <?php echo $item->pubDate ?></p>
|
||||
</blockquote>
|
||||
<?php
|
||||
|
||||
endforeach;
|
||||
|
||||
Fragment::save();
|
||||
|
||||
endif;
|
||||
|
||||
echo View::factory('profiler/stats');
|
||||
~~~
|
||||
|
||||
## Example: Nested Fragments
|
||||
|
||||
You can nest fragments with different lifetimes to provide more specific control. For example, let's say your page has lots of dynamic content so we want to cache it with a lifetime of five minutes, but one of the pieces takes much longer to generate, and only changes every hour anyways. No reason to generate it every 5 minutes, so we will use a nested fragment.
|
||||
|
||||
[!!] If a nested fragment has a shorter lifetime than the parent, it will only get processed when the parent has expired.
|
||||
|
||||
~~~
|
||||
// Cache homepage for five minutes
|
||||
if ( ! Fragment::load('homepage', Date::MINUTE * 5)):
|
||||
|
||||
echo "<p>Home page stuff</p>";
|
||||
|
||||
// Pretend like we are actually doing something :)
|
||||
sleep(2);
|
||||
|
||||
// Cache this every hour since it doesn't change as often
|
||||
if ( ! Fragment::load('homepage-subfragment', Date::HOUR)):
|
||||
|
||||
echo "<p>Home page special thingy</p>";
|
||||
|
||||
// Pretend like this takes a long time
|
||||
sleep(5);
|
||||
|
||||
Fragment::save(); endif;
|
||||
|
||||
echo "<p>More home page stuff</p>";
|
||||
|
||||
Fragment::save();
|
||||
|
||||
endif;
|
||||
|
||||
echo View::factory('profiler/stats');
|
||||
~~~
|
53
includes/kohana/system/guide/kohana/helpers.md
Normal file
53
includes/kohana/system/guide/kohana/helpers.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Helpers
|
||||
|
||||
Kohana comes with many static "helper" functions to make certain tasks easier.
|
||||
|
||||
You can make your own helpers by simply making a class and putting it in the `classes` directory, and you can also extend any helper to modify or add new functions using transparent extension.
|
||||
|
||||
- **[Arr]** - Array functions. Get an array key or default to a set value, get an array key by path, etc.
|
||||
|
||||
- **[CLI]** - Parse command line options.
|
||||
|
||||
- **[Cookie]** - Covered in more detail on the [Cookies](cookies) page.
|
||||
|
||||
- **[Date]** - Useful date functions and constants. Time between two dates, convert between am/pm and military, date offset, etc.
|
||||
|
||||
- **[Encrypt]** - Covered in more detail on the [Security](security) page.
|
||||
|
||||
- **[Feed]** - Parse and create RSS feeds.
|
||||
|
||||
- **[File]** - Get file type by mime, split and merge a file into small pieces.
|
||||
|
||||
- **[Form]** - Create HTML form elements.
|
||||
|
||||
- **[Fragment]** - Simple file based caching. Covered in more detail on the [Fragments](fragments) page.
|
||||
|
||||
- **[HTML]** - Useful HTML functions. Encode, obfuscate, create script, anchor, and image tags, etc.
|
||||
|
||||
- **[I18n]** - Internationalization helper for creating multilanguage sites.
|
||||
|
||||
- **[Inflector]** - Change a word into plural or singular form, camelize or humanize a phrase, etc.
|
||||
|
||||
- **[Kohana]** - The Kohana class is also a helper. Debug variables (like print_r but better), file loading, etc.
|
||||
|
||||
- **[Num]** - Provides locale aware formating and english ordinals (th, st, nd, etc).
|
||||
|
||||
- **[Profiler]** - Covered in more detail on the [Profiling](profiling) page.
|
||||
|
||||
- **[Remote]** - Remote server access helper using [CURL](http://php.net/curl).
|
||||
|
||||
- **[Request]** - Get the current request url, create expire tags, send a file, get the user agent, etc.
|
||||
|
||||
- **[Route]** - Create routes, create an internal link using a route.
|
||||
|
||||
- **[Security]** - Covered in more detail on the [Security](security) page.
|
||||
|
||||
- **[Session]** - Covered in more detail on the [Sessions](sessions) page.
|
||||
|
||||
- **[Text]** - Autolink, prevent window words, convert a number to text, etc.
|
||||
|
||||
- **[URL]** - Create a relative or absolute URL, make a URL-safe title, etc.
|
||||
|
||||
- **[UTF8]** - Provides multi-byte aware string functions like strlen, strpos, substr, etc.
|
||||
|
||||
- **[Upload]** - Helper for uploading files from a form.
|
19
includes/kohana/system/guide/kohana/index.md
Normal file
19
includes/kohana/system/guide/kohana/index.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# What is Kohana?
|
||||
|
||||
Kohana is an open source, [object oriented](http://en.wikipedia.org/wiki/Object-oriented_programming) [MVC](http://en.wikipedia.org/wiki/Model–view–controller "Model View Controller") [web framework](http://en.wikipedia.org/wiki/Web_application_framework) built using [PHP5](http://php.net/manual/intro-whatis "PHP Hypertext Preprocessor") by a team of volunteers that aims to be swift, secure, and small.
|
||||
|
||||
[!!] Kohana is licensed under a [BSD license](http://kohanaframework.org/license), so you can legally use it for any kind of open source, commercial, or personal project.
|
||||
|
||||
## What makes Kohana great?
|
||||
|
||||
Anything can be extended using the unique [filesystem](files) design, little or no [configuration](config) is necessary, [error handling](errors) helps locate the source of errors quickly, and [debugging](debugging) and [profiling](profiling) provide insight into the application.
|
||||
|
||||
To help secure your applications, tools for [input validation](security/validation), [signed cookies](security/cookies), [form] and [HTML] generators are all included. The [database](security/database) layer provides protection against [SQL injection](http://wikipedia.org/wiki/SQL_injection). Of course, all official code is carefully written and reviewed for security.
|
||||
|
||||
## Contribute to the Documentation
|
||||
|
||||
We are working very hard to provide complete documentation. To help improve the guide, please [fork the userguide](http://github.com/kohana/userguide), make your changes, and send a pull request. If you are not familiar with Git, you can also submit a [feature request](http://dev.kohanaframework.org/projects/kohana3/issues) (requires registration).
|
||||
|
||||
## Unofficial Documentation
|
||||
|
||||
If you are having trouble finding an answer here, have a look through the [unofficial wiki](http://kerkness.ca/kowiki/doku.php). Your answer may also be found by searching the [forum](http://forum.kohanaframework.org/) or [Stack Overflow](http://stackoverflow.com/questions/tagged/kohana) followed by asking your question on either. Additionally, you can chat with the community of developers on the freenode [#kohana](irc://irc.freenode.net/kohana) IRC channel.
|
45
includes/kohana/system/guide/kohana/install.md
Normal file
45
includes/kohana/system/guide/kohana/install.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Installation
|
||||
|
||||
1. Download the latest **stable** release from the [Kohana website](http://kohanaframework.org/).
|
||||
2. Unzip the downloaded package to create a `kohana` directory.
|
||||
3. Upload the contents of this folder to your webserver.
|
||||
4. Open `application/bootstrap.php` and make the following changes:
|
||||
- Set the default [timezone](http://php.net/timezones) for your application.
|
||||
|
||||
~~~
|
||||
// Example of changing timezone from Chicago to Sao Paulo, Brazil
|
||||
date_default_timezone_set('America/Sao_Paulo');
|
||||
~~~
|
||||
- Set the `base_url` in the [Kohana::init] call to reflect the location of the kohana folder on your server relative to the document root.
|
||||
|
||||
~~~
|
||||
// Example of kohana's installation at /var/www/mywebsite and
|
||||
// Apache's DocumentRoot configured to /var/www
|
||||
Kohana::init(array(
|
||||
'base_url' => '/mywebsite',
|
||||
));
|
||||
~~~
|
||||
6. Make sure the `application/cache` and `application/logs` directories are writable by the web server.
|
||||
|
||||
~~~
|
||||
sudo chmod 777 -R application/cache
|
||||
sudo chmod 777 -R application/logs
|
||||
~~~
|
||||
|
||||
7. Test your installation by opening the URL you set as the `base_url` in your favorite browser.
|
||||
|
||||
[!!] Depending on your platform, the installation's subdirs may have lost their permissions thanks to zip extraction. Chmod them all to 755 by running `find . -type d -exec chmod 0755 {} \;` from the root of your Kohana installation.
|
||||
|
||||
You should see the installation page. If it reports any errors, you will need to correct them before continuing.
|
||||
|
||||

|
||||
|
||||
Once your install page reports that your environment is set up correctly you need to either rename or delete `install.php` in the root directory. Kohana is now installed and you should see the output of the welcome controller:
|
||||
|
||||

|
||||
|
||||
## Installing Kohana From GitHub
|
||||
|
||||
The [source code](http://github.com/kohana/kohana) for Kohana is hosted with [GitHub](http://github.com). To install Kohana using the github source code first you need to install [git](http://git-scm.com/). Visit [http://help.github.com](http://help.github.com) for details on how to install git on your platform.
|
||||
|
||||
[!!] For more information on installing Kohana using git submodules, see the [Working with Git](tutorials/git) tutorial.
|
49
includes/kohana/system/guide/kohana/menu.md
Normal file
49
includes/kohana/system/guide/kohana/menu.md
Normal file
@@ -0,0 +1,49 @@
|
||||
## [Kohana]()
|
||||
|
||||
- Getting Started
|
||||
- [Installation](install)
|
||||
- [Conventions and Style](conventions)
|
||||
- [Model View Controller](mvc)
|
||||
- [Controllers](mvc/controllers)
|
||||
- [Models](mvc/models)
|
||||
- [Views](mvc/views)
|
||||
- [Cascading Filesystem](files)
|
||||
- [Class Files](files/classes)
|
||||
- [Config Files](files/config)
|
||||
- [Translation Files](files/i18n)
|
||||
- [Message Files](files/messages)
|
||||
- [Configuration](config)
|
||||
- [Request Flow](flow)
|
||||
- [Bootstrap](bootstrap)
|
||||
- [Modules](modules)
|
||||
- [Routing](routing)
|
||||
- [Error Handling](errors)
|
||||
- [Tips & Common Mistakes](tips)
|
||||
- [Upgrading from v3.2](upgrading)
|
||||
- Basic Usage
|
||||
- [Debugging](debugging)
|
||||
- [Loading Classes](autoloading)
|
||||
- [Transparent Extension](extension)
|
||||
- [Helpers](helpers)
|
||||
- [Requests](requests)
|
||||
- [Sessions](sessions)
|
||||
- [Cookies](cookies)
|
||||
- [Fragments](fragments)
|
||||
- [Profiling](profiling)
|
||||
- [Security](security)
|
||||
- [XSS](security/xss)
|
||||
- [Validation](security/validation)
|
||||
- [Cookies](security/cookies)
|
||||
- [Database](security/database)
|
||||
- [Encryption](security/encryption)
|
||||
- [Deploying](security/deploying)
|
||||
- [Tutorials](tutorials)
|
||||
- [Hello World](tutorials/hello-world)
|
||||
- [Simple MVC](tutorials/simple-mvc)
|
||||
- [Custom Error Pages](tutorials/error-pages)
|
||||
- [Content Translation](tutorials/translation)
|
||||
- [Clean URLs](tutorials/clean-urls)
|
||||
- [Sharing Kohana](tutorials/sharing-kohana)
|
||||
- [Kohana as a Library](tutorials/library-kohana)
|
||||
- [Template Driven Site](tutorials/templates)
|
||||
- [Working with Git](tutorials/git)
|
40
includes/kohana/system/guide/kohana/modules.md
Normal file
40
includes/kohana/system/guide/kohana/modules.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Modules
|
||||
|
||||
Modules are simply an addition to the [Cascading Filesystem](files). A module can add any kind of file (controllers, views, classes, config files, etc.) to the filesystem available to Kohana (via [Kohana::find_file]). This is useful to make any part of your application more transportable or shareable between different apps. For example, creating a new modeling system, a search engine, a css/js manager, etc.
|
||||
|
||||
## Where to find modules
|
||||
|
||||
Kolanos has created [kohana-universe](http://github.com/kolanos/kohana-universe/tree/master/modules/), a fairly comprehensive list of modules that are available on Github. To get your module listed there, send him a message via Github.
|
||||
|
||||
Mon Geslani created a [very nice site](http://kohana.mongeslani.com/) that allows you to sort Github modules by activity, watchers, forks, etc. It seems to not be as comprehensive as kohana-universe.
|
||||
|
||||
Andrew Hutchings has created [kohana-modules](http://www.kohana-modules.com) which is similar to the above sites.
|
||||
|
||||
## Enabling modules
|
||||
|
||||
Modules are enabled by calling [Kohana::modules] and passing an array of `'name' => 'path'`. The name isn't important, but the path obviously is. A module's path does not have to be in `MODPATH`, but usually is. You can only call [Kohana::modules] once.
|
||||
|
||||
Kohana::modules(array(
|
||||
'auth' => MODPATH.'auth', // Basic authentication
|
||||
'cache' => MODPATH.'cache', // Caching with multiple backends
|
||||
'codebench' => MODPATH.'codebench', // Benchmarking tool
|
||||
'database' => MODPATH.'database', // Database access
|
||||
'image' => MODPATH.'image', // Image manipulation
|
||||
'orm' => MODPATH.'orm', // Object Relationship Mapping
|
||||
'oauth' => MODPATH.'oauth', // OAuth authentication
|
||||
'pagination' => MODPATH.'pagination', // Paging of results
|
||||
'unittest' => MODPATH.'unittest', // Unit testing
|
||||
'userguide' => MODPATH.'userguide', // User guide and API documentation
|
||||
));
|
||||
|
||||
## Init.php
|
||||
|
||||
When a module is activated, if an `init.php` file exists in that module's directory, it is included. This is the ideal place to have a module include routes or other initialization necessary for the module to function. The Userguide and Codebench modules have init.php files you can look at.
|
||||
|
||||
## How modules work
|
||||
|
||||
A file in an enabled module is virtually the same as having that exact file in the same place in the application folder. The main difference being that it can be overwritten by a file of the same name in a higher location (a module enabled after it, or the application folder) via the [Cascading Filesystem](files). It also provides an easy way to organize and share your code.
|
||||
|
||||
## Creating your own module
|
||||
|
||||
To create a module simply create a folder (usually in `DOCROOT/modules`) and place the files you want to be in the module there, and activate that module in your bootstrap. To share your module, you can upload it to [Github](http://github.com). You can look at examples of modules made by [Kohana](http://github.com/kohana) or [other users](#where-to-find-modules).
|
3
includes/kohana/system/guide/kohana/mvc.md
Normal file
3
includes/kohana/system/guide/kohana/mvc.md
Normal file
@@ -0,0 +1,3 @@
|
||||
<http://kohanaframework.org/guide/about.mvc>
|
||||
|
||||
Discuss the MVC pattern, as it pertains to Kohana. Perhaps have an image, etc.
|
181
includes/kohana/system/guide/kohana/mvc/controllers.md
Normal file
181
includes/kohana/system/guide/kohana/mvc/controllers.md
Normal file
@@ -0,0 +1,181 @@
|
||||
# Controllers
|
||||
|
||||
A Controller is a class file that stands in between the models and the views in an application. It passes information on to the model when data needs to be changed and it requests information from the model when data needs to be loaded. Controllers then pass on the information of the model to the views where the final output can be rendered for the users. Controllers essentially control the flow of the application.
|
||||
|
||||
Controllers are called by the [Request::execute()] function based on the [Route] that the url matched. Be sure to read the [routing](routing) page to understand how to use routes to map urls to your controllers.
|
||||
|
||||
## Creating Controllers
|
||||
|
||||
In order to function, a controller must do the following:
|
||||
|
||||
* Reside in `classes/Controller` (or a sub-directory)
|
||||
* Filename must match the class name exactly, e.g. `Articles.php`
|
||||
* The class name must map to the filename (with `/` replaced with `_`) and each word is capitalized
|
||||
* Must have the Controller class as a (grand)parent
|
||||
|
||||
Some examples of controller names and file locations:
|
||||
|
||||
// classes/Controller/Foobar.php
|
||||
class Controller_Foobar extends Controller {
|
||||
|
||||
// classes/Controller/Admin.php
|
||||
class Controller_Admin extends Controller {
|
||||
|
||||
Controllers can be in sub-folders:
|
||||
|
||||
// classes/Controller/Baz/Bar.php
|
||||
class Controller_Baz_Bar extends Controller {
|
||||
|
||||
// classes/Controller/Product/Category.php
|
||||
class Controller_Product_Category extends Controller {
|
||||
|
||||
[!!] Note that controllers in sub-folders can not be called by the default route, you will need to define a route that has a [directory](routing#directory) param or sets a default value for directory.
|
||||
|
||||
Controllers can extend other controllers.
|
||||
|
||||
// classes/Controller/Users.php
|
||||
class Controller_Users extends Controller_Template
|
||||
|
||||
// classes/Controller/Api.php
|
||||
class Controller_Api extends Controller_REST
|
||||
|
||||
[!!] [Controller_Template] is an example controller provided in Kohana.
|
||||
|
||||
You can also have a controller extend another controller to share common things, such as requiring you to be logged in to use all of those controllers.
|
||||
|
||||
// classes/Controller/Admin.php
|
||||
class Controller_Admin extends Controller {
|
||||
// This controller would have a before() that checks if the user is logged in
|
||||
|
||||
// classes/Controller/Admin/Plugins.php
|
||||
class Controller_Admin_Plugins extends Controller_Admin {
|
||||
// Because this controller extends Controller_Admin, it would have the same logged in check
|
||||
|
||||
## $this->request
|
||||
|
||||
Every controller has the `$this->request` property which is the [Request] object that called the controller. You can use this to get information about the current request, as well as set the response body via `$this->response->body($ouput)`.
|
||||
|
||||
Here is a partial list of the properties and methods available to `$this->request`. These can also be accessed via `Request::instance()`, but `$this->request` is provided as a shortcut. See the [Request] class for more information on any of these.
|
||||
|
||||
Property/method | What it does
|
||||
--- | ---
|
||||
[$this->request->route()](../api/Request#property:route) | The [Route] that matched the current request url
|
||||
[$this->request->directory()](../api/Request#property:directory), <br /> [$this->request->controller](../api/Request#property:controller), <br /> [$this->request->action](../api/Request#property:action) | The directory, controller and action that matched for the current route
|
||||
[$this->request->param()](../api/Request#param) | Any other params defined in your route
|
||||
|
||||
## $this->response
|
||||
[$this->response->body()](../api/Response#property:body) | The content to return for this request
|
||||
[$this->response->status()](../api/Response#property:status) | The HTTP status for the request (200, 404, 500, etc.)
|
||||
[$this->response->headers()](../api/Response#property:headers) | The HTTP headers to return with the response
|
||||
|
||||
|
||||
## Actions
|
||||
|
||||
You create actions for your controller by defining a public function with an `action_` prefix. Any method that is not declared as `public` and prefixed with `action_` can NOT be called via routing.
|
||||
|
||||
An action method will decide what should be done based on the current request, it *controls* the application. Did the user want to save a blog post? Did they provide the necessary fields? Do they have permission to do that? The controller will call other classes, including models, to accomplish this. Every action should set `$this->response->body($view)` to the [view file](mvc/views) to be sent to the browser, unless it redirected or otherwise ended the script earlier.
|
||||
|
||||
A very basic action method that simply loads a [view](mvc/views) file.
|
||||
|
||||
public function action_hello()
|
||||
{
|
||||
$this->response->body(View::factory('hello/world')); // This will load views/hello/world.php
|
||||
}
|
||||
|
||||
### Parameters
|
||||
|
||||
Parameters are accessed by calling `$this->request->param('name')` where `name` is the name defined in the route.
|
||||
|
||||
// Assuming Route::set('example','<controller>(/<action>(/<id>(/<new>)))');
|
||||
|
||||
public function action_foobar()
|
||||
{
|
||||
$id = $this->request->param('id');
|
||||
$new = $this->request->param('new');
|
||||
|
||||
If that parameter is not set it will be returned as NULL. You can provide a second parameter to set a default value if that param is not set.
|
||||
|
||||
public function action_foobar()
|
||||
{
|
||||
// $id will be false if it was not supplied in the url
|
||||
$id = $this->request->param('user',FALSE);
|
||||
|
||||
### Examples
|
||||
|
||||
A view action for a product page.
|
||||
|
||||
public function action_view()
|
||||
{
|
||||
$product = new Model_Product($this->request->param('id'));
|
||||
|
||||
if ( ! $product->loaded())
|
||||
{
|
||||
throw HTTP_Exception::factory(404, 'Product not found!');
|
||||
}
|
||||
|
||||
$this->response->body(View::factory('product/view')
|
||||
->set('product', $product));
|
||||
}
|
||||
|
||||
A user login action.
|
||||
|
||||
public function action_login()
|
||||
{
|
||||
$view = View::factory('user/login');
|
||||
|
||||
if ($this->request->post())
|
||||
{
|
||||
// Try to login
|
||||
if (Auth::instance()->login($this->request->post('username'), $this->request->post('password')))
|
||||
{
|
||||
$this->redirect('home', 302);
|
||||
}
|
||||
|
||||
$view->errors = 'Invalid email or password';
|
||||
}
|
||||
|
||||
$this->response->body($view);
|
||||
}
|
||||
|
||||
## Before and after
|
||||
|
||||
You can use the `before()` and `after()` functions to have code executed before or after the action is executed. For example, you could check if the user is logged in, set a template view, loading a required file, etc.
|
||||
|
||||
For example, if you look in `Controller_Template` you can see that in the be
|
||||
|
||||
You can check what action has been requested (via `$this->request->action`) and do something based on that, such as requiring the user to be logged in to use a controller, unless they are using the login action.
|
||||
|
||||
// Checking auth/login in before, and redirecting if necessary:
|
||||
|
||||
Controller_Admin extends Controller {
|
||||
|
||||
public function before()
|
||||
{
|
||||
// If this user doesn't have the admin role, and is not trying to login, redirect to login
|
||||
if ( ! Auth::instance()->logged_in('admin') AND $this->request->action !== 'login')
|
||||
{
|
||||
$this->redirect('admin/login', 302);
|
||||
}
|
||||
}
|
||||
|
||||
public function action_login() {
|
||||
...
|
||||
|
||||
### Custom __construct() function
|
||||
|
||||
In general, you should not have to change the `__construct()` function, as anything you need for all actions can be done in `before()`. If you need to change the controller constructor, you must preserve the parameters or PHP will complain. This is so the Request object that called the controller is available. *Again, in most cases you should probably be using `before()`, and not changing the constructor*, but if you really, *really* need to it should look like this:
|
||||
|
||||
// You should almost never need to do this, use before() instead!
|
||||
|
||||
// Be sure Kohana_Request is in the params
|
||||
public function __construct(Request $request, Response $response)
|
||||
{
|
||||
// You must call parent::__construct at some point in your function
|
||||
parent::__construct($request, $response);
|
||||
|
||||
// Do whatever else you want
|
||||
}
|
||||
|
||||
## Extending other controllers
|
||||
|
||||
TODO: More description and examples of extending other controllers, multiple extension, etc.
|
35
includes/kohana/system/guide/kohana/mvc/models.md
Normal file
35
includes/kohana/system/guide/kohana/mvc/models.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Models
|
||||
|
||||
From Wikipedia:
|
||||
|
||||
> The model manages the behavior and data of the application domain,
|
||||
> responds to requests for information about its state (usually from the view),
|
||||
> and responds to instructions to change state (usually from the controller).
|
||||
|
||||
Creating a simple model:
|
||||
|
||||
class Model_Post extends Model
|
||||
{
|
||||
public function do_stuff()
|
||||
{
|
||||
// This is where you do domain logic...
|
||||
}
|
||||
}
|
||||
|
||||
If you want database access, have your model extend the Model_Database class:
|
||||
|
||||
class Model_Post extends Model_Database
|
||||
{
|
||||
public function do_stuff()
|
||||
{
|
||||
// This is where you do domain logic...
|
||||
}
|
||||
|
||||
public function get_stuff()
|
||||
{
|
||||
// Get stuff from the database:
|
||||
return $this->db->query(...);
|
||||
}
|
||||
}
|
||||
|
||||
If you want CRUD/ORM capabilities, see the [ORM Module](../../guide/orm)
|
153
includes/kohana/system/guide/kohana/mvc/views.md
Normal file
153
includes/kohana/system/guide/kohana/mvc/views.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# Views
|
||||
|
||||
Views are files that contain the display information for your application. This is most commonly HTML, CSS and Javascript but can be anything you require such as XML or JSON for AJAX output. The purpose of views is to keep this information separate from your application logic for easy reusability and cleaner code.
|
||||
|
||||
Views themselves can contain code used for displaying the data you pass into them. For example, looping through an array of product information and display each one on a new table row. Views are still PHP files so you can use any code you normally would. However, you should try to keep your views as "dumb" as possible and retreive all data you need in your controllers, then pass it to the view.
|
||||
|
||||
# Creating View Files
|
||||
|
||||
View files are stored in the `views` directory of the [filesystem](files). You can also create sub-directories within the `views` directory to organize your files. All of the following examples are reasonable view files:
|
||||
|
||||
APPPATH/views/home.php
|
||||
APPPATH/views/pages/about.php
|
||||
APPPATH/views/products/details.php
|
||||
MODPATH/error/views/errors/404.php
|
||||
MODPATH/common/views/template.php
|
||||
|
||||
## Loading Views
|
||||
|
||||
[View] objects will typically be created inside a [Controller](mvc/controllers) using the [View::factory] method. Typically the view is then assigned as the [Request::$response] property or to another view.
|
||||
|
||||
public function action_about()
|
||||
{
|
||||
$this->response->body(View::factory('pages/about'));
|
||||
}
|
||||
|
||||
When a view is assigned as the [Response::body], as in the example above, it will automatically be rendered when necessary. To get the rendered result of a view you can call the [View::render] method or just type cast it to a string. When a view is rendered, the view file is loaded and HTML is generated.
|
||||
|
||||
public function action_index()
|
||||
{
|
||||
$view = View::factory('pages/about');
|
||||
|
||||
// Render the view
|
||||
$about_page = $view->render();
|
||||
|
||||
// Or just type cast it to a string
|
||||
$about_page = (string) $view;
|
||||
|
||||
$this->response->body($about_page);
|
||||
}
|
||||
|
||||
## Variables in Views
|
||||
|
||||
Once view has been loaded, variables can be assigned to it using the [View::set] and [View::bind] methods.
|
||||
|
||||
public function action_roadtrip()
|
||||
{
|
||||
$view = View::factory('user/roadtrip')
|
||||
->set('places', array('Rome', 'Paris', 'London', 'New York', 'Tokyo'));
|
||||
->bind('user', $this->user);
|
||||
|
||||
// The view will have $places and $user variables
|
||||
$this->response->body($view);
|
||||
}
|
||||
|
||||
[!!] The only difference between `set()` and `bind()` is that `bind()` assigns the variable by reference. If you `bind()` a variable before it has been defined, the variable will be created with a value of `NULL`.
|
||||
|
||||
You can also assign variables directly to the View object. This is identical to calling `set()`;
|
||||
|
||||
public function action_roadtrip()
|
||||
{
|
||||
$view = View::factory('user/roadtrip');
|
||||
|
||||
$view->places = array('Rome', 'Paris', 'London', 'New York', 'Tokyo');
|
||||
$view->user = $this->user;
|
||||
|
||||
// The view will have $places and $user variables
|
||||
$this->response->body($view);
|
||||
}
|
||||
|
||||
### Global Variables
|
||||
|
||||
An application may have several view files that need access to the same variables. For example, to display a page title in both the header of your template and in the body of the page content. You can create variables that are accessible in any view using the [View::set_global] and [View::bind_global] methods.
|
||||
|
||||
// Assign $page_title to all views
|
||||
View::bind_global('page_title', $page_title);
|
||||
|
||||
If the application has three views that are rendered for the home page: `template`, `template/sidebar`, and `pages/home`. First, an abstract controller to create the template will be created:
|
||||
|
||||
abstract class Controller_Website extends Controller_Template {
|
||||
|
||||
public $page_title;
|
||||
|
||||
public function before()
|
||||
{
|
||||
parent::before();
|
||||
|
||||
// Make $page_title available to all views
|
||||
View::bind_global('page_title', $this->page_title);
|
||||
|
||||
// Load $sidebar into the template as a view
|
||||
$this->template->sidebar = View::factory('template/sidebar');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Next, the home controller will extend `Controller_Website`:
|
||||
|
||||
class Controller_Home extends Controller_Website {
|
||||
|
||||
public function action_index()
|
||||
{
|
||||
$this->page_title = 'Home';
|
||||
|
||||
$this->template->content = View::factory('pages/home');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
## Views Within Views
|
||||
|
||||
If you want to include another view within a view, there are two choices. By calling [View::factory] you can sandbox the included view. This means that you will have to provide all of the variables to the view using [View::set] or [View::bind]:
|
||||
|
||||
// In your view file:
|
||||
|
||||
// Only the $user variable will be available in "views/user/login.php"
|
||||
<?php echo View::factory('user/login')->bind('user', $user) ?>
|
||||
|
||||
The other option is to include the view directly, which makes all of the current variables available to the included view:
|
||||
|
||||
// In your view file:
|
||||
|
||||
// Any variable defined in this view will be included in "views/message.php"
|
||||
<?php include Kohana::find_file('views', 'user/login') ?>
|
||||
|
||||
You can also assign a variable of your parent view to be the child view from within your controller. For example:
|
||||
|
||||
// In your controller:
|
||||
|
||||
public functin action_index()
|
||||
{
|
||||
$view = View::factory('common/template);
|
||||
|
||||
$view->title = "Some title";
|
||||
$view->body = View::factory('pages/foobar');
|
||||
}
|
||||
|
||||
// In views/common/template.php:
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title><?php echo $title></title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<?php echo $body ?>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Of course, you can also load an entire [Request] within a view:
|
||||
|
||||
<?php echo Request::factory('user/login')->execute() ?>
|
||||
|
||||
This is an example of \[HMVC], which makes it possible to create and read calls to other URLs within your application.
|
54
includes/kohana/system/guide/kohana/profiling.md
Normal file
54
includes/kohana/system/guide/kohana/profiling.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Profiling
|
||||
|
||||
Kohana provides a very simple way to display statistics about your application:
|
||||
|
||||
1. Common [Kohana] method calls, such as [Kohana::find_file()].
|
||||
2. Requests. Including the main request, as well as any sub-requests.
|
||||
3. [Database] queries
|
||||
4. Average execution times for your application
|
||||
|
||||
[!!] In order for profiling to work, the `profile` setting must be `TRUE` in your [Kohana::init()] call in your bootstrap.
|
||||
|
||||
## Profiling your code
|
||||
|
||||
You can easily add profiling to your own functions and code. This is done using the [Profiler::start()] function. The first parameter is the group, the second parameter is the name of the benchmark.
|
||||
|
||||
public function foobar($input)
|
||||
{
|
||||
// Be sure to only profile if it's enabled
|
||||
if (Kohana::$profiling === TRUE)
|
||||
{
|
||||
// Start a new benchmark
|
||||
$benchmark = Profiler::start('Your Category', __FUNCTION__);
|
||||
}
|
||||
|
||||
// Do some stuff
|
||||
|
||||
if (isset($benchmark))
|
||||
{
|
||||
// Stop the benchmark
|
||||
Profiler::stop($benchmark);
|
||||
}
|
||||
|
||||
return $something;
|
||||
}
|
||||
|
||||
## How to read the profiling report
|
||||
|
||||
The benchmarks are sorted into groups. Each benchmark will show its name, how many times it was run (show in parenthesis after the benchmark name), and then the min, max, average, and total time and memory spent on that benchmark. The total column will have shaded backgrounds to show the relative times between benchmarks in the same group.
|
||||
|
||||
At the very end is a group called "Application Execution". This keeps track of how long each execution has taken. The number in parenthesis is how many executions are being compared. It shows the fastest, slowest, and average time and memory usage of the last several requsets. The last box is the time and memory usage of the current request.
|
||||
|
||||
((This could use a picture of a profiler with some database queries, etc. with annotations to point out each area as just described.))
|
||||
|
||||
## Displaying the profiler
|
||||
|
||||
You can display or collect the current [profiler] statistics at any time:
|
||||
|
||||
<?php echo View::factory('profiler/stats') ?>
|
||||
|
||||
## Preview
|
||||
|
||||
(This is the actual profiler stats for this page.)
|
||||
|
||||
{{profiler/stats}}
|
150
includes/kohana/system/guide/kohana/requests.md
Normal file
150
includes/kohana/system/guide/kohana/requests.md
Normal file
@@ -0,0 +1,150 @@
|
||||
# Requests
|
||||
|
||||
Kohana includes a flexible HMVC request system. It supports out of the box support for internal requests and external requests.
|
||||
|
||||
HMVC stands for `Hierarchical Model View Controller` and basically means requests can each have MVC triads called from inside each other.
|
||||
|
||||
The Request object in Kohana is HTTP/1.1 compliant.
|
||||
|
||||
## Creating Requests
|
||||
|
||||
Creating a request is very easy:
|
||||
|
||||
### Internal Requests
|
||||
|
||||
An internal request is a request calling to the internal application. It utilizes [routes](routing) to direct the application based on the URI that is passed to it. A basic internal request might look something like:
|
||||
|
||||
$request = Request::factory('welcome');
|
||||
|
||||
In this example, the URI is 'welcome'.
|
||||
|
||||
#### The initial request
|
||||
|
||||
Since Kohana uses HMVC, you can call many requests inside each other. The first request (usually called from `index.php`) is called the "initial request". You can access this request via:
|
||||
|
||||
Request::initial();
|
||||
|
||||
You should only use this method if you are absolutely sure you want the initial request. Otherwise you should use the `Request::current()` method.
|
||||
|
||||
#### Sub-requests
|
||||
|
||||
You can call a request at any time in your application by using the `Request::factory()` syntax. All of these requests will be considered sub-requests.
|
||||
|
||||
Other than this difference, they are exactly the same. You can detect if the request is a sub-request in your controller with the is_initial() method:
|
||||
|
||||
$sub_request = ! $this->request->is_initial()
|
||||
|
||||
### External Requests
|
||||
|
||||
An external request calls out to a third party website.
|
||||
|
||||
You can use this to scrape HTML from a remote site, or make a REST call to a third party API:
|
||||
|
||||
// This uses GET
|
||||
$request = Request::factory('http://www.google.com/');
|
||||
|
||||
// This uses PUT
|
||||
$request = Request::factory('http://example.com/put_api')->method(Request::PUT)->body(json_encode('the body'))->headers('Content-Type', 'application/json');
|
||||
|
||||
// This uses POST
|
||||
$request = Request::factory('http://example.com/post_api')->method(Request::POST)->post(array('foo' => 'bar', 'bar' => 'baz'));
|
||||
|
||||
## Executing Requests
|
||||
|
||||
To execute a request, use the `execute()` method on it. This will give you a [response](responses) object.
|
||||
|
||||
$request = Request::factory('welcome');
|
||||
$response = $request->execute();
|
||||
|
||||
### Header callbacks
|
||||
The request client supports header callbacks - an array of callbacks that will be triggered when a specified header is included in the response from a server. Header callbacks provide a powerful way to deal with scenarios including authentication, rate limiting, redirects and other application-specific use cases:
|
||||
|
||||
$request = Request::factory('http://example.com/user', array(
|
||||
'header_callbacks' => array(
|
||||
'Content-Encoding' =>
|
||||
function (Request $request, Response $response, Request_Client $client)
|
||||
{
|
||||
// Uncompress the response
|
||||
$response->body(GZIP::expand($response->body()));
|
||||
},
|
||||
'X-Rate-Limited' =>
|
||||
function (Request $request, Response $response, Request_Client $client)
|
||||
{
|
||||
// Log the rate limit event
|
||||
// And perhaps set a deadlock in cache to prevent further requests
|
||||
},
|
||||
'WWW-Authenticate' =>
|
||||
function (Request $request, Response $response, Request_Client $client)
|
||||
{
|
||||
// Execute a request to refresh your OAuth token somehow
|
||||
// Have the original request resent
|
||||
return Request::factory($request->uri())
|
||||
->query($request->query())
|
||||
->headers('Authorization', 'token'.$token);
|
||||
}));
|
||||
|
||||
Where multiple headers are present in the response, callbacks will be executed in sequence. Callbacks can be any valid PHP callback type and have three possible return types:
|
||||
|
||||
Type | Function
|
||||
------------------|---------
|
||||
[Request] object | If a new request is returned, the request client will automatically assign properties, callbacks etc to match the original request and then execute the request. No further callbacks will be triggered for the original request, but the new request may trigger callbacks when executed.
|
||||
[Response] object | If the callback returns a new response instance it will be returned to the application. No further callbacks will be triggered for the original request. The callback is responsible for setting any relevant callbacks and properties for the request it executes
|
||||
NULL | The callback can, if required, modify the provided Response object and return NULL. The modified response object will be passed into subsequent callbacks.
|
||||
|
||||
#### Nested requests
|
||||
If your callback returns a new Request object, the request client will apply the same callback and property definitions to it before execution. This allows for nested requests - for example, you might need to re-authenticate before submitting a POST request and then being redirected to a new location. To avoid infinite recursion and fatal errors, the request client keeps track of the number of subrequests and will throw a [Request_Client_Recursion_Exception] if the recursion gets too deep. This behaviour is controlled by two properties: [Request_Client::callback_depth()] and [Request_Client::max_callback_depth()]. The default limit is 5 subrequests.
|
||||
|
||||
If your callback executes a new request itself and returns the response, it is responsible for dealing with any callbacks and request nesting itself. You may find the [Request_Client::assign_client_properties()] method useful in this case.
|
||||
|
||||
#### Callback parameters
|
||||
Arbitrary parameters can be passed to the callbacks through the [Request_Client::callback_params()] property:
|
||||
|
||||
$request = Request::factory('http://example.com/foo', array(
|
||||
'header_callbacks' => array(
|
||||
'X-Custom-1' =>
|
||||
function (Request $request, Response $response, Request_Client $client)
|
||||
{
|
||||
// Do something that needs an external parameter
|
||||
if ($client->callback_params('foo') == 'bar')
|
||||
{
|
||||
// etc
|
||||
}
|
||||
},
|
||||
)
|
||||
'callback_params' => array(
|
||||
'foo' => 'bar'
|
||||
)
|
||||
));
|
||||
|
||||
// later on
|
||||
$request->client()->callback_params('foo',FALSE);
|
||||
|
||||
As with nested requests, callback_params will automatically be passed to subrequests if the callback returns a new Request object. If the callback returns a Response object, it is responsible for passing on any relevant parameters.
|
||||
|
||||
#### Following redirects
|
||||
The request client ships with a standard callback to automatically follow redirects - [Request_Client::on_header_location()]. This will recursively follow redirects that are specified with a Location header and a status code in 201, 301, 302, 303, 307. This behaviour is disabled by default, but can be enabled by passing a set of options to the Request's constructor:
|
||||
|
||||
$request = Request::factory('http://example.com/redirectme', array(
|
||||
'follow' => TRUE));
|
||||
|
||||
[!!] If you define additional header callbacks of your own, you will need to include the 'Location' callback in your callbacks array.
|
||||
|
||||
A number of options are available to control the behaviour of the [Request_Client] when following redirects.
|
||||
|
||||
Option |Default |Function
|
||||
-----------------|------------------------|---------
|
||||
follow | FALSE |Whether to follow redirects
|
||||
follow_headers | array('Authorization') |The keys of headers that will be re-sent with the redirected request
|
||||
strict_redirect | TRUE |Whether to use the original request method following to a 302 redirect (see below)
|
||||
|
||||
[!!] HTTP/1.1 specifies that a 302 redirect should be followed using the original request method. However, the vast majority of clients and servers get this wrong, with 302 widely used for 'POST - 302 redirect - GET' patterns. By default, Kohana's client is fully compliant with the HTTP spec. If you need to interact with non-compliant third party sites you may need to set strict_redirect FALSE to force the client to switch to GET following a 302 response.
|
||||
|
||||
You can easily alter this behaviour by configuring your own 'Location' header callback.
|
||||
|
||||
## Request Cache Control
|
||||
|
||||
You can cache requests for fast execution by passing a cache instance in as the second parameter of factory:
|
||||
|
||||
$request = Request::factory('welcome', array('cache'=>Cache::instance()));
|
||||
|
||||
TODO
|
257
includes/kohana/system/guide/kohana/routing.md
Normal file
257
includes/kohana/system/guide/kohana/routing.md
Normal file
@@ -0,0 +1,257 @@
|
||||
# Routing
|
||||
|
||||
Kohana provides a very powerful routing system. In essence, routes provide an interface between the urls and your controllers and actions. With the correct routes you could make almost any url scheme correspond to almost any arrangement of controllers, and you could change one without impacting the other.
|
||||
|
||||
As mentioned in the [Request Flow](flow) section, a request is handled by the [Request] class, which will look for a matching [Route] and load the appropriate controller to handle that request.
|
||||
|
||||
[!!] It is important to understand that **routes are matched in the order they are added**, and as soon as a URL matches a route, routing is essentially "stopped" and *the remaining routes are never tried*. Because the default route matches almost anything, including an empty url, new routes must be place before it.
|
||||
|
||||
## Creating routes
|
||||
|
||||
If you look in `APPPATH/bootstrap.php` you will see the "default" route as follows:
|
||||
|
||||
Route::set('default', '(<controller>(/<action>(/<id>)))')
|
||||
->defaults(array(
|
||||
'controller' => 'Welcome',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
[!!] The default route is simply provided as a sample, you can remove it and replace it with your own routes.
|
||||
|
||||
So this creates a route with the name `default` that will match urls in the format of `(<controller>(/<action>(/<id>)))`.
|
||||
|
||||
Let's take a closer look at each of the parameters of [Route::set], which are `name`, `uri`, and an optional array `regex`.
|
||||
|
||||
### Name
|
||||
|
||||
The name of the route must be a **unique** string. If it is not it will overwrite the older route with the same name. The name is used for creating urls by reverse routing, or checking which route was matched.
|
||||
|
||||
### URI
|
||||
|
||||
The uri is a string that represents the format of urls that should be matched. The tokens surrounded with `<>` are *keys* and anything surrounded with `()` are *optional* parts of the uri. In Kohana routes, any character is allowed and treated literally aside from `()<>`. The `/` has no meaning besides being a character that must match in the uri. Usually the `/` is used as a static seperator but as long as the regex makes sense, there are no restrictions to how you can format your routes.
|
||||
|
||||
Lets look at the default route again, the uri is `(<controller>(/<action>(/<id>)))`. We have three keys or params: controller, action, and id. In this case, the entire uri is optional, so a blank uri would match and the default controller and action (set by defaults(), [covered below](#defaults)) would be assumed resulting in the `Controller_Welcome` class being loaded and the `action_index` method being called to handle the request.
|
||||
|
||||
You can use any name you want for your keys, but the following keys have special meaning to the [Request] object, and will influence which controller and action are called:
|
||||
|
||||
* **Directory** - The sub-directory of `classes/Controller` to look for the controller (\[covered below]\(#directory))
|
||||
* **Controller** - The controller that the request should execute.
|
||||
* **Action** - The action method to call.
|
||||
|
||||
### Regex
|
||||
|
||||
The Kohana route system uses [perl compatible regular expressions](http://perldoc.perl.org/perlre.html) in its matching process. By default each key (surrounded by `<>`) will match `[^/.,;?\n]++` (or in english: anything that is not a slash, period, comma, semicolon, question mark, or newline). You can define your own patterns for each key by passing an associative array of keys and patterns as an additional third argument to Route::set.
|
||||
|
||||
In this example, we have controllers in two directories, `admin` and `affiliate`. Because this route will only match urls that begin with `admin` or `affiliate`, the default route would still work for controllers in `classes/Controller`.
|
||||
|
||||
Route::set('sections', '<directory>(/<controller>(/<action>(/<id>)))',
|
||||
array(
|
||||
'directory' => '(admin|affiliate)'
|
||||
))
|
||||
->defaults(array(
|
||||
'controller' => 'Home',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
You can also use a less restrictive regex to match unlimited parameters, or to ignore overflow in a route. In this example, the url `foobar/baz/and-anything/else_that/is-on-the/url` would be routed to `Controller_Foobar::action_baz()` and the `"stuff"` parameter would be `"and-anything/else_that/is-on-the/url"`. If you wanted to use this for unlimited parameters, you could [explode](http://php.net/manual/en/function.explode.php) it, or you just ignore the overflow.
|
||||
|
||||
Route::set('default', '(<controller>(/<action>(/<stuff>)))', array('stuff' => '.*'))
|
||||
->defaults(array(
|
||||
'controller' => 'Welcome',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
|
||||
### Default values
|
||||
|
||||
If a key in a route is optional (or not present in the route), you can provide a default value for that key by passing an associated array of keys and default values to [Route::defaults], chained after your [Route::set]. This can be useful to provide a default controller or action for your site, among other things.
|
||||
|
||||
[!!] The `controller` and `action` key must always have a value, so they either need to be required in your route (not inside of parentheses) or have a default value provided.
|
||||
|
||||
[!!] Kohana automatically converts controllers to follow the standard naming convention. For example /blog/view/123 would look for the controller Controller_Blog in classes/Controller/Blog.php and trigger the action_view() method on it.
|
||||
|
||||
In the default route, all the keys are optional, and the controller and action are given a default. If we called an empty url, the defaults would fill in and `Controller_Welcome::action_index()` would be called. If we called `foobar` then only the default for action would be used, so it would call `Controller_Foobar::action_index()` and finally, if we called `foobar/baz` then neither default would be used and `Controller_Foobar::action_baz()` would be called.
|
||||
|
||||
TODO: need an example here
|
||||
|
||||
You can also use defaults to set a key that isn't in the route at all.
|
||||
|
||||
TODO: example of either using directory or controller where it isn't in the route, but set by defaults
|
||||
|
||||
### Directory
|
||||
|
||||
## Route Filters
|
||||
|
||||
In 3.3, you can specify advanced routing schemes by using filter callbacks. When you need to match a route based on more than just the URI of a request, for example, based on the method request (GET/POST/DELETE), a filter will allow you to do so. These filters will receive the `Route` object being tested, the currently matched `$params` array, and the `Request` object as the three parameters. Here's a simple example:
|
||||
|
||||
Route::set('save-form', 'save')
|
||||
->filter(function($route, $params, $request)
|
||||
{
|
||||
if ($request->method() !== HTTP_Request::POST)
|
||||
{
|
||||
return FALSE; // This route only matches POST requests
|
||||
}
|
||||
});
|
||||
|
||||
Filters can also replace or alter the array of parameters:
|
||||
|
||||
Route::set('rest-api', 'api/<action>')
|
||||
->filter(function($route, $params, $request)
|
||||
{
|
||||
// Prefix the method to the action name
|
||||
$params['action'] = strtolower($request->method()).'_'.$params['action'];
|
||||
return $params; // Returning an array will replace the parameters
|
||||
})
|
||||
->defaults(array(
|
||||
'controller' => 'api',
|
||||
));
|
||||
|
||||
If you are using php 5.2, you can still use any valid callback for this behavior:
|
||||
|
||||
Route::set('testing', 'foo')
|
||||
->filter(array('Class', 'method_to_process_my_uri'));
|
||||
|
||||
## Examples
|
||||
|
||||
There are countless other possibilities for routes. Here are some more examples:
|
||||
|
||||
/*
|
||||
* Authentication shortcuts
|
||||
*/
|
||||
Route::set('auth', '<action>',
|
||||
array(
|
||||
'action' => '(login|logout)'
|
||||
))
|
||||
->defaults(array(
|
||||
'controller' => 'Auth'
|
||||
));
|
||||
|
||||
/*
|
||||
* Multi-format feeds
|
||||
* 452346/comments.rss
|
||||
* 5373.json
|
||||
*/
|
||||
Route::set('feeds', '<user_id>(/<action>).<format>',
|
||||
array(
|
||||
'user_id' => '\d+',
|
||||
'format' => '(rss|atom|json)',
|
||||
))
|
||||
->defaults(array(
|
||||
'controller' => 'Feeds',
|
||||
'action' => 'status',
|
||||
));
|
||||
|
||||
/*
|
||||
* Static pages
|
||||
*/
|
||||
Route::set('static', '<path>.html',
|
||||
array(
|
||||
'path' => '[a-zA-Z0-9_/]+',
|
||||
))
|
||||
->defaults(array(
|
||||
'controller' => 'Static',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
/*
|
||||
* You don't like slashes?
|
||||
* EditGallery:bahamas
|
||||
* Watch:wakeboarding
|
||||
*/
|
||||
Route::set('gallery', '<action>(<controller>):<id>',
|
||||
array(
|
||||
'controller' => '[A-Z][a-z]++',
|
||||
'action' => '[A-Z][a-z]++',
|
||||
))
|
||||
->defaults(array(
|
||||
'controller' => 'Slideshow',
|
||||
));
|
||||
|
||||
/*
|
||||
* Quick search
|
||||
*/
|
||||
Route::set('search', ':<query>', array('query' => '.*'))
|
||||
->defaults(array(
|
||||
'controller' => 'Search',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
## Request parameters
|
||||
|
||||
The `directory`, `controller` and `action` can be accessed from the [Request] as public properties like so:
|
||||
|
||||
// From within a controller:
|
||||
$this->request->action();
|
||||
$this->request->controller();
|
||||
$this->request->directory();
|
||||
|
||||
// Can be used anywhere:
|
||||
Request::current()->action();
|
||||
Request::current()->controller();
|
||||
Request::current()->directory();
|
||||
|
||||
All other keys specified in a route can be accessed via [Request::param()]:
|
||||
|
||||
// From within a controller:
|
||||
$this->request->param('key_name');
|
||||
|
||||
// Can be used anywhere:
|
||||
Request::current()->param('key_name');
|
||||
|
||||
The [Request::param] method takes an optional second argument to specify a default return value in case the key is not set by the route. If no arguments are given, all keys are returned as an associative array. In addition, `action`, `controller` and `directory` are not accessible via [Request::param()].
|
||||
|
||||
For example, with the following route:
|
||||
|
||||
Route::set('ads','ad/<ad>(/<affiliate>)')
|
||||
->defaults(array(
|
||||
'controller' => 'ads',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
If a url matches the route, then `Controller_Ads::index()` will be called. You can access the parameters by using the `param()` method of the controller's [Request]. Remember to define a default value (via the second, optional parameter of [Request::param]) if you didn't in `->defaults()`.
|
||||
|
||||
class Controller_Ads extends Controller {
|
||||
public function action_index()
|
||||
{
|
||||
$ad = $this->request->param('ad');
|
||||
$affiliate = $this->request->param('affiliate',NULL);
|
||||
}
|
||||
|
||||
|
||||
## Where should routes be defined?
|
||||
|
||||
The established convention is to either place your custom routes in the `MODPATH/<module>/init.php` file of your module if the routes belong to a module, or simply insert them into the `APPPATH/bootstrap.php` file (be sure to put them **above** the default route) if they are specific to the application. Of course, nothing stops you from including them from an external file, or even generating them dynamically.
|
||||
|
||||
## A deeper look at how routes work
|
||||
|
||||
TODO: talk about how routes are compiled
|
||||
|
||||
## Creating URLs and links using routes
|
||||
|
||||
Along with Kohana's powerful routing capabilities are included some methods for generating URLs for your routes' uris. You can always specify your uris as a string using [URL::site] to create a full URL like so:
|
||||
|
||||
URL::site('admin/edit/user/'.$user_id);
|
||||
|
||||
However, Kohana also provides a method to generate the uri from the route's definition. This is extremely useful if your routing could ever change since it would relieve you from having to go back through your code and change everywhere that you specified a uri as a string. Here is an example of dynamic generation that corresponds to the `feeds` route example from above:
|
||||
|
||||
Route::get('feeds')->uri(array(
|
||||
'user_id' => $user_id,
|
||||
'action' => 'comments',
|
||||
'format' => 'rss'
|
||||
));
|
||||
|
||||
Let's say you decided later to make that route definition more verbose by changing it to `feeds/<user_id>(/<action>).<format>`. If you wrote your code with the above uri generation method you wouldn't have to change a single line! When a part of the uri is enclosed in parentheses and specifies a key for which there in no value provided for uri generation and no default value specified in the route, then that part will be removed from the uri. An example of this is the `(/<id>)` part of the default route; this will not be included in the generated uri if an id is not provided.
|
||||
|
||||
One method you might use frequently is the shortcut [Request::uri] which is the same as the above except it assumes the current route, directory, controller and action. If our current route is the default and the uri was `users/list`, we can do the following to generate uris in the format `users/view/$id`:
|
||||
|
||||
$this->request->uri(array('action' => 'view', 'id' => $user_id));
|
||||
|
||||
Or if within a view, the preferable method is:
|
||||
|
||||
Request::instance()->uri(array('action' => 'view', 'id' => $user_id));
|
||||
|
||||
TODO: examples of using html::anchor in addition to the above examples
|
||||
|
||||
## Testing routes
|
||||
|
||||
TODO: mention bluehawk's devtools module
|
1
includes/kohana/system/guide/kohana/security.md
Normal file
1
includes/kohana/system/guide/kohana/security.md
Normal file
@@ -0,0 +1 @@
|
||||
General security concerns, like using the Security class, CSRF, and a brief intro to XSS, database security, etc. Also mention the security features that Kohana provides, like cleaning globals.
|
3
includes/kohana/system/guide/kohana/security/cookies.md
Normal file
3
includes/kohana/system/guide/kohana/security/cookies.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Discuss security of cookies, like changing the encryption key in the config.
|
||||
|
||||
Not sure why I'm linking to this: <http://kohanaframework.org/guide/security.cookies>
|
5
includes/kohana/system/guide/kohana/security/database.md
Normal file
5
includes/kohana/system/guide/kohana/security/database.md
Normal file
@@ -0,0 +1,5 @@
|
||||
Discuss database security.
|
||||
|
||||
How to avoid injection, etc.
|
||||
|
||||
Not sure why I'm linking to this: <http://kohanaframework.org/guide/security.database>
|
31
includes/kohana/system/guide/kohana/security/deploying.md
Normal file
31
includes/kohana/system/guide/kohana/security/deploying.md
Normal file
@@ -0,0 +1,31 @@
|
||||
Changes that should happen when you deploy. (Production)
|
||||
|
||||
Security settings from: <http://kohanaframework.org/guide/using.configuration>
|
||||
|
||||
<http://kerkness.ca/wiki/doku.php?id=setting_up_production_environment>
|
||||
|
||||
|
||||
## Setting up a production environment
|
||||
|
||||
There are a few things you'll want to do with your application before moving into production.
|
||||
|
||||
1. See the [Bootstrap page](bootstrap) in the docs.
|
||||
This covers most of the global settings that would change between environments.
|
||||
As a general rule, you should enable caching and disable profiling ([Kohana::init] settings) for production sites.
|
||||
[Route::cache] can also help if you have a lot of routes.
|
||||
2. Turn on APC or some kind of opcode caching.
|
||||
This is the single easiest performance boost you can make to PHP itself. The more complex your application, the bigger the benefit of using opcode caching.
|
||||
|
||||
/**
|
||||
* Set the environment string by the domain (defaults to Kohana::DEVELOPMENT).
|
||||
*/
|
||||
Kohana::$environment = ($_SERVER['SERVER_NAME'] !== 'localhost') ? Kohana::PRODUCTION : Kohana::DEVELOPMENT;
|
||||
/**
|
||||
* Initialise Kohana based on environment
|
||||
*/
|
||||
Kohana::init(array(
|
||||
'base_url' => '/',
|
||||
'index_file' => FALSE,
|
||||
'profile' => Kohana::$environment !== Kohana::PRODUCTION,
|
||||
'caching' => Kohana::$environment === Kohana::PRODUCTION,
|
||||
));
|
107
includes/kohana/system/guide/kohana/security/encryption.md
Normal file
107
includes/kohana/system/guide/kohana/security/encryption.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# Encryption
|
||||
|
||||
Kohana supports built-in encryption and decryption via the [Encrypt] class, which is a convenient wrapper for the [Mcrypt library](http://www.php.net/mcrypt).
|
||||
|
||||
To use the class, first start by ensuring you have the Mcrypt extension loaded to your PHP config. See the [Mcrypt Installation page](http://www.php.net/manual/en/mcrypt.installation.php) on php.net. The Mcrypt extension requires [libmcrypt](http://sourceforge.net/projects/mcrypt/files/).
|
||||
|
||||
Next, copy the default config/encryption.php from system/config folder to your application/config folder.
|
||||
|
||||
The default Encryption config file that ships with Kohana 3.2.x looks like this:
|
||||
|
||||
<?php defined('SYSPATH') OR die('No direct script access.');
|
||||
|
||||
return array(
|
||||
|
||||
'default' => array(
|
||||
/**
|
||||
* The following options must be set:
|
||||
*
|
||||
* string key secret passphrase
|
||||
* integer mode encryption mode, one of MCRYPT_MODE_*
|
||||
* integer cipher encryption cipher, one of the Mcrpyt cipher constants
|
||||
*/
|
||||
'cipher' => MCRYPT_RIJNDAEL_128,
|
||||
'mode' => MCRYPT_MODE_NOFB,
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
|
||||
A couple of notes about the config.
|
||||
First, you may have multiple first-level keys other than 'default' if you need to.
|
||||
In this respect, the config file is similar to having multiple databases defined in your config/database.php file.
|
||||
Second, notice there is no key provided. You need to add that.
|
||||
It is strongly recommended that you choose a high-strength random key using the [pwgen linux program](http://linux.die.net/man/1/pwgen)...
|
||||
|
||||
shell> pwgen 63 1
|
||||
trwQwVXX96TIJoKxyBHB9AJkwAOHixuV1ENZmIWyanI0j1zNgSVvqywy044Agaj
|
||||
|
||||
...or by going to [GRC.com/passwords.htm](https://www.grc.com/passwords.htm).
|
||||
|
||||
## Complete Config Example
|
||||
|
||||
Here's a sample encryption configuration with three types of encryption defined. **If you copy this example, please change your keys!**
|
||||
|
||||
<?php defined('SYSPATH') OR die('No direct script access.');
|
||||
// application/config/encrypt.php
|
||||
|
||||
return array(
|
||||
|
||||
'default' => array(
|
||||
'key' => 'trwQwVXX96TIJoKxyBHB9AJkwAOHixuV1ENZmIWyanI0j1zNgSVvqywy044Agaj',
|
||||
'cipher' => MCRYPT_RIJNDAEL_128,
|
||||
'mode' => MCRYPT_MODE_NOFB,
|
||||
),
|
||||
'blowfish' => array(
|
||||
'key' => '7bZJJkmNrelj5NaKoY6h6rMSRSmeUlJuTeOd5HHka5XknyMX4uGSfeVolTz4IYy',
|
||||
'cipher' => MCRYPT_BLOWFISH,
|
||||
'mode' => MCRYPT_MODE_ECB,
|
||||
),
|
||||
'tripledes' => array(
|
||||
'key' => 'a9hcSLRvA3LkFc7EJgxXIKQuz1ec91J7P6WNq1IaxMZp4CTj5m31gZLARLxI1jD',
|
||||
'cipher' => MCRYPT_3DES,
|
||||
'mode' => MCRYPT_MODE_CBC,
|
||||
),
|
||||
);
|
||||
|
||||
You can view the available encryption ciphers and modes on your system by running...
|
||||
|
||||
shell> php -r "print_r(get_defined_constants());" | grep MCRYPT
|
||||
|
||||
For more information on Mcrypt ciphers, visit [php.net/mcrypt.ciphers](http://us3.php.net/manual/en/mcrypt.ciphers.php).
|
||||
|
||||
## Basic Usage
|
||||
|
||||
### Create an instance
|
||||
|
||||
To use the Encryption class, obtain an instance of the Encrypt class by calling it's *instance* method,
|
||||
optionally passing the desired configuration group. If you do not pass a config group to the instance method,
|
||||
the default group will be used.
|
||||
|
||||
$encrypt = Encrypt::instance('tripledes');
|
||||
|
||||
### Encoding Data
|
||||
|
||||
Next, encode some data using the *encode* method:
|
||||
|
||||
$encrypt = Encrypt::instance('tripledes');
|
||||
$encrypted_data = $encrypt->encode('Data to Encode');
|
||||
// $encrypted_data now contains pCD5Z6oVdb9hbLxxV+FgGrhwVzZuhQoH
|
||||
|
||||
[!!] Raw encrypted strings usually won't print in a browser, and may not store properly in a VARCHAR or TEXT field. For this reason, Kohana's Encrypt class automatically calls base64_encode on encode, and base64_decode on decode, to prevent this problem.
|
||||
|
||||
[!!] One word of caution. The length of the encoded data expands quite a bit, so be sure your database column is long enough to store the encrypted data. If even one character is truncated, the data will not be recoverable.
|
||||
|
||||
### Decoding Data
|
||||
|
||||
To decode some data, load it from the place you stored it (most likely your database) then pass it to the *decode* method:
|
||||
|
||||
$encrypt = Encrypt::instance('tripledes');
|
||||
$decoded_string = $encrypt->decode($encrypted_data);
|
||||
echo $decoded_string;
|
||||
// prints 'Data to Encode'
|
||||
|
||||
You can't know in advance what the encoded string will be, and it's not reproducible, either.
|
||||
That is, you can encode the same value over and over, but you'll always obtain a different encoded version,
|
||||
even without changing your key, cipher and mode. This is because Kohana adds some random entropy before encoding it with your value.
|
||||
This ensures an attacker cannot easily discover your key and cipher, even given a collection of encoded values.
|
266
includes/kohana/system/guide/kohana/security/validation.md
Normal file
266
includes/kohana/system/guide/kohana/security/validation.md
Normal file
@@ -0,0 +1,266 @@
|
||||
# Validation
|
||||
|
||||
*This page needs to be reviewed for accuracy by the development team. Better examples would be helpful.*
|
||||
|
||||
Validation can be performed on any array using the [Validation] class. Labels and rules can be attached to a Validation object by the array key, called a "field name".
|
||||
|
||||
labels
|
||||
: A label is a human-readable version of the field name.
|
||||
|
||||
rules
|
||||
: A rule is a callback or closure used to decide whether or not to add an error to a field
|
||||
|
||||
[!!] Note that any valid [PHP callback](http://php.net/manual/language.pseudo-types.php#language.types.callback) can be used as a rule.
|
||||
|
||||
Using `TRUE` as the field name when adding a rule will be applied to all named fields.
|
||||
|
||||
Creating a validation object is done using the [Validation::factory] method:
|
||||
|
||||
$object = Validation::factory($array);
|
||||
|
||||
[!!] The `$object` object will be used for the rest of this tutorial. This tutorial will show you how to validate the registration of a new user.
|
||||
|
||||
## Provided Rules
|
||||
|
||||
Kohana provides a set of useful rules in the [Valid] class:
|
||||
|
||||
Rule name | Function
|
||||
------------------------- |-------------------------------------------------
|
||||
[Valid::not_empty] | Value must be a non-empty value
|
||||
[Valid::regex] | Match the value against a regular expression
|
||||
[Valid::min_length] | Minimum number of characters for value
|
||||
[Valid::max_length] | Maximum number of characters for value
|
||||
[Valid::exact_length] | Value must be an exact number of characters
|
||||
[Valid::email] | An email address is required
|
||||
[Valid::email_domain] | Check that the domain of the email exists
|
||||
[Valid::url] | Value must be a URL
|
||||
[Valid::ip] | Value must be an IP address
|
||||
[Valid::phone] | Value must be a phone number
|
||||
[Valid::credit_card] | Require a credit card number
|
||||
[Valid::date] | Value must be a date (and time)
|
||||
[Valid::alpha] | Only alpha characters allowed
|
||||
[Valid::alpha_dash] | Only alpha and hyphens allowed
|
||||
[Valid::alpha_numeric] | Only alpha and numbers allowed
|
||||
[Valid::digit] | Value must be an integer digit
|
||||
[Valid::decimal] | Value must be a decimal or float value
|
||||
[Valid::numeric] | Only numeric characters allowed
|
||||
[Valid::range] | Value must be within a range
|
||||
[Valid::color] | Value must be a valid HEX color
|
||||
[Valid::matches] | Value matches another field value
|
||||
|
||||
## Adding Rules
|
||||
|
||||
All validation rules are defined as a field name, a method, a function (using the [PHP callback](http://php.net/callback) syntax) or [closure](http://php.net/manual/functions.anonymous.php), and an array of parameters:
|
||||
|
||||
$object->rule($field, $callback, array($parameter1, $parameter2));
|
||||
|
||||
If no parameters are specified, the field value will be passed to the callback. The following two rules are equivalent:
|
||||
|
||||
$object->rule($field, 'not_empty');
|
||||
$object->rule($field, 'not_empty', array(':value'));
|
||||
|
||||
Rules defined in the [Valid] class can be added by using the method name alone. The following three rules are equivalent:
|
||||
|
||||
$object->rule('number', 'phone');
|
||||
$object->rule('number', array('Valid', 'phone'));
|
||||
$object->rule('number', 'Valid::phone');
|
||||
|
||||
### Adding Rules for multiple fields together
|
||||
|
||||
To validate multiple fields together, you can do something like this:
|
||||
|
||||
$object->rule('one', 'only_one', array(':validation', array('one', 'two')));
|
||||
$object->rule('two', 'only_one', array(':validation', array('one', 'two')));
|
||||
|
||||
public function only_one($validation, $fields)
|
||||
{
|
||||
// If more than 1 field is set, bail.
|
||||
$matched = 0;
|
||||
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
if (isset($validation[$field]))
|
||||
{
|
||||
$matched++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($matched > 0)
|
||||
{
|
||||
// Add the error to all concerned fields
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
$validation->error($field, 'only_one');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## Binding Variables
|
||||
|
||||
The [Validation] class allows you to bind variables to certain strings so that they can be used when defining rules. Variables are bound by calling the [Validation::bind] method.
|
||||
|
||||
$object->bind(':model', $user_model);
|
||||
// Future code will be able to use :model to reference the object
|
||||
$object->rule('username', 'some_rule', array(':model'));
|
||||
|
||||
By default, the validation object will automatically bind the following values for you to use as rule parameters:
|
||||
|
||||
- `:validation` - references the validation object
|
||||
- `:field` - references the field name the rule is for
|
||||
- `:value` - references the value of the field the rule is for
|
||||
|
||||
## Adding Errors
|
||||
|
||||
The [Validation] class will add an error for a field if any of the rules associated to it return `FALSE`. This allows many built in PHP functions to be used as rules, like `in_array`.
|
||||
|
||||
$object->rule('color', 'in_array', array(':value', array('red', 'green', 'blue')));
|
||||
|
||||
Rules added to empty fields will run, but returning `FALSE` will not automatically add an error for the field. In order for a rule to affect empty fields, you must add the error manually by calling the [Validation::error] method. In order to do this, you must pass the validation object to the rule.
|
||||
|
||||
$object->rule($field, 'the_rule', array(':validation', ':field'));
|
||||
|
||||
public function the_rule($validation, $field)
|
||||
{
|
||||
if (something went wrong)
|
||||
{
|
||||
$validation->error($field, 'the_rule');
|
||||
}
|
||||
}
|
||||
|
||||
[!!] `not_empty` and `matches` are the only rules that will run on empty fields and add errors by returning `FALSE`.
|
||||
|
||||
## Example
|
||||
|
||||
To start our example, we will perform validation on the HTTP POST data of the current request that contains user registration information:
|
||||
|
||||
[!!] In Kohana controllers, we access `$this->request->post()` instead of `$_POST` for better request isolation.
|
||||
|
||||
$object = Validation::factory($this->request->post());
|
||||
|
||||
Next we need to process the POST'ed information using [Validation]. To start, we need to add some rules:
|
||||
|
||||
$object
|
||||
->rule('username', 'not_empty')
|
||||
->rule('username', 'regex', array(':value', '/^[a-z_.]++$/iD'))
|
||||
->rule('password', 'not_empty')
|
||||
->rule('password', 'min_length', array(':value', '6'))
|
||||
->rule('confirm', 'matches', array(':validation', 'confirm', 'password'))
|
||||
->rule('use_ssl', 'not_empty');
|
||||
|
||||
Any existing PHP function can also be used a rule. For instance, if we want to check if the user entered a proper value for the SSL question:
|
||||
|
||||
$object->rule('use_ssl', 'in_array', array(':value', array('yes', 'no')));
|
||||
|
||||
Note that all array parameters must still be wrapped in an array! Without the wrapping array, `in_array` would be called as `in_array($value, 'yes', 'no')`, which would result in a PHP error.
|
||||
|
||||
Any custom rules can be added using a [PHP callback](http://php.net/manual/language.pseudo-types.php#language.types.callback]:
|
||||
|
||||
$object->rule('username', 'User_Model::unique_username');
|
||||
|
||||
The method `User_Model::unique_username()` would be defined similar to:
|
||||
|
||||
public static function unique_username($username)
|
||||
{
|
||||
// Check if the username already exists in the database
|
||||
return ! DB::select(array(DB::expr('COUNT(username)'), 'total'))
|
||||
->from('users')
|
||||
->where('username', '=', $username)
|
||||
->execute()
|
||||
->get('total');
|
||||
}
|
||||
|
||||
[!!] Custom rules allow many additional checks to be reused for multiple purposes. These methods will almost always exist in a model, but may be defined in any class.
|
||||
|
||||
# A Complete Example
|
||||
|
||||
First, we need a [View] that contains the HTML form, which will be placed in `application/views/user/register.php`:
|
||||
|
||||
<?php echo Form::open() ?>
|
||||
<?php if ($errors): ?>
|
||||
<p class="message">Some errors were encountered, please check the details you entered.</p>
|
||||
<ul class="errors">
|
||||
<?php foreach ($errors as $message): ?>
|
||||
<li><?php echo $message ?></li>
|
||||
<?php endforeach ?>
|
||||
<?php endif ?>
|
||||
|
||||
<dl>
|
||||
<dt><?php echo Form::label('username', 'Username') ?></dt>
|
||||
<dd><?php echo Form::input('username', $post['username']) ?></dd>
|
||||
|
||||
<dt><?php echo Form::label('password', 'Password') ?></dt>
|
||||
<dd><?php echo Form::password('password') ?></dd>
|
||||
<dd class="help">Passwords must be at least 6 characters long.</dd>
|
||||
<dt><?php echo Form::label('confirm', 'Confirm Password') ?></dt>
|
||||
<dd><?php echo Form::password('confirm') ?></dd>
|
||||
|
||||
<dt><?php echo Form::label('use_ssl', 'Use extra security?') ?></dt>
|
||||
<dd><?php echo Form::select('use_ssl', array('yes' => 'Always', 'no' => 'Only when necessary'), $post['use_ssl']) ?></dd>
|
||||
<dd class="help">For security, SSL is always used when making payments.</dd>
|
||||
</dl>
|
||||
|
||||
<?php echo Form::submit(NULL, 'Sign Up') ?>
|
||||
<?php echo Form::close() ?>
|
||||
|
||||
[!!] This example uses the [Form] helper extensively. Using [Form] instead of writing HTML ensures that all of the form inputs will properly handle input that includes HTML characters. If you prefer to write the HTML yourself, be sure to use [HTML::chars] to escape user input.
|
||||
|
||||
Next, we need a controller and action to process the registration, which will be placed in `application/classes/Controller/User.php`:
|
||||
|
||||
class Controller_User extends Controller {
|
||||
|
||||
public function action_register()
|
||||
{
|
||||
$user = Model::factory('user');
|
||||
|
||||
$validation = Validation::factory($this->request->post())
|
||||
->rule('username', 'not_empty')
|
||||
->rule('username', 'regex', array(':value', '/^[a-z_.]++$/iD'))
|
||||
->rule('username', array($user, 'unique_username'))
|
||||
|
||||
->rule('password', 'not_empty')
|
||||
->rule('password', 'min_length', array(':value', 6))
|
||||
->rule('confirm', 'matches', array(':validation', ':field', 'password'))
|
||||
|
||||
->rule('use_ssl', 'not_empty')
|
||||
->rule('use_ssl', 'in_array', array(':value', array('yes', 'no')));
|
||||
|
||||
if ($validation->check())
|
||||
{
|
||||
// Data has been validated, register the user
|
||||
$user->register($this->request->post());
|
||||
|
||||
// Always redirect after a successful POST to prevent refresh warnings
|
||||
$this->redirect('user/profile', 302);
|
||||
}
|
||||
|
||||
// Validation failed, collect the errors
|
||||
$errors = $validation->errors('user');
|
||||
|
||||
// Display the registration form
|
||||
$this->response->body(View::factory('user/register'))
|
||||
->bind('post', $this->request->post())
|
||||
->bind('errors', $errors);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
We will also need a user model, which will be placed in `application/classes/Model/User.php`:
|
||||
|
||||
class Model_User extends Model {
|
||||
|
||||
public function register($array)
|
||||
{
|
||||
// Create a new user record in the database
|
||||
$id = DB::insert(array_keys($array))
|
||||
->values($array)
|
||||
->execute();
|
||||
|
||||
// Save the new user id to a cookie
|
||||
cookie::set('user', $id);
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
That is it, we have a complete user registration example that properly checks user input!
|
17
includes/kohana/system/guide/kohana/security/xss.md
Normal file
17
includes/kohana/system/guide/kohana/security/xss.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Cross-Site Scripting (XSS) Security
|
||||
|
||||
*This page is not comprehensive and should not be considered a complete guide to XSS prevention.*
|
||||
|
||||
The first step to preventing [XSS](http://wikipedia.org/wiki/Cross-Site_Scripting) attacks is knowing when you need to protect yourself. XSS can only be triggered when it is displayed within HTML content, sometimes via a form input or being displayed from database results. Any global variable that contains client information can be tainted. This includes `$_GET`, `$_POST`, and `$_COOKIE` data.
|
||||
|
||||
## Prevention
|
||||
|
||||
There are a few simple rules to follow to guard your application HTML against XSS. If you do not want HTML in a variable, use [strip_tags](http://php.net/strip_tags) to remove all unwanted HTML tags from a value.
|
||||
|
||||
[!!] If you allow users to submit HTML to your application, it is highly recommended to use an HTML cleaning tool such as [HTML Purifier](http://htmlpurifier.org/) or [HTML Tidy](http://php.net/tidy).
|
||||
|
||||
The second is to always escape data when inserting into HTML. The [HTML] class provides generators for many common tags, including script and stylesheet links, anchors, images, and email (mailto) links. Any untrusted content should be escaped using [HTML::chars].
|
||||
|
||||
## References
|
||||
|
||||
* [OWASP XSS Cheat Sheet](http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)
|
167
includes/kohana/system/guide/kohana/sessions.md
Normal file
167
includes/kohana/system/guide/kohana/sessions.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# Sessions
|
||||
|
||||
Kohana provides classes that make it easy to work with both cookies and sessions. At a high level both sessions and cookies provide the same functionality. They allow the developer to store temporary or persistent information about a specific client for later retrieval, usually to make something persistent between requests.
|
||||
|
||||
Sessions should be used for storing temporary or private data. Very sensitive data should be stored using the [Session] class with the "database" or "native" adapters. When using the "cookie" adapter, the session should always be encrypted.
|
||||
|
||||
[!!] For more information on best practices with session variables see [the seven deadly sins of sessions](http://lists.nyphp.org/pipermail/talk/2006-December/020358.html).
|
||||
|
||||
## Storing, Retrieving, and Deleting Data
|
||||
|
||||
[Cookie] and [Session] provide a very similar API for storing data. The main difference between them is that sessions are accessed using an object, and cookies are accessed using a static class.
|
||||
|
||||
Accessing the session instance is done using the [Session::instance] method:
|
||||
|
||||
// Get the session instance
|
||||
$session = Session::instance();
|
||||
|
||||
When using sessions, you can also get all of the current session data using the [Session::as_array] method:
|
||||
|
||||
// Get all of the session data as an array
|
||||
$data = $session->as_array();
|
||||
|
||||
You can also use this to overload the `$_SESSION` global to get and set data in a way more similar to standard PHP:
|
||||
|
||||
// Overload $_SESSION with the session data
|
||||
$_SESSION =& $session->as_array();
|
||||
|
||||
// Set session data
|
||||
$_SESSION[$key] = $value;
|
||||
|
||||
### Storing Data
|
||||
|
||||
Storing session or cookie data is done using the `set` method:
|
||||
|
||||
// Set session data
|
||||
$session->set($key, $value);
|
||||
// Or
|
||||
Session::instance()->set($key, $value);
|
||||
|
||||
// Store a user id
|
||||
$session->set('user_id', 10);
|
||||
|
||||
### Retrieving Data
|
||||
|
||||
Getting session or cookie data is done using the `get` method:
|
||||
|
||||
// Get session data
|
||||
$data = $session->get($key, $default_value);
|
||||
|
||||
// Get the user id
|
||||
$user = $session->get('user_id');
|
||||
|
||||
### Deleting Data
|
||||
|
||||
Deleting session or cookie data is done using the `delete` method:
|
||||
|
||||
// Delete session data
|
||||
$session->delete($key);
|
||||
|
||||
|
||||
// Delete the user id
|
||||
$session->delete('user_id');
|
||||
|
||||
## Session Configuration
|
||||
|
||||
Always check these settings before making your application live, as many of them will have a direct affect on the security of your application.
|
||||
|
||||
## Session Adapters
|
||||
|
||||
When creating or accessing an instance of the [Session] class you can decide which session adapter or driver you wish to use. The session adapters that are available to you are:
|
||||
|
||||
Native
|
||||
: Stores session data in the default location for your web server. The storage location is defined by [session.save_path](http://php.net/manual/session.configuration.php#ini.session.save-path) in `php.ini` or defined by [ini_set](http://php.net/ini_set).
|
||||
|
||||
Database
|
||||
: Stores session data in a database table using the [Session_Database] class. Requires the [Database] module to be enabled.
|
||||
|
||||
Cookie
|
||||
: Stores session data in a cookie using the [Cookie] class. **Sessions will have a 4KB limit when using this adapter, and should be encrypted.**
|
||||
|
||||
The default adapter can be set by changing the value of [Session::$default]. The default adapter is "native".
|
||||
|
||||
To access a Session using the default adapter, simply call [Session::instance()]. To access a Session using something other than the default, pass the adapter name to `instance()`, for example: `Session::instance('cookie')`
|
||||
|
||||
|
||||
### Session Adapter Settings
|
||||
|
||||
You can apply configuration settings to each of the session adapters by creating a session config file at `APPPATH/config/session.php`. The following sample configuration file defines all the settings for each adapter:
|
||||
|
||||
[!!] As with cookies, a "lifetime" setting of "0" means that the session will expire when the browser is closed.
|
||||
|
||||
return array(
|
||||
'native' => array(
|
||||
'name' => 'session_name',
|
||||
'lifetime' => 43200,
|
||||
),
|
||||
'cookie' => array(
|
||||
'name' => 'cookie_name',
|
||||
'encrypted' => TRUE,
|
||||
'lifetime' => 43200,
|
||||
),
|
||||
'database' => array(
|
||||
'name' => 'cookie_name',
|
||||
'encrypted' => TRUE,
|
||||
'lifetime' => 43200,
|
||||
'group' => 'default',
|
||||
'table' => 'table_name',
|
||||
'columns' => array(
|
||||
'session_id' => 'session_id',
|
||||
'last_active' => 'last_active',
|
||||
'contents' => 'contents'
|
||||
),
|
||||
'gc' => 500,
|
||||
),
|
||||
);
|
||||
|
||||
#### Native Adapter
|
||||
|
||||
Type | Setting | Description | Default
|
||||
----------|-----------|---------------------------------------------------|-----------
|
||||
`string` | name | name of the session | `"session"`
|
||||
`integer` | lifetime | number of seconds the session should live for | `0`
|
||||
|
||||
#### Cookie Adapter
|
||||
|
||||
Type | Setting | Description | Default
|
||||
----------|-----------|---------------------------------------------------|-----------
|
||||
`string` | name | name of the cookie used to store the session data | `"session"`
|
||||
`boolean` | encrypted | encrypt the session data using [Encrypt]? | `FALSE`
|
||||
`integer` | lifetime | number of seconds the session should live for | `0`
|
||||
|
||||
#### Database Adapter
|
||||
|
||||
Type | Setting | Description | Default
|
||||
----------|-----------|---------------------------------------------------|-----------
|
||||
`string` | group | [Database::instance] group name | `"default"`
|
||||
`string` | table | table name to store sessions in | `"sessions"`
|
||||
`array` | columns | associative array of column aliases | `array`
|
||||
`integer` | gc | 1:x chance that garbage collection will be run | `500`
|
||||
`string` | name | name of the cookie used to store the session data | `"session"`
|
||||
`boolean` | encrypted | encrypt the session data using [Encrypt]? | `FALSE`
|
||||
`integer` | lifetime | number of seconds the session should live for | `0`
|
||||
|
||||
##### Table Schema
|
||||
|
||||
You will need to create the session storage table in the database. This is the default schema:
|
||||
|
||||
CREATE TABLE `sessions` (
|
||||
`session_id` VARCHAR(24) NOT NULL,
|
||||
`last_active` INT UNSIGNED NOT NULL,
|
||||
`contents` TEXT NOT NULL,
|
||||
PRIMARY KEY (`session_id`),
|
||||
INDEX (`last_active`)
|
||||
) ENGINE = MYISAM;
|
||||
|
||||
##### Table Columns
|
||||
|
||||
You can change the column names to match an existing database schema when connecting to a legacy session table. The default value is the same as the key value.
|
||||
|
||||
session_id
|
||||
: the name of the "id" column
|
||||
|
||||
last_active
|
||||
: UNIX timestamp of the last time the session was updated
|
||||
|
||||
contents
|
||||
: session data stored as a serialized string, and optionally encrypted
|
41
includes/kohana/system/guide/kohana/tips.md
Normal file
41
includes/kohana/system/guide/kohana/tips.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Tips and Common Mistakes
|
||||
|
||||
This is a collection of tips and common mistakes or errors you may encounter.
|
||||
|
||||
## Never edit the `system` folder!
|
||||
|
||||
You should (almost) never edit the system folder. Any change you want to make to files in system and modules can be made via the [cascading filesystem](files) and [transparent extension](extension) and won't break when you try to update your Kohana version.
|
||||
|
||||
## Don't try and use one route for everything
|
||||
|
||||
Kohana 3 [routes](routing) are very powerful and flexible, don't be afraid to use as many as you need to make your app function the way you want!
|
||||
|
||||
## Files not found on some systems
|
||||
|
||||
As of Kohana 3.3, classes are autoloaded using the case-sensitive PSR-0 autoloader. This means that using the class Foo {} with a file in classes/foo.php will work on case-insensitive file systems (such as the default HFS+ FS used in Mac OS X) but will fail when used on a case-sensitive FS (typical on many production Linux servers).
|
||||
|
||||
## Handling lots of routes
|
||||
|
||||
Sometimes your application is sufficiently complex that you have many routes and it becomes unmanageable to put them all in bootstrap.php. If this is the case, simply make a `routes.php` file in APPPATH and require that in your bootstrap: `require_once APPPATH.'routes'.EXT;`
|
||||
|
||||
## Reflection_Exception
|
||||
|
||||
If you get a Reflection_Exception when setting up your site, it is almost certainly because your [Kohana::init] 'base_url' setting is wrong. If your base url is correct something is probably wrong with your [routes](routing).
|
||||
|
||||
ReflectionException [ -1 ]: Class controller_<something> does not exist
|
||||
// where <something> is part of the url you entered in your browser
|
||||
|
||||
### Solution {#reflection-exception-solution}
|
||||
|
||||
Set your [Kohana::init] 'base_url' to the correct setting. The base url should be the path to your index.php file relative to the webserver document root.
|
||||
|
||||
## ORM/Session __sleep() bug
|
||||
|
||||
There is a bug in php which can corrupt your session after a fatal error. A production server shouldn't have uncaught fatal errors, so this bug should only happen during development, when you do something stupid and cause a fatal error. On the next page load you will get a database connection error, then all subsequent page loads will display the following error:
|
||||
|
||||
ErrorException [ Notice ]: Undefined index: id
|
||||
MODPATH/orm/classes/kohana/orm.php [ 1308 ]
|
||||
|
||||
### Solution {#orm-session-sleep-solution}
|
||||
|
||||
To fix this, clear your cookies for that domain to reset your session. This should never happen on a production server, so you won't have to explain to your clients how to clear their cookies. You can see the [discussion on this issue](http://dev.kohanaframework.org/issues/3242) for more details.
|
17
includes/kohana/system/guide/kohana/tutorials.md
Normal file
17
includes/kohana/system/guide/kohana/tutorials.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Tutorials
|
||||
|
||||
## Tutorials in this guide
|
||||
|
||||
## Tutorials written elsewhere
|
||||
|
||||
### Ellisgl's KO3 tutorial on dealtaker.com:
|
||||
|
||||
1. [Install and Basic Usage](http://www.dealtaker.com/blog/2009/11/20/kohana-php-3-0-ko3-tutorial-part-1/)
|
||||
2. [Views](http://www.dealtaker.com/blog/2009/12/07/kohana-php-3-0-ko3-tutorial-part-2/)
|
||||
3. [Controllers](http://www.dealtaker.com/blog/2009/12/30/kohana-php-3-0-ko3-tutorial-part-3/)
|
||||
4. [Models](http://www.dealtaker.com/blog/2010/02/01/kohana-php-3-0-ko3-tutorial-part-4/)
|
||||
5. [Subrequests](http://www.dealtaker.com/blog/2010/02/25/kohana-php-3-0-ko3-tutorial-part-5/)
|
||||
6. [Routes](http://www.dealtaker.com/blog/2010/03/03/kohana-php-3-0-ko3-tutorial-part-6/)
|
||||
7. [Helpers](http://www.dealtaker.com/blog/2010/03/26/kohana-php-3-0-ko3-tutorial-part-7/)
|
||||
8. [Modules](http://www.dealtaker.com/blog/2010/04/30/kohana-php-3-0-ko3-tutorial-part-8/)
|
||||
9. [Vendor Libraries](http://www.dealtaker.com/blog/2010/06/02/kohana-php-3-0-ko3-tutorial-part-9/)
|
93
includes/kohana/system/guide/kohana/tutorials/clean-urls.md
Normal file
93
includes/kohana/system/guide/kohana/tutorials/clean-urls.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Clean URLs
|
||||
|
||||
Removing `index.php` from your urls.
|
||||
|
||||
To keep your URLs clean, you will probably want to be able to access your app without having `/index.php/` in the URL. There are two steps to remove `index.php` from the URL.
|
||||
|
||||
1. Edit the bootstrap file
|
||||
2. Set up rewriting
|
||||
|
||||
## 1. Configure Bootstrap
|
||||
|
||||
The first thing you will need to change is the `index_file` setting of [Kohana::init] to false:
|
||||
|
||||
Kohana::init(array(
|
||||
'base_url' => '/myapp/',
|
||||
'index_file' => FALSE,
|
||||
));
|
||||
|
||||
This change will make it so all of the links generated using [URL::site], [URL::base], and [HTML::anchor] will no longer include "index.php" in the URL. All generated links will start with `/myapp/` instead of `/myapp/index.php/`.
|
||||
|
||||
## 2. URL Rewriting
|
||||
|
||||
Enabling rewriting is done differently, depending on your web server.
|
||||
|
||||
Rewriting will make it so urls will be passed to index.php.
|
||||
|
||||
## Apache
|
||||
|
||||
Rename `example.htaccess` to only `.htaccess` and alter the `RewriteBase` line to match the `base_url` setting from your [Kohana::init]
|
||||
|
||||
RewriteBase /myapp/
|
||||
|
||||
The rest of the `.htaccess file` rewrites all requests through index.php, unless the file exists on the server (so your css, images, favicon, etc. are still loaded like normal). In most cases, you are done!
|
||||
|
||||
### 404 errors
|
||||
|
||||
If you get a "404 Not Found" error when trying to view a page then it's likely Apache is not configured to read the `.htaccess` file.
|
||||
|
||||
In the main apache configuration file (usually `httpd.conf`), or in the virtual server configuration file, check that the `AccessFileName` directive is set to `.htaccess` and the `AllowOverride` directive is set to `All`.
|
||||
|
||||
AccessFileName .htaccess
|
||||
|
||||
<Directory "/var/www/html/myapp">
|
||||
AllowOverride All
|
||||
</Directory>
|
||||
|
||||
|
||||
### Failed!
|
||||
|
||||
If you get a "Internal Server Error" or "No input file specified" error, try changing:
|
||||
|
||||
RewriteRule ^(?:application|modules|system)\b - [F,L]
|
||||
|
||||
Instead, we can try a slash:
|
||||
|
||||
RewriteRule ^(application|modules|system)/ - [F,L]
|
||||
|
||||
If that doesn't work, try changing:
|
||||
|
||||
RewriteRule .* index.php/$0 [PT]
|
||||
|
||||
To something more simple:
|
||||
|
||||
RewriteRule .* index.php [PT]
|
||||
|
||||
### Still Failed!
|
||||
|
||||
If you are still getting errors, check to make sure that your host supports URL `mod_rewrite`. If you can change the Apache configuration, add these lines to the configuration, usually `httpd.conf`:
|
||||
|
||||
<Directory "/var/www/html/myapp">
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
AllowOverride All
|
||||
</Directory>
|
||||
|
||||
You should also check your Apache logs to see if they can shed some light on the error.
|
||||
|
||||
## NGINX
|
||||
|
||||
It is hard to give examples of nginx configuration, but here is a sample for a server:
|
||||
|
||||
location / {
|
||||
index index.php index.html index.htm;
|
||||
try_files $uri index.php;
|
||||
}
|
||||
|
||||
location = index.php {
|
||||
include fastcgi.conf;
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_index index.php;
|
||||
}
|
||||
|
||||
If you are having issues getting this working, enable debug level logging in nginx and check the access and error logs.
|
99
includes/kohana/system/guide/kohana/tutorials/error-pages.md
Normal file
99
includes/kohana/system/guide/kohana/tutorials/error-pages.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# Custom Error Pages
|
||||
|
||||
Custom error pages allow you to display a friendly error message to users, rather than the standard Kohana stack trace.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. You will need `'errors' => TRUE` passed to [Kohana::init]. This will convert PHP-errors into exceptions which are easier to handle (The default value is `TRUE`).
|
||||
2. Custom error pages will only be used to handle throw [HTTP_Exception]'s. If you simply set a status of, for example, 404 via [Respose::status] the custom page will not be used.
|
||||
|
||||
## Extending the HTTP_Exception classes
|
||||
|
||||
Handling [HTTP_Exception]'s in Kohana has become easier with the changes introduced in 3.3.
|
||||
|
||||
For each [HTTP_Exception] class we can individually override the generation of the [Response] instance.
|
||||
|
||||
[!!] Note: We can also use HMVC to issue a sub-request to another page rather than generating the [Response] in the [HTTP_Exception] itself.
|
||||
|
||||
For example, to handle 404 pages we can do this in APPPATH/classes/HTTP/Exception/404.php:
|
||||
|
||||
class HTTP_Exception_404 extends Kohana_HTTP_Exception_404 {
|
||||
|
||||
/**
|
||||
* Generate a Response for the 404 Exception.
|
||||
*
|
||||
* The user should be shown a nice 404 page.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function get_response()
|
||||
{
|
||||
$view = View::factory('errors/404');
|
||||
|
||||
// Remembering that `$this` is an instance of HTTP_Exception_404
|
||||
$view->message = $this->getMessage();
|
||||
|
||||
$response = Response::factory()
|
||||
->status(404)
|
||||
->body($view->render());
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
Another example, this time to handle 401 Unauthorized errors (aka "Not Logged In") we can do this in APPPATH/classes/HTTP/Exception/401.php:
|
||||
|
||||
class HTTP_Exception_401 extends Kohana_HTTP_Exception_401 {
|
||||
|
||||
/**
|
||||
* Generate a Response for the 401 Exception.
|
||||
*
|
||||
* The user should be redirect to a login page.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function get_response()
|
||||
{
|
||||
$response = Response::factory()
|
||||
->status(401)
|
||||
->headers('Location', URL::site('account/login'));
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
Finally, to override the default [Response] for all [HTTP_Exception]'s without a more specific override we can do this in APPPATH/classes/HTTP/Exception.php:
|
||||
|
||||
class HTTP_Exception extends Kohana_HTTP_Exception {
|
||||
|
||||
/**
|
||||
* Generate a Response for all Exceptions without a more specific override
|
||||
*
|
||||
* The user should see a nice error page, however, if we are in development
|
||||
* mode we should show the normal Kohana error page.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function get_response()
|
||||
{
|
||||
// Lets log the Exception, Just in case it's important!
|
||||
Kohana_Exception::log($this);
|
||||
|
||||
if (Kohana::$environment >= Kohana::DEVELOPMENT)
|
||||
{
|
||||
// Show the normal Kohana error page.
|
||||
return parent::get_response();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generate a nicer looking "Oops" page.
|
||||
$view = View::factory('errors/default');
|
||||
|
||||
$response = Response::factory()
|
||||
->status($this->getCode())
|
||||
->body($view->render());
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
}
|
143
includes/kohana/system/guide/kohana/tutorials/git.md
Normal file
143
includes/kohana/system/guide/kohana/tutorials/git.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# Creating a New Application
|
||||
|
||||
[!!] The following examples assume that your web server is already set up, and you are going to create a new application at <http://localhost/gitorial/>.
|
||||
|
||||
Using your console, change to the empty directory `gitorial` and run `git init`. This will create the bare structure for a new git repository.
|
||||
|
||||
Next, we will create a [submodule](http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html) for the `system` directory. Go to <http://github.com/kohana/core> and copy the "Clone URL":
|
||||
|
||||

|
||||
|
||||
Now use the URL to create the submodule for `system`:
|
||||
|
||||
git submodule add git://github.com/kohana/core.git system
|
||||
|
||||
[!!] This will create a link to the current development version of the next stable release. The development version should almost always be safe to use, have the same API as the current stable download with bugfixes applied.
|
||||
|
||||
Now add whatever submodules you need. For example, if you need the [Database] module:
|
||||
|
||||
git submodule add git://github.com/kohana/database.git modules/database
|
||||
|
||||
After submodules are added, they must be initialized:
|
||||
|
||||
git submodule init
|
||||
|
||||
Now that the submodules are added, you can commit them:
|
||||
|
||||
git commit -m 'Added initial submodules'
|
||||
|
||||
Next, create the application directory structure. This is the bare minimum required:
|
||||
|
||||
mkdir -p application/classes/{Controller,Model}
|
||||
mkdir -p application/{config,views}
|
||||
mkdir -m 0777 -p application/{cache,logs}
|
||||
|
||||
If you run `find application` you should see this:
|
||||
|
||||
application
|
||||
application/cache
|
||||
application/config
|
||||
application/classes
|
||||
application/classes/Controller
|
||||
application/classes/Model
|
||||
application/logs
|
||||
application/views
|
||||
|
||||
We don't want git to track log or cache files, so add a `.gitignore` file to each of the directories. This will ignore all non-hidden files:
|
||||
|
||||
echo '[^.]*' > application/{logs,cache}/.gitignore
|
||||
|
||||
[!!] Git ignores empty directories, so adding a `.gitignore` file also makes sure that git will track the directory, but not the files within it.
|
||||
|
||||
Now we need the `index.php` and `bootstrap.php` files:
|
||||
|
||||
wget https://github.com/kohana/kohana/raw/3.3/master/index.php --no-check-certificate
|
||||
wget https://github.com/kohana/kohana/raw/3.3/master/application/bootstrap.php --no-check-certificate -O application/bootstrap.php
|
||||
|
||||
Commit these changes too:
|
||||
|
||||
git add application
|
||||
git commit -m 'Added initial directory structure'
|
||||
|
||||
That's all there is to it. You now have an application that is using Git for versioning.
|
||||
|
||||
## Adding Submodules
|
||||
To add a new submodule complete the following steps:
|
||||
|
||||
1. run the following code - git submodule add repository path for each new submodule e.g.:
|
||||
|
||||
git submodule add git://github.com/shadowhand/sprig.git modules/sprig
|
||||
|
||||
2. then init and update the submodules:
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
## Updating Submodules
|
||||
|
||||
At some point you will probably also want to upgrade your submodules. To update all of your submodules to the latest `HEAD` version:
|
||||
|
||||
git submodule foreach 'git checkout 3.3/master && git pull origin 3.3/master'
|
||||
|
||||
To update a single submodule, for example, `system`:
|
||||
|
||||
cd system
|
||||
git checkout 3.3/master
|
||||
git pull origin 3.3/master
|
||||
cd ..
|
||||
git add system
|
||||
git commit -m 'Updated system to latest version'
|
||||
|
||||
If you want to update a single submodule to a specific commit:
|
||||
|
||||
cd modules/database
|
||||
git pull origin 3.3/master
|
||||
git checkout fbfdea919028b951c23c3d99d2bc1f5bbeda0c0b
|
||||
cd ../..
|
||||
git add database
|
||||
git commit -m 'Updated database module'
|
||||
|
||||
Note that you can also check out the commit at a tagged official release point, for example:
|
||||
|
||||
git checkout v3.3.0
|
||||
|
||||
Simply run `git tag` without arguments to get a list of all tags.
|
||||
|
||||
## Removing Submodules
|
||||
To remove a submodule that is no longer needed complete the following steps:
|
||||
|
||||
1. open .gitmodules and remove the reference to the to submodule
|
||||
It will look something like this:
|
||||
|
||||
[submodule "modules/auth"]
|
||||
path = modules/auth
|
||||
url = git://github.com/kohana/auth.git
|
||||
|
||||
2. open .git/config and remove the reference to the to submodule\\
|
||||
|
||||
[submodule "modules/auth"]
|
||||
url = git://github.com/kohana/auth.git
|
||||
|
||||
3. run git rm --cached path/to/submodule, e.g.
|
||||
|
||||
git rm --cached modules/auth
|
||||
|
||||
**Note:** Do not put a trailing slash at the end of path. If you put a trailing slash at the end of the command, it will fail.
|
||||
|
||||
## Updating Remote Repository URL
|
||||
|
||||
During the development of a project, the source of a submodule may change for any reason (you've created your own fork, the server URL changed, the repository name or path changed, etc...) and you'll have to update those changes. To do so, you'll need to perform the following steps:
|
||||
|
||||
1. edit the .gitmodules file, and change the URL for the submodules which changed.
|
||||
|
||||
2. in your source tree's root run:
|
||||
|
||||
git submodule sync
|
||||
|
||||
3. run `git init` to update the project's repository configuration with the new URLs:
|
||||
|
||||
git submodule init
|
||||
|
||||
And it's done, now you can continue pushing and pulling your submodules with no problems.
|
||||
|
||||
Source: http://jtrancas.wordpress.com/2011/02/06/git-submodule-location/
|
106
includes/kohana/system/guide/kohana/tutorials/hello-world.md
Normal file
106
includes/kohana/system/guide/kohana/tutorials/hello-world.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# Hello, World
|
||||
|
||||
Just about every framework ever written has some kind of hello world example included, so it'd be pretty rude of us to break this tradition!
|
||||
|
||||
We'll start out by creating a very very basic hello world, and then we'll expand it to follow MVC principles.
|
||||
|
||||
## Bare bones
|
||||
|
||||
First off we have to make a controller that Kohana can use to handle a request.
|
||||
|
||||
Create the file `application/classes/Controller/Hello.php` in your application folder and fill it out like so:
|
||||
|
||||
<?php defined('SYSPATH') OR die('No Direct Script Access');
|
||||
|
||||
Class Controller_Hello extends Controller
|
||||
{
|
||||
public function action_index()
|
||||
{
|
||||
echo 'hello, world!';
|
||||
}
|
||||
}
|
||||
|
||||
Lets see what's going on here:
|
||||
|
||||
`<?php defined('SYSPATH') OR die('No Direct Script Access');`
|
||||
: You should recognize the first tag as an opening php tag (if you don't you should probably [learn php](http://php.net)). What follows is a small check that makes sure that this file is being included by Kohana. It stops people from accessing files directly from the url.
|
||||
|
||||
`Class Controller_Hello extends Controller`
|
||||
: This line declares our controller, each controller class has to be prefixed with `Controller_` and an underscore delimited path to the folder the controller is in (see [Conventions and styles](about.conventions) for more info). Each controller should also extend the base `Controller` class which provides a standard structure for controllers.
|
||||
|
||||
|
||||
`public function action_index()`
|
||||
: This defines the "index" action of our controller. Kohana will attempt to call this action if the user hasn't specified an action. (See [Routes, URLs and Links](tutorials.urls))
|
||||
|
||||
`echo 'hello, world!';`
|
||||
: And this is the line which outputs the customary phrase!
|
||||
|
||||
Now if you open your browser and go to http://localhost/index.php/hello you should see something like:
|
||||
|
||||

|
||||
|
||||
## That was good, but we can do better
|
||||
|
||||
What we did in the previous section was a good example of how easy it to create an *extremely* basic Kohana app. (In fact it's so basic, that you should never make it again!)
|
||||
|
||||
If you've ever heard anything about MVC you'll probably have realised that echoing content out in a controller is strictly against the principles of MVC.
|
||||
|
||||
The proper way to code with an MVC framework is to use _views_ to handle the presentation of your application, and allow the controller to do what it does best – control the flow of the request!
|
||||
|
||||
Lets change our original controller slightly:
|
||||
|
||||
<?php defined('SYSPATH') OR die('No Direct Script Access');
|
||||
|
||||
Class Controller_Hello extends Controller_Template
|
||||
{
|
||||
public $template = 'site';
|
||||
|
||||
public function action_index()
|
||||
{
|
||||
$this->template->message = 'hello, world!';
|
||||
}
|
||||
}
|
||||
|
||||
`extends Controller_Template`
|
||||
: We're now extending the template controller, it makes it more convenient to use views within our controller.
|
||||
|
||||
`public $template = 'site';`
|
||||
: The template controller needs to know what template you want to use. It'll automatically load the view defined in this variable and assign the view object to it.
|
||||
|
||||
`$this->template->message = 'hello, world!';`
|
||||
: `$this->template` is a reference to the view object for our site template. What we're doing here is assigning a variable called "message", with a value of "hello, world!" to the view.
|
||||
|
||||
Now lets try running our code...
|
||||
|
||||

|
||||
|
||||
For some reason Kohana's thrown a wobbly and isn't showing our amazing message.
|
||||
|
||||
If we look at the error message we can see that the View library wasn't able to find our site template, probably because we haven't made it yet – *doh*!
|
||||
|
||||
Let's go and make the view file `application/views/site.php` for our message:
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>We've got a message for you!</title>
|
||||
<style type="text/css">
|
||||
body {font-family: Georgia;}
|
||||
h1 {font-style: italic;}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1><?php echo $message; ?></h1>
|
||||
<p>We just wanted to say it! :)</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
If we refresh the page then we can see the fruits of our labour:
|
||||
|
||||

|
||||
|
||||
## Stage 3 – Profit!
|
||||
|
||||
In this tutorial you've learnt how to create a controller and use a view to separate your logic from your display.
|
||||
|
||||
This is obviously a very basic introduction to working with Kohana and doesn't even scrape the potential you have when developing applications with it.
|
219
includes/kohana/system/guide/kohana/tutorials/library-kohana.md
Normal file
219
includes/kohana/system/guide/kohana/tutorials/library-kohana.md
Normal file
@@ -0,0 +1,219 @@
|
||||
# Importing Kohana as a Library
|
||||
|
||||
If you're working with an existing codebase it's often difficult to modernise the code as it would mean a complete rewrite and there's rarely the time. An alternative is to improve the codebase incrementally as best you can, gradually outsourcing code to external libraries to reduce the amount of old code there is to maintain.
|
||||
|
||||
This tutorial describes how to include the Kohana PHP framework into existing PHP applications, without having to use the routing and HMVC request handling features.
|
||||
|
||||
[!!] The code modified in this tutorial was copied from Kohana version 3.1.x. You may need to update it to work with future releases.
|
||||
|
||||
In normal usage of the Kohana framework, the `index.php` file acts as the request handler; it sets up the environment, loads the system configuration, and then handles the request (see [Request Flow](flow)).
|
||||
We'll walk you through the steps required to create a file we'll call `include.php` which will allow you to include Kohana from exiting PHP applications.
|
||||
|
||||
## Demo application
|
||||
|
||||
The following file will serve as our (insultingly simple) demo application for this tutorial.
|
||||
|
||||
### File: `demo.php`
|
||||
|
||||
~~~
|
||||
<?php
|
||||
$content = 'Hello World';
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<title>Demo page</title>
|
||||
</head>
|
||||
<body>
|
||||
<?php echo $content; ?>
|
||||
</body>
|
||||
</html>
|
||||
~~~
|
||||
|
||||
## Install Kohana
|
||||
|
||||
[Download and install the Kohana framework](install); from this point on, we'll be referring to the location of the Kohana libraries as the `kohana` directory.
|
||||
|
||||
## Create a common setup file
|
||||
|
||||
Since `index.php` and `include.php` will duplicate a lot of code, we're going to move that code to a third file, `common.php`. The bulk of the code is unchanged; we've changed the install check to exit rather than return after rendering, and removed the request execution.
|
||||
|
||||
The new file creates the initial request object, rather than fully executing the request, so that, if you do define routes, the `Request::$initial` variable will be set up correctly.
|
||||
|
||||
### File: `kohana/common.php`
|
||||
|
||||
~~~
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The directory in which your application specific resources are located.
|
||||
* The application directory must contain the bootstrap.php file.
|
||||
*
|
||||
* @link http://kohanaframework.org/guide/about.install#application
|
||||
*/
|
||||
$application = 'application';
|
||||
|
||||
/**
|
||||
* The directory in which your modules are located.
|
||||
*
|
||||
* @link http://kohanaframework.org/guide/about.install#modules
|
||||
*/
|
||||
$modules = 'modules';
|
||||
|
||||
/**
|
||||
* The directory in which the Kohana resources are located. The system
|
||||
* directory must contain the classes/kohana.php file.
|
||||
*
|
||||
* @link http://kohanaframework.org/guide/about.install#system
|
||||
*/
|
||||
$system = 'system';
|
||||
|
||||
/**
|
||||
* The default extension of resource files. If you change this, all resources
|
||||
* must be renamed to use the new extension.
|
||||
*
|
||||
* @link http://kohanaframework.org/guide/about.install#ext
|
||||
*/
|
||||
define('EXT', '.php');
|
||||
|
||||
/**
|
||||
* Set the PHP error reporting level. If you set this in php.ini, you remove this.
|
||||
* @link http://www.php.net/manual/errorfunc.configuration#ini.error-reporting
|
||||
*
|
||||
* When developing your application, it is highly recommended to enable notices
|
||||
* and strict warnings. Enable them by using: E_ALL | E_STRICT
|
||||
*
|
||||
* In a production environment, it is safe to ignore notices and strict warnings.
|
||||
* Disable them by using: E_ALL ^ E_NOTICE
|
||||
*
|
||||
* When using a legacy application with PHP >= 5.3, it is recommended to disable
|
||||
* deprecated notices. Disable with: E_ALL & ~E_DEPRECATED
|
||||
*/
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
/**
|
||||
* End of standard configuration! Changing any of the code below should only be
|
||||
* attempted by those with a working knowledge of Kohana internals.
|
||||
*
|
||||
* @link http://kohanaframework.org/guide/using.configuration
|
||||
*/
|
||||
|
||||
// Set the full path to the docroot
|
||||
define('DOCROOT', realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR);
|
||||
|
||||
// Make the application relative to the docroot, for symlink'd index.php
|
||||
if ( ! is_dir($application) AND is_dir(DOCROOT.$application))
|
||||
$application = DOCROOT.$application;
|
||||
|
||||
// Make the modules relative to the docroot, for symlink'd index.php
|
||||
if ( ! is_dir($modules) AND is_dir(DOCROOT.$modules))
|
||||
$modules = DOCROOT.$modules;
|
||||
|
||||
// Make the system relative to the docroot, for symlink'd index.php
|
||||
if ( ! is_dir($system) AND is_dir(DOCROOT.$system))
|
||||
$system = DOCROOT.$system;
|
||||
|
||||
// Define the absolute paths for configured directories
|
||||
define('APPPATH', realpath($application).DIRECTORY_SEPARATOR);
|
||||
define('MODPATH', realpath($modules).DIRECTORY_SEPARATOR);
|
||||
define('SYSPATH', realpath($system).DIRECTORY_SEPARATOR);
|
||||
|
||||
// Clean up the configuration vars
|
||||
unset($application, $modules, $system);
|
||||
|
||||
if (file_exists('install'.EXT))
|
||||
{
|
||||
// Load the installation check
|
||||
include 'install'.EXT;
|
||||
exit; // Changes were made here
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the start time of the application, used for profiling.
|
||||
*/
|
||||
if ( ! defined('KOHANA_START_TIME'))
|
||||
{
|
||||
define('KOHANA_START_TIME', microtime(TRUE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the memory usage at the start of the application, used for profiling.
|
||||
*/
|
||||
if ( ! defined('KOHANA_START_MEMORY'))
|
||||
{
|
||||
define('KOHANA_START_MEMORY', memory_get_usage());
|
||||
}
|
||||
|
||||
// Bootstrap the application
|
||||
require APPPATH.'bootstrap'.EXT;
|
||||
|
||||
/**
|
||||
* Instantiate the request object. A source of the URI can be passed, eg: $_SERVER['PATH_INFO'].
|
||||
* If no source is specified, the URI will be automatically detected.
|
||||
*/
|
||||
Request::factory(); // Changes were made here
|
||||
~~~
|
||||
|
||||
## Alter Kohana's `index.php`
|
||||
|
||||
Having moved most of the code from Kohana's `index.php` to `common.php` the new `kohana/index.php` contains only this:
|
||||
|
||||
### File: `kohana/index.php`
|
||||
|
||||
~~~
|
||||
<?php
|
||||
|
||||
require_once 'common.php';
|
||||
|
||||
// Execute the request
|
||||
Request::$initial->execute()
|
||||
->execute()
|
||||
->send_headers(TRUE)
|
||||
->body();
|
||||
~~~
|
||||
|
||||
## Create the include file
|
||||
|
||||
Our `include.php` file is also pretty simple. The try-catch clause is needed because if the request matches no routes Kohana will throw an `HTTP_Exception_404` exception.
|
||||
|
||||
### File: `kohana/include.php`
|
||||
|
||||
~~~
|
||||
<?php
|
||||
|
||||
try {
|
||||
require_once 'common.php';
|
||||
}
|
||||
catch (HTTP_Exception_404 $e)
|
||||
{
|
||||
// The request did not match any routes; ignore the 404 exception.
|
||||
}
|
||||
~~~
|
||||
|
||||
**NB:** Due to the way Kohana's routing works, if the request matches no routes it will fail to instantiate an object, and `Request::$current` and `Request::$initial` will not be available.
|
||||
|
||||
## Integration
|
||||
|
||||
Now that we're set up, we can add Kohana into our application using a single include, and then we're good to go.
|
||||
|
||||
### File: `demo.php`
|
||||
|
||||
~~~
|
||||
<?php
|
||||
require_once 'kohana/include.php';
|
||||
|
||||
$content = 'Hello World';
|
||||
$content = HTML::anchor('http://kohanaframework.org/', $content);
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<title>Demo page</title>
|
||||
</head>
|
||||
<body>
|
||||
<?php echo $content; ?>
|
||||
<hr />
|
||||
<?php echo URL::base(); ?>
|
||||
<hr />
|
||||
<?php echo Debug::dump(array(1,2,3,4,5)); ?>
|
||||
</body>
|
||||
</html>
|
||||
~~~
|
@@ -0,0 +1,54 @@
|
||||
# Sharing Kohana
|
||||
|
||||
Kohana follows a [front controller pattern](http://en.wikipedia.org/wiki/Front_Controller_pattern "Front Controller pattern") (which means that all requests are sent to `index.php`) and as such the [filesystem](files) is very configurable. Inside of `index.php` you can change the `$application`, `$modules`, and `$system` paths.
|
||||
|
||||
[!!] There is a security check at the top of every Kohana file to prevent it from being accessed without using the front controller. Also, the `.htaccess` file should protect those folders as well. Moving the application, modules, and system directories to a location that cannot be accessed via the web can add another layer of security, but is optional.
|
||||
|
||||
The `$application` variable lets you set the directory that contains your application files. By default, this is `application`. The `$modules` variable lets you set the directory that contains module files. The `$system` variable lets you set the directory that contains the default Kohana files. You can move these three directories anywhere.
|
||||
|
||||
For instance, by default the directories are set up like this:
|
||||
|
||||
www/
|
||||
index.php
|
||||
application/
|
||||
modules/
|
||||
system/
|
||||
|
||||
You could move the directories out of the web root so they look like this:
|
||||
|
||||
application/
|
||||
modules/
|
||||
system/
|
||||
www/
|
||||
index.php
|
||||
|
||||
Then you would need to change the settings in `index.php` to be:
|
||||
|
||||
$application = '../application';
|
||||
$modules = '../modules';
|
||||
$system = '../system';
|
||||
|
||||
## Sharing system and modules
|
||||
|
||||
To take this a step further, we could point several Kohana apps to the same system and modules folders. For example (and this is just an example, you could arrange these anyway you want):
|
||||
|
||||
apps/
|
||||
foobar/
|
||||
application/
|
||||
www/
|
||||
bazbar/
|
||||
application/
|
||||
www/
|
||||
kohana/
|
||||
3.0.6/
|
||||
3.0.7/
|
||||
3.0.8/
|
||||
modules/
|
||||
|
||||
And you would need to change the settings in `index.php` to be:
|
||||
|
||||
$application = '../application';
|
||||
$system = '../../../kohana/3.0.6';
|
||||
$modules = '../../../kohana/modules';
|
||||
|
||||
With this method each app can point to a central copy of Kohana, and when you add a new version, allow you to quickly update the apps by editing their respective `index.php` files.
|
@@ -0,0 +1 @@
|
||||
Simple example of controller model and view working together.
|
@@ -0,0 +1,7 @@
|
||||
Making a template driven site.
|
||||
|
||||
<http://kerkness.ca/wiki/doku.php?id=template-site:create_the_template>
|
||||
|
||||
<http://kerkness.ca/wiki/doku.php?id=template-site:extending_the_template_controller>
|
||||
|
||||
<http://kerkness.ca/wiki/doku.php?id=template-site:basic_page_controller>
|
@@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
<http://kerkness.ca/wiki/doku.php?id=routing:static_pages>
|
||||
|
||||
<http://kerkness.ca/wiki/doku.php?id=routing:multi-language_with_a_route>
|
100
includes/kohana/system/guide/kohana/upgrading.md
Normal file
100
includes/kohana/system/guide/kohana/upgrading.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# Migrating from 3.2.x
|
||||
|
||||
## HVMC Isolation
|
||||
|
||||
HVMC Sub-request isolation has been improved to prevent exceptions leaking from this inner to the outer request. If you were previously catching any exceptions from sub-requests, you should now be checking the [Response] object returned from [Request::execute].
|
||||
|
||||
## HTTP Exceptions
|
||||
|
||||
The use of HTTP Exceptions is now encouraged over manually setting the [Response] status to, for example, '404'. This allows for easier custom error pages (detailed below);
|
||||
|
||||
The full list of supported codes can be seen in the SYSPATH/classes/HTTP/Exception/ folder.
|
||||
|
||||
Syntax:
|
||||
|
||||
throw HTTP_Exception::factory($code, $message, array $variables, Exception $previous);
|
||||
|
||||
Examples:
|
||||
|
||||
// Page Not Found
|
||||
throw HTTP_Exception::factory(404, 'The requested URL :uri was not found on this server.', array(
|
||||
':uri' => $this->request->uri(),
|
||||
));
|
||||
|
||||
// Unauthorized / Login Requied
|
||||
throw HTTP_Exception::factory(401)->authenticate('Basic realm="MySite"');
|
||||
|
||||
// Forbidden / Permission Deined
|
||||
throw HTTP_Exception::factory(403);
|
||||
|
||||
## Redirects (HTTP 300, 301, 302, 303, 307)
|
||||
|
||||
Redirects are no longer issued against the [Request] object. The new syntax from inside a controller is:
|
||||
|
||||
$this->redirect('http://www.google.com', 302);
|
||||
|
||||
or from outside a controller:
|
||||
|
||||
HTTP::redirect('http://www.google.com', 302);
|
||||
|
||||
## Custom Error Pages (HTTP 500, 404, 403, 401 etc)
|
||||
|
||||
Custom error pages are now easier than ever to implement, thanks to some of the changes brought about by the HVMC and Redirect changes above.
|
||||
|
||||
See [Custom Error Pages](tutorials/error-pages) for more details.
|
||||
|
||||
## Browser cache checking (ETags)
|
||||
|
||||
The Response::check_cache method has moved to [HTTP::check_cache], with an alias at [Controller::check_cache]. Previously, this method would be used from a controller like this:
|
||||
|
||||
$this->response->check_cache(sha1('my content'), Request $this->request);
|
||||
|
||||
Now, there are two options for using the method:
|
||||
|
||||
$this->check_cache(sha1('my content'));
|
||||
|
||||
which is an alias for:
|
||||
|
||||
HTTP::check_cache($this->request, $this->response, sha1('my content'));
|
||||
|
||||
## PSR-0 support (file/class naming conventions)
|
||||
|
||||
With the introduction of [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) support, the autoloading of classes is case sensitive. Now, the file (and folder) names must match the class name exactly.
|
||||
|
||||
Examples:
|
||||
|
||||
Kohana_Core
|
||||
|
||||
would be located in
|
||||
|
||||
classes/Kohana/Core.php
|
||||
|
||||
and
|
||||
|
||||
Kohana_HTTP_Header
|
||||
|
||||
would be located in
|
||||
|
||||
classes/Kohana/HTTP/Header.php
|
||||
|
||||
This also affects dynamically named classes such as drivers and ORMs. So for example, in the database config using `'mysql'` as the type instead of `'MySQL'` would throw a class not found error.
|
||||
|
||||
## Query Builder Identifier Escaping
|
||||
|
||||
The query builder will no longer detect columns like `COUNT("*")`. Instead, you will need to use `DB::expr()` any time you need an unescaped column. For example:
|
||||
|
||||
DB::select(DB::expr('COUNT(*)'))->from('users')->execute()
|
||||
|
||||
## Route Filters
|
||||
|
||||
In `3.3.0`, you can no longer pass a callback to `Route::uri()`. Instead, we've added the ability to define one or more filters which will be able to decide if the route matches and will also allow you to change any of the parameters. These filters will receive the `Route` object being tested, the currently matched `$params` array, and the `Request` object as the three parameters.
|
||||
|
||||
Route::set('route-name', 'some/uri/<id>')
|
||||
->filter(function($route, $params, $request) {
|
||||
// Returning FALSE will make this route not match
|
||||
// Returning an array will replace the $params sent to the controller
|
||||
});
|
||||
|
||||
These filters can be used for things like prepending the request method to the action, checking if a resource exists before matching the route, or any other logic that the URI alone cannot provide. You can add as many filters as needed so it's useful to keep filters as small as possible to make them reusable.
|
||||
|
||||
See [Routing](routing#route-filters) for more details.
|
Reference in New Issue
Block a user