diff --git a/application/bootstrap.php b/application/bootstrap.php index 0f4adad..f93f414 100644 --- a/application/bootstrap.php +++ b/application/bootstrap.php @@ -1,6 +1,20 @@ " + */ +if (isset($_SERVER['KOHANA_ENV'])) +{ + Kohana::$environment = constant('Kohana::'.strtoupper($_SERVER['KOHANA_ENV'])); +} /** * Initialize Kohana, setting the default options. @@ -57,27 +87,33 @@ Kohana::init(array( /** * Attach the file write to logging. Multiple writers are supported. */ -Kohana::$log->attach(new Kohana_Log_File(APPPATH.'logs')); +Kohana::$log->attach(new Log_File(APPPATH.'logs')); /** * Attach a file reader to config. Multiple readers are supported. */ -Kohana::$config->attach(new Kohana_Config_File); +Kohana::$config->attach(new Config_File); /** * Enable modules. Modules are referenced by a relative or absolute path. */ 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 + 'auth' => SMDPATH.'auth', // Basic authentication + 'cache' => SMDPATH.'cache', // Caching with multiple backends + // 'codebench' => SMDPATH.'codebench', // Benchmarking tool + 'database' => SMDPATH.'database', // Database access + // 'image' => SMDPATH.'image', // Image manipulation + 'orm' => SMDPATH.'orm', // Object Relationship Mapping + // 'unittest' => SMDPATH.'unittest', // Unit testing + // 'userguide' => SMDPATH.'userguide', // User guide and API documentation + )); + +/** + * Enable specalised interfaces + */ +Route::set('sections', '/(/(/(/)))', + array( + 'directory' => '('.implode('|',Kohana::config('config.method_directory')).')' )); /** @@ -97,15 +133,4 @@ Route::set('default/media', 'media(/)', array('file' => '.+')) 'action' => 'media', 'file' => NULL, )); - -if ( ! defined('SUPPRESS_REQUEST')) -{ - /** - * Execute the main request. A source of the URI can be passed, eg: $_SERVER['PATH_INFO']. - * If no source is specified, the URI will be automatically detected. - */ - echo Request::instance() - ->execute() - ->send_headers() - ->response; -} +?> diff --git a/includes/kohana/README.md b/includes/kohana/README.md index 97e31dc..e19aba8 100644 --- a/includes/kohana/README.md +++ b/includes/kohana/README.md @@ -1,3 +1,3 @@ -# Kohana PHP Framework, version 3.0 (dev) +# Kohana PHP Framework, version 3.1 (release) -This is the current development version of [Kohana](http://kohanaframework.org/). +This is the current release version of [Kohana](http://kohanaframework.org/). diff --git a/includes/kohana/application/bootstrap.php b/includes/kohana/application/bootstrap.php new file mode 100644 index 0000000..d6081cd --- /dev/null +++ b/includes/kohana/application/bootstrap.php @@ -0,0 +1,118 @@ +" + */ +if (isset($_SERVER['KOHANA_ENV'])) +{ + Kohana::$environment = constant('Kohana::'.strtoupper($_SERVER['KOHANA_ENV'])); +} + +/** + * Initialize Kohana, setting the default options. + * + * The following options are available: + * + * - string base_url path, and optionally domain, of your application NULL + * - string index_file name of your index file, usually "index.php" index.php + * - string charset internal character set used for input and output utf-8 + * - string cache_dir set the internal cache directory APPPATH/cache + * - boolean errors enable or disable error handling TRUE + * - boolean profile enable or disable internal profiling TRUE + * - boolean caching enable or disable internal caching FALSE + */ +Kohana::init(array( + 'base_url' => '/', +)); + +/** + * Attach the file write to logging. Multiple writers are supported. + */ +Kohana::$log->attach(new Log_File(APPPATH.'logs')); + +/** + * Attach a file reader to config. Multiple readers are supported. + */ +Kohana::$config->attach(new Config_File); + +/** + * Enable modules. Modules are referenced by a relative or absolute path. + */ +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 + // 'unittest' => MODPATH.'unittest', // Unit testing + // 'userguide' => MODPATH.'userguide', // User guide and API documentation + )); + +/** + * Set the routes. Each route must have a minimum of a name, a URI and a set of + * defaults for the URI. + */ +Route::set('default', '((/(/)))') + ->defaults(array( + 'controller' => 'welcome', + 'action' => 'index', + )); diff --git a/includes/kohana/application/classes/controller/welcome.php b/includes/kohana/application/classes/controller/welcome.php new file mode 100644 index 0000000..0984eff --- /dev/null +++ b/includes/kohana/application/classes/controller/welcome.php @@ -0,0 +1,10 @@ +response->body('hello, world!'); + } + +} // End Welcome diff --git a/includes/kohana/build.xml b/includes/kohana/build.xml deleted file mode 100644 index daea9ed..0000000 --- a/includes/kohana/build.xml +++ /dev/null @@ -1,233 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/includes/kohana/example.htaccess b/includes/kohana/example.htaccess deleted file mode 100644 index 53b8ccb..0000000 --- a/includes/kohana/example.htaccess +++ /dev/null @@ -1,21 +0,0 @@ -# Turn on URL rewriting -RewriteEngine On - -# Installation directory -RewriteBase / - -# Protect hidden files from being viewed - - Order Deny,Allow - Deny From All - - -# Protect application and system files from being viewed -RewriteRule ^(?:application|modules|system)\b.* index.php/$0 [L] - -# Allow any files or directories that exist to be displayed directly -RewriteCond %{REQUEST_FILENAME} !-f -RewriteCond %{REQUEST_FILENAME} !-d - -# Rewrite all other URLs to index.php/URL -RewriteRule .* index.php/$0 [PT] diff --git a/includes/kohana/install.php b/includes/kohana/install.php index a522c2f..cbb0a4c 100644 --- a/includes/kohana/install.php +++ b/includes/kohana/install.php @@ -1,20 +1,4 @@ - + @@ -179,12 +163,20 @@ else

+ + + + + + + + - + @@ -203,6 +195,14 @@ else + + + + + + + + diff --git a/includes/kohana/modules/auth/README.md b/includes/kohana/modules/auth/README.md new file mode 100644 index 0000000..27ac9cd --- /dev/null +++ b/includes/kohana/modules/auth/README.md @@ -0,0 +1,13 @@ +New Age Auth +--- + +I've forked the main Auth module because there were some fundamental flaws with it: + + 1. It's trivial to [bruteforce](http://dev.kohanaframework.org/issues/3163) publicly hidden salt hashes. + - I've fixed this by switching the password hashing algorithm to the more secure secret-key based hash_hmac method. + 2. ORM drivers were included. + - I've fixed this by simply removing them. They cause confusion with new users because they think that Auth requires ORM. The only driver currently provided by default is the file driver. + 3. Auth::get_user()'s api is inconsistent because it returns different data types. + - I've fixed this by returning an empty user model by default. You can override what gets returned (if you've changed your user model class name for instance) by overloading the get_user() method in your application. + +These changes should be merged into the mainline branch eventually, but they completely break the API, so likely won't be done until 3.1. \ No newline at end of file diff --git a/includes/kohana/modules/auth/classes/kohana/auth.php b/includes/kohana/modules/auth/classes/kohana/auth.php index 51128f6..c5030e8 100644 --- a/includes/kohana/modules/auth/classes/kohana/auth.php +++ b/includes/kohana/modules/auth/classes/kohana/auth.php @@ -27,7 +27,7 @@ abstract class Kohana_Auth { if ( ! $type = $config->get('driver')) { - $type = 'ORM'; + $type = 'file'; } // Set the session class name @@ -40,16 +40,6 @@ abstract class Kohana_Auth { return Auth::$_instance; } - /** - * Create an instance of Auth. - * - * @return Auth - */ - public static function factory($config = array()) - { - return new Auth($config); - } - protected $_session; protected $_config; @@ -61,9 +51,6 @@ abstract class Kohana_Auth { */ public function __construct($config = array()) { - // Clean up the salt pattern and split it into an array - $config['salt_pattern'] = preg_split('/,\s*/', Kohana::config('auth')->get('salt_pattern')); - // Save the config in the object $this->_config = $config; @@ -78,13 +65,13 @@ abstract class Kohana_Auth { /** * Gets the currently logged in user from the session. - * Returns FALSE if no user is currently logged in. + * Returns NULL if no user is currently logged in. * * @return mixed */ - public function get_user() + public function get_user($default = NULL) { - return $this->_session->get($this->_config['session_key'], FALSE); + return $this->_session->get($this->_config['session_key'], $default); } /** @@ -102,11 +89,8 @@ abstract class Kohana_Auth { if (is_string($password)) { - // Get the salt from the stored password - $salt = $this->find_salt($this->password($username)); - - // Create a hashed password using the salt from the stored password - $password = $this->hash_password($password, $salt); + // Create a hashed password + $password = $this->hash($password); } return $this->_login($username, $password, $remember); @@ -141,90 +125,40 @@ abstract class Kohana_Auth { /** * Check if there is an active session. Optionally allows checking for a - * specific role. + * specific role. * * @param string role name * @return mixed */ public function logged_in($role = NULL) { - return FALSE !== $this->get_user(); + return ($this->get_user() !== NULL); } /** - * Creates a hashed password from a plaintext password, inserting salt - * based on the configured salt pattern. + * Creates a hashed hmac password from a plaintext password. This + * method is deprecated, [Auth::hash] should be used instead. * + * @deprecated * @param string plaintext password - * @return string hashed password string */ - public function hash_password($password, $salt = FALSE) + public function hash_password($password) { - if ($salt === FALSE) - { - // Create a salt seed, same length as the number of offsets in the pattern - $salt = substr($this->hash(uniqid(NULL, TRUE)), 0, count($this->_config['salt_pattern'])); - } - - // Password hash that the salt will be inserted into - $hash = $this->hash($salt.$password); - - // Change salt to an array - $salt = str_split($salt, 1); - - // Returned password - $password = ''; - - // Used to calculate the length of splits - $last_offset = 0; - - foreach ($this->_config['salt_pattern'] as $offset) - { - // Split a new part of the hash off - $part = substr($hash, 0, $offset - $last_offset); - - // Cut the current part out of the hash - $hash = substr($hash, $offset - $last_offset); - - // Add the part to the password, appending the salt character - $password .= $part.array_shift($salt); - - // Set the last offset to the current offset - $last_offset = $offset; - } - - // Return the password, with the remaining hash appended - return $password.$hash; + return $this->hash($password); } /** - * Perform a hash, using the configured method. + * Perform a hmac hash, using the configured method. * * @param string string to hash * @return string */ public function hash($str) { - return hash($this->_config['hash_method'], $str); - } + if ( ! $this->_config['hash_key']) + throw new Kohana_Exception('A valid hash key must be set in your auth config.'); - /** - * Finds the salt from a password, based on the configured salt pattern. - * - * @param string hashed password - * @return string - */ - public function find_salt($password) - { - $salt = ''; - - foreach ($this->_config['salt_pattern'] as $i => $offset) - { - // Find salt characters, take a good long look... - $salt .= substr($password, $offset + $i, 1); - } - - return $salt; + return hash_hmac($this->_config['hash_method'], $str, $this->_config['hash_key']); } protected function complete_login($user) @@ -238,4 +172,4 @@ abstract class Kohana_Auth { return TRUE; } -} // End Auth \ No newline at end of file +} // End Auth diff --git a/includes/kohana/modules/auth/classes/model/auth/role.php b/includes/kohana/modules/auth/classes/model/auth/role.php deleted file mode 100644 index 565c4f0..0000000 --- a/includes/kohana/modules/auth/classes/model/auth/role.php +++ /dev/null @@ -1,27 +0,0 @@ - array('through' => 'roles_users')); - - // Validation rules - protected $_rules = array( - 'name' => array( - 'not_empty' => NULL, - 'min_length' => array(4), - 'max_length' => array(32), - ), - 'description' => array( - 'max_length' => array(255), - ), - ); - -} // End Auth Role Model \ No newline at end of file diff --git a/includes/kohana/modules/auth/classes/model/auth/user.php b/includes/kohana/modules/auth/classes/model/auth/user.php deleted file mode 100644 index 35a512d..0000000 --- a/includes/kohana/modules/auth/classes/model/auth/user.php +++ /dev/null @@ -1,244 +0,0 @@ - array('model' => 'user_token'), - 'roles' => array('model' => 'role', 'through' => 'roles_users'), - ); - - // Validation rules - protected $_rules = array( - 'username' => array( - 'not_empty' => NULL, - 'min_length' => array(4), - 'max_length' => array(32), - 'regex' => array('/^[-\pL\pN_.]++$/uD'), - ), - 'password' => array( - 'not_empty' => NULL, - 'min_length' => array(5), - 'max_length' => array(42), - ), - 'password_confirm' => array( - 'matches' => array('password'), - ), - 'email' => array( - 'not_empty' => NULL, - 'min_length' => array(4), - 'max_length' => array(127), - 'email' => NULL, - ), - ); - - // Validation callbacks - protected $_callbacks = array( - 'username' => array('username_available'), - 'email' => array('email_available'), - ); - - // Field labels - protected $_labels = array( - 'username' => 'username', - 'email' => 'email address', - 'password' => 'password', - 'password_confirm' => 'password confirmation', - ); - - // Columns to ignore - protected $_ignored_columns = array('password_confirm'); - - /** - * Validates login information from an array, and optionally redirects - * after a successful login. - * - * @param array values to check - * @param string URI or URL to redirect to - * @return boolean - */ - public function login(array & $array, $redirect = FALSE) - { - $fieldname = $this->unique_key($array['username']); - $array = Validate::factory($array) - ->label('username', $this->_labels[$fieldname]) - ->label('password', $this->_labels['password']) - ->filter(TRUE, 'trim') - ->rules('username', $this->_rules[$fieldname]) - ->rules('password', $this->_rules['password']); - - // Get the remember login option - $remember = isset($array['remember']); - - // Login starts out invalid - $status = FALSE; - - if ($array->check()) - { - // Attempt to load the user - $this->where($fieldname, '=', $array['username'])->find(); - - if ($this->loaded() AND Auth::instance()->login($this, $array['password'], $remember)) - { - if (is_string($redirect)) - { - // Redirect after a successful login - Request::instance()->redirect($redirect); - } - - // Login is successful - $status = TRUE; - } - else - { - $array->error('username', 'invalid'); - } - } - - return $status; - } - - /** - * Validates an array for a matching password and password_confirm field, - * and optionally redirects after a successful save. - * - * @param array values to check - * @param string URI or URL to redirect to - * @return boolean - */ - public function change_password(array & $array, $redirect = FALSE) - { - $array = Validate::factory($array) - ->label('password', $this->_labels['password']) - ->label('password_confirm', $this->_labels['password_confirm']) - ->filter(TRUE, 'trim') - ->rules('password', $this->_rules['password']) - ->rules('password_confirm', $this->_rules['password_confirm']); - - if ($status = $array->check()) - { - // Change the password - $this->password = $array['password']; - - if ($status = $this->save() AND is_string($redirect)) - { - // Redirect to the success page - Request::instance()->redirect($redirect); - } - } - - return $status; - } - - /** - * Complete the login for a user by incrementing the logins and saving login timestamp - * - * @return void - */ - public function complete_login() - { - if ( ! $this->_loaded) - { - // nothing to do - return; - } - - // Update the number of logins - $this->logins = new Database_Expression('logins + 1'); - - // Set the last login date - $this->last_login = time(); - - // Save the user - $this->save(); - } - - /** - * Does the reverse of unique_key_exists() by triggering error if username exists. - * Validation callback. - * - * @param Validate Validate object - * @param string field name - * @return void - */ - public function username_available(Validate $array, $field) - { - if ($this->unique_key_exists($array[$field], 'username')) - { - $array->error($field, 'username_available', array($array[$field])); - } - } - - /** - * Does the reverse of unique_key_exists() by triggering error if email exists. - * Validation callback. - * - * @param Validate Validate object - * @param string field name - * @return void - */ - public function email_available(Validate $array, $field) - { - if ($this->unique_key_exists($array[$field], 'email')) - { - $array->error($field, 'email_available', array($array[$field])); - } - } - - /** - * Tests if a unique key value exists in the database. - * - * @param mixed the value to test - * @param string field name - * @return boolean - */ - public function unique_key_exists($value, $field = NULL) - { - if ($field === NULL) - { - // Automatically determine field by looking at the value - $field = $this->unique_key($value); - } - - return (bool) DB::select(array('COUNT("*")', 'total_count')) - ->from($this->_table_name) - ->where($field, '=', $value) - ->where($this->_primary_key, '!=', $this->pk()) - ->execute($this->_db) - ->get('total_count'); - } - - /** - * Allows a model use both email and username as unique identifiers for login - * - * @param string unique value - * @return string field name - */ - public function unique_key($value) - { - return Validate::email($value) ? 'email' : 'username'; - } - - /** - * Saves the current object. Will hash password if it was changed. - * - * @return ORM - */ - public function save() - { - if (array_key_exists('password', $this->_changed)) - { - $this->_object['password'] = Auth::instance()->hash_password($this->_object['password']); - } - - return parent::save(); - } - -} // End Auth User Model \ No newline at end of file diff --git a/includes/kohana/modules/auth/config/auth.php b/includes/kohana/modules/auth/config/auth.php index c009819..0d80208 100644 --- a/includes/kohana/modules/auth/config/auth.php +++ b/includes/kohana/modules/auth/config/auth.php @@ -2,17 +2,15 @@ return array( - 'driver' => 'ORM', - 'hash_method' => 'sha1', - 'salt_pattern' => '1, 3, 5, 9, 14, 15, 20, 21, 28, 30', - 'lifetime' => 1209600, - 'session_key' => 'auth_user', - 'autologin_key' => 'auth_autologin', - 'forced_key' => 'auth_forced', + 'driver' => 'file', + 'hash_method' => 'sha256', + 'hash_key' => NULL, + 'lifetime' => 1209600, + 'session_key' => 'auth_user', // Username/password combinations for the Auth File driver 'users' => array( // 'admin' => 'b3154acf3a344170077d11bdb5fff31532f679a1919e716a02', ), -); \ No newline at end of file +); diff --git a/includes/kohana/modules/auth/config/userguide.php b/includes/kohana/modules/auth/config/userguide.php deleted file mode 100644 index b5606e8..0000000 --- a/includes/kohana/modules/auth/config/userguide.php +++ /dev/null @@ -1,23 +0,0 @@ - array( - - // This should be the path to this modules userguide pages, without the 'guide/'. Ex: '/guide/modulename/' would be 'modulename' - 'auth' => array( - - // Whether this modules userguide pages should be shown - 'enabled' => TRUE, - - // The name that should show up on the userguide index page - 'name' => 'Auth', - - // A short description of this module, shown on the index page - 'description' => 'User authentication and authorization.', - - // Copyright message, shown in the footer for this module - 'copyright' => '© 2008–2010 Kohana Team', - ) - ) -); \ No newline at end of file diff --git a/includes/kohana/modules/cache/classes/kohana/cache.php b/includes/kohana/modules/cache/classes/kohana/cache.php index 5c9ac4a..cdef449 100644 --- a/includes/kohana/modules/cache/classes/kohana/cache.php +++ b/includes/kohana/modules/cache/classes/kohana/cache.php @@ -138,7 +138,7 @@ abstract class Kohana_Cache { } /** - * @var Kohana_Config + * @var Config */ protected $_config; diff --git a/includes/kohana/modules/cache/classes/kohana/cache/apc.php b/includes/kohana/modules/cache/classes/kohana/cache/apc.php index 64ffe82..78765fe 100644 --- a/includes/kohana/modules/cache/classes/kohana/cache/apc.php +++ b/includes/kohana/modules/cache/classes/kohana/cache/apc.php @@ -71,7 +71,9 @@ class Kohana_Cache_Apc extends Cache { */ public function get($id, $default = NULL) { - return (($data = apc_fetch($this->_sanitize_id($id))) === FALSE) ? $default : $data; + $data = apc_fetch($this->_sanitize_id($id), $success); + + return $success ? $data : $default; } /** diff --git a/includes/kohana/modules/cache/classes/kohana/cache/file.php b/includes/kohana/modules/cache/classes/kohana/cache/file.php index 096ba36..0ace205 100644 --- a/includes/kohana/modules/cache/classes/kohana/cache/file.php +++ b/includes/kohana/modules/cache/classes/kohana/cache/file.php @@ -373,7 +373,7 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect { $name = $files->getFilename(); // If the name is not a dot - if ($name != '.' and $name != '..') + if ($name != '.' AND $name != '..' AND substr($file->getFilename(), 0, 1) == '.') { // Create new file resource $fp = new SplFileInfo($files->getRealPath()); diff --git a/includes/kohana/modules/codebench/classes/bench/datespan.php b/includes/kohana/modules/codebench/classes/bench/datespan.php index 6ea1f50..ff35479 100644 --- a/includes/kohana/modules/codebench/classes/bench/datespan.php +++ b/includes/kohana/modules/codebench/classes/bench/datespan.php @@ -29,7 +29,7 @@ class Bench_DateSpan extends Codebench { public static function bench_span_original($remote, $local = NULL, $output = 'years,months,weeks,days,hours,minutes,seconds') { // Array with the output formats - $output = preg_split('/[^a-z]+/', strtolower((string) $output)); + $output = preg_split('/[^a-z]+/', strtolower( (string) $output)); // Invalid output if (empty($output)) @@ -116,7 +116,7 @@ class Bench_DateSpan extends Codebench { public static function bench_span_use_array($remote, $local = NULL, $output = 'years,months,weeks,days,hours,minutes,seconds') { // Array with the output formats - $output = preg_split('/[^a-z]+/', strtolower((string) $output)); + $output = preg_split('/[^a-z]+/', strtolower( (string) $output)); // Invalid output if (empty($output)) diff --git a/includes/kohana/modules/codebench/classes/controller/codebench.php b/includes/kohana/modules/codebench/classes/controller/codebench.php index 52e8404..cdd9a70 100644 --- a/includes/kohana/modules/codebench/classes/controller/codebench.php +++ b/includes/kohana/modules/codebench/classes/controller/codebench.php @@ -17,7 +17,9 @@ class Controller_Codebench extends Kohana_Controller_Template { { // Convert submitted class name to URI segment if (isset($_POST['class'])) + { $this->request->redirect('codebench/'.trim($_POST['class'])); + } // Pass the class name on to the view $this->template->class = (string) $class; diff --git a/includes/kohana/modules/codebench/media/guide/codebench/codebench_screenshot1.png b/includes/kohana/modules/codebench/media/guide/codebench/codebench_screenshot1.png old mode 100755 new mode 100644 diff --git a/includes/kohana/modules/codebench/media/guide/codebench/codebench_screenshot2.png b/includes/kohana/modules/codebench/media/guide/codebench/codebench_screenshot2.png old mode 100755 new mode 100644 diff --git a/includes/kohana/modules/codebench/views/codebench.php b/includes/kohana/modules/codebench/views/codebench.php index 1961950..7b6ef2a 100644 --- a/includes/kohana/modules/codebench/views/codebench.php +++ b/includes/kohana/modules/codebench/views/codebench.php @@ -2,7 +2,7 @@ /** * Codebench — A benchmarking module. * - * @package Kohana + * @package Kohana/Codebench * @author Kohana Team * @copyright (c) 2009 Kohana Team * @license http://kohanaphp.com/license.html @@ -14,7 +14,9 @@ - <?php if ($class !== '') echo $class, ' · ' ?>Codebench + <?php if ($class !== ''): ?> + <?php echo $class, ' · ' ?> + <?php endif; ?>Codebench
PECL HTTP EnabledPassKohana can use the http extension for the Request_Client_External class.
cURL Enabled Pass Kohana requires cURL for the Remote class.Kohana can use the cURL extension for the Request_Client_External class.
Kohana requires GD v2 for the Image class.
MySQL EnabledPassKohana can use the MySQL extension to support MySQL databases.
PDO Enabled