summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--system/core/CodeIgniter.php2
-rw-r--r--system/core/Common.php2
-rw-r--r--system/core/Hooks.php2
-rw-r--r--system/core/Loader.php7
-rw-r--r--system/core/Router.php2
-rw-r--r--system/core/URI.php15
-rw-r--r--system/core/compat/hash.php51
-rw-r--r--system/database/DB_query_builder.php4
-rw-r--r--system/libraries/Encryption.php2
-rw-r--r--system/libraries/Form_validation.php12
-rw-r--r--system/libraries/Session/Session.php2
-rw-r--r--system/libraries/Zip.php2
-rw-r--r--tests/codeigniter/core/Lang_test.php26
-rw-r--r--tests/codeigniter/core/Loader_test.php49
-rw-r--r--tests/codeigniter/libraries/Form_validation_test.php250
-rw-r--r--user_guide_src/source/changelog.rst22
-rw-r--r--user_guide_src/source/conf.py4
-rw-r--r--user_guide_src/source/database/forge.rst4
-rw-r--r--user_guide_src/source/general/security.rst12
-rw-r--r--user_guide_src/source/installation/upgrade_300.rst2
-rw-r--r--user_guide_src/source/tutorial/static_pages.rst6
21 files changed, 430 insertions, 48 deletions
diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php
index d830c1829..ddf322749 100644
--- a/system/core/CodeIgniter.php
+++ b/system/core/CodeIgniter.php
@@ -55,7 +55,7 @@ defined('BASEPATH') OR exit('No direct script access allowed');
* @var string
*
*/
- define('CI_VERSION', '3.0-dev');
+ define('CI_VERSION', '3.0.1-dev');
/*
* ------------------------------------------------------
diff --git a/system/core/Common.php b/system/core/Common.php
index f28272b5b..a96828e96 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -181,7 +181,7 @@ if ( ! function_exists('load_class'))
// Did we find the class?
if ($name === FALSE)
{
- // Note: We use exit() rather then show_error() in order to avoid a
+ // Note: We use exit() rather than show_error() in order to avoid a
// self-referencing loop with the Exceptions class
set_status_header(503);
echo 'Unable to locate the specified class: '.$class.'.php';
diff --git a/system/core/Hooks.php b/system/core/Hooks.php
index 08479b133..3b4fb2250 100644
--- a/system/core/Hooks.php
+++ b/system/core/Hooks.php
@@ -46,7 +46,7 @@ defined('BASEPATH') OR exit('No direct script access allowed');
* @subpackage Libraries
* @category Libraries
* @author EllisLab Dev Team
- * @link http://codeigniter.com/user_guide/libraries/encryption.html
+ * @link http://codeigniter.com/user_guide/general/hooks.html
*/
class CI_Hooks {
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 254ad0d6d..9205ad1b6 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -1118,7 +1118,7 @@ class CI_Loader {
}
else
{
- log_message('debug', APPPATH.'libraries/'.$file_path.$subclass.'.php exists, but does not declare '.$subclass);
+ log_message('debug', $path.' exists, but does not declare '.$subclass);
}
}
}
@@ -1307,10 +1307,7 @@ class CI_Loader {
}
// Load all other libraries
- foreach ($autoload['libraries'] as $item)
- {
- $this->library($item);
- }
+ $this->library($autoload['libraries']);
}
// Autoload models
diff --git a/system/core/Router.php b/system/core/Router.php
index eb3da2285..f91d3f6ec 100644
--- a/system/core/Router.php
+++ b/system/core/Router.php
@@ -493,7 +493,7 @@ class CI_Router {
* Set directory name
*
* @param string $dir Directory name
- * @param bool $appent Whether we're appending rather then setting the full value
+ * @param bool $appent Whether we're appending rather than setting the full value
* @return void
*/
public function set_directory($dir, $append = FALSE)
diff --git a/system/core/URI.php b/system/core/URI.php
index e96749456..2211e3665 100644
--- a/system/core/URI.php
+++ b/system/core/URI.php
@@ -205,13 +205,16 @@ class CI_URI {
$query = isset($uri['query']) ? $uri['query'] : '';
$uri = isset($uri['path']) ? $uri['path'] : '';
- if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0)
+ if (isset($_SERVER['SCRIPT_NAME'][0]))
{
- $uri = (string) substr($uri, strlen($_SERVER['SCRIPT_NAME']));
- }
- elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0)
- {
- $uri = (string) substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
+ if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0)
+ {
+ $uri = (string) substr($uri, strlen($_SERVER['SCRIPT_NAME']));
+ }
+ elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0)
+ {
+ $uri = (string) substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
+ }
}
// This section ensures that even on servers that require the URI to be in the query string (Nginx) a correct
diff --git a/system/core/compat/hash.php b/system/core/compat/hash.php
index 477535dca..15954559c 100644
--- a/system/core/compat/hash.php
+++ b/system/core/compat/hash.php
@@ -174,9 +174,56 @@ if ( ! function_exists('hash_pbkdf2'))
}
$hash_length = strlen(hash($algo, NULL, TRUE));
- if (empty($length))
+ empty($length) && $length = $hash_length;
+
+ // Pre-hash password inputs longer than the algorithm's block size
+ // (i.e. prepare HMAC key) to mitigate potential DoS attacks.
+ static $block_sizes;
+ empty($block_sizes) && $block_sizes = array(
+ 'gost' => 32,
+ 'haval128,3' => 128,
+ 'haval160,3' => 128,
+ 'haval192,3' => 128,
+ 'haval224,3' => 128,
+ 'haval256,3' => 128,
+ 'haval128,4' => 128,
+ 'haval160,4' => 128,
+ 'haval192,4' => 128,
+ 'haval224,4' => 128,
+ 'haval256,4' => 128,
+ 'haval128,5' => 128,
+ 'haval160,5' => 128,
+ 'haval192,5' => 128,
+ 'haval224,5' => 128,
+ 'haval256,5' => 128,
+ 'md2' => 16,
+ 'md4' => 64,
+ 'md5' => 64,
+ 'ripemd128' => 64,
+ 'ripemd160' => 64,
+ 'ripemd256' => 64,
+ 'ripemd320' => 64,
+ 'salsa10' => 64,
+ 'salsa20' => 64,
+ 'sha1' => 64,
+ 'sha224' => 64,
+ 'sha256' => 64,
+ 'sha384' => 128,
+ 'sha512' => 128,
+ 'snefru' => 32,
+ 'snefru256' => 32,
+ 'tiger128,3' => 64,
+ 'tiger160,3' => 64,
+ 'tiger192,3' => 64,
+ 'tiger128,4' => 64,
+ 'tiger160,4' => 64,
+ 'tiger192,4' => 64,
+ 'whirlpool' => 64
+ );
+
+ if (isset($block_sizes[$algo]) && strlen($password) > $block_sizes[$algo])
{
- $length = $hash_length;
+ $password = hash($algo, $password, TRUE);
}
$hash = '';
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php
index e5ffef2bb..8251f4558 100644
--- a/system/database/DB_query_builder.php
+++ b/system/database/DB_query_builder.php
@@ -918,6 +918,8 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
}
is_bool($escape) OR $escape = $this->_protect_identifiers;
+ // lowercase $side in case somebody writes e.g. 'BEFORE' instead of 'before' (doh)
+ $side = strtolower($side);
foreach ($field as $k => $v)
{
@@ -2253,7 +2255,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
else
{
// Cycle through the "select" portion of the query and prep each column name.
- // The reason we protect identifiers here rather then in the select() function
+ // The reason we protect identifiers here rather than in the select() function
// is because until the user calls the from() function we don't know if there are aliases
foreach ($this->qb_select as $key => $val)
{
diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php
index e3e68139a..f3e039881 100644
--- a/system/libraries/Encryption.php
+++ b/system/libraries/Encryption.php
@@ -121,7 +121,7 @@ class CI_Encryption {
);
/**
- * List of supported HMAC algorightms
+ * List of supported HMAC algorithms
*
* name => digest size pairs
*
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index 05de59628..522eba704 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -198,22 +198,20 @@ class CI_Form_validation {
return $this;
}
- // No fields? Nothing to do...
- if ( ! is_string($field) OR $field === '')
+ // No fields or no rules? Nothing to do...
+ if ( ! is_string($field) OR $field === '' OR empty($rules))
{
return $this;
}
elseif ( ! is_array($rules))
{
// BC: Convert pipe-separated rules string to an array
- if (is_string($rules))
- {
- $rules = explode('|', $rules);
- }
- else
+ if ( ! is_string($rules))
{
return $this;
}
+
+ $rules = explode('|', $rules);
}
// If the field label wasn't passed we use the field name
diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php
index bb457c659..0549fef66 100644
--- a/system/libraries/Session/Session.php
+++ b/system/libraries/Session/Session.php
@@ -869,7 +869,7 @@ class CI_Session {
public function set_tempdata($data, $value = NULL, $ttl = 300)
{
$this->set_userdata($data, $value);
- $this->mark_as_temp($data, $ttl);
+ $this->mark_as_temp(is_array($data) ? array_keys($data) : $data, $ttl);
}
// ------------------------------------------------------------------------
diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php
index f2f17148b..3e98ac568 100644
--- a/system/libraries/Zip.php
+++ b/system/libraries/Zip.php
@@ -352,7 +352,7 @@ class CI_Zip {
// Set the original directory root for child dir's to use as relative
if ($root_path === NULL)
{
- $root_path = dirname($path).DIRECTORY_SEPARATOR;
+ $root_path = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, dirname($path)).DIRECTORY_SEPARATOR;
}
while (FALSE !== ($file = readdir($fp)))
diff --git a/tests/codeigniter/core/Lang_test.php b/tests/codeigniter/core/Lang_test.php
index 929bc2ffd..d2dd7598a 100644
--- a/tests/codeigniter/core/Lang_test.php
+++ b/tests/codeigniter/core/Lang_test.php
@@ -49,6 +49,32 @@ class Lang_test extends CI_TestCase {
// --------------------------------------------------------------------
+ public function test_multiple_file_load()
+ {
+ // Multiple files
+ $this->ci_vfs_clone('system/language/english/profiler_lang.php');
+ $files = array(
+ 0 => 'profiler',
+ 1 => 'nonexistent'
+ );
+ $this->setExpectedException(
+ 'RuntimeException',
+ 'CI Error: Unable to load the requested language file: language/english/nonexistent_lang.php'
+ );
+ $this->lang->load($files, 'english');
+ }
+
+ // --------------------------------------------------------------------
+
+ public function test_alternative_path_load()
+ {
+ // Alternative Path
+ $this->ci_vfs_clone('system/language/english/profiler_lang.php');
+ $this->assertTrue($this->lang->load('profiler', 'english', FALSE, TRUE, 'vfs://system/'));
+ }
+
+ // --------------------------------------------------------------------
+
/**
* @depends test_load
*/
diff --git a/tests/codeigniter/core/Loader_test.php b/tests/codeigniter/core/Loader_test.php
index 9e2092e05..cfaf6c74b 100644
--- a/tests/codeigniter/core/Loader_test.php
+++ b/tests/codeigniter/core/Loader_test.php
@@ -22,6 +22,9 @@ class Loader_test extends CI_TestCase {
public function test_library()
{
+ // Test getting CI_Loader object
+ $this->assertInstanceOf('CI_Loader', $this->load->library(NULL));
+
// Create library in VFS
$lib = 'unit_test_lib';
$class = 'CI_'.ucfirst($lib);
@@ -35,6 +38,13 @@ class Loader_test extends CI_TestCase {
$this->assertTrue(class_exists($class), $class.' does not exist');
$this->assertAttributeInstanceOf($class, $lib, $this->ci_obj);
+ // Create library in VFS
+ $lib = array('unit_test_lib' => 'unit_test_lib');
+
+ // Test loading as an array (int).
+ $this->assertInstanceOf('CI_Loader', $this->load->library($lib));
+ $this->assertTrue(class_exists($class), $class.' does not exist');
+
// Test a string given to params
$this->assertInstanceOf('CI_Loader', $this->load->library($lib, ' '));
@@ -319,6 +329,24 @@ class Loader_test extends CI_TestCase {
// --------------------------------------------------------------------
+ public function test_clear_vars()
+ {
+ $key1 = 'foo';
+ $val1 = 'bar';
+ $key2 = 'boo';
+ $val2 = 'hoo';
+ $this->assertInstanceOf('CI_Loader', $this->load->vars(array($key1 => $val1)));
+ $this->assertInstanceOf('CI_Loader', $this->load->vars($key2, $val2));
+ $this->assertEquals($val1, $this->load->get_var($key1));
+ $this->assertEquals(array($key1 => $val1, $key2 => $val2), $this->load->get_vars());
+
+ $this->assertInstanceOf('CI_Loader', $this->load->clear_vars());
+ $this->assertEquals('', $this->load->get_var($key1));
+ $this->assertEquals('', $this->load->get_var($key2));
+ }
+
+ // --------------------------------------------------------------------
+
public function test_helper()
{
// Create helper in VFS
@@ -443,6 +471,24 @@ class Loader_test extends CI_TestCase {
// --------------------------------------------------------------------
+ public function test_remove_package_path()
+ {
+ $dir = 'third-party';
+ $path = APPPATH.$dir.'/';
+ $path2 = APPPATH.'another/';
+ $paths = $this->load->get_package_paths(TRUE);
+
+ $this->assertInstanceOf('CI_Loader', $this->load->add_package_path($path));
+ $this->assertInstanceOf('CI_Loader', $this->load->remove_package_path($path));
+ $this->assertEquals($paths, $this->load->get_package_paths(TRUE));
+
+ $this->assertInstanceOf('CI_Loader', $this->load->add_package_path($path2));
+ $this->assertInstanceOf('CI_Loader', $this->load->remove_package_path());
+ $this->assertNotContains($path2, $this->load->get_package_paths(TRUE));
+ }
+
+ // --------------------------------------------------------------------
+
public function test_load_config()
{
$cfg = 'someconfig';
@@ -511,5 +557,4 @@ class Loader_test extends CI_TestCase {
// Verify config calls
$this->assertEquals($cfg['config'], $this->ci_obj->config->loaded);
}
-
-} \ No newline at end of file
+}
diff --git a/tests/codeigniter/libraries/Form_validation_test.php b/tests/codeigniter/libraries/Form_validation_test.php
index 1bbd1758b..26d82ec93 100644
--- a/tests/codeigniter/libraries/Form_validation_test.php
+++ b/tests/codeigniter/libraries/Form_validation_test.php
@@ -248,7 +248,7 @@ class Form_validation_test extends CI_TestCase {
$this->assertTrue($this->form_validation->valid_emails('1@sample.com,2@sample.com'));
$this->assertTrue($this->form_validation->valid_emails('email@sample.com'));
- $this->assertFalse($this->form_validation->valid_emails('valid_email', '@sample.com'));
+ $this->assertFalse($this->form_validation->valid_emails('valid_email', '@sample.com'));
$this->assertFalse($this->form_validation->valid_emails('@sample.com,2@sample.com,validemail@email.ca'));
}
@@ -323,6 +323,254 @@ class Form_validation_test extends CI_TestCase {
$this->assertEquals('', $this->form_validation->error('req_field'));
}
+ public function test_set_error_delimiters()
+ {
+ $this->form_validation->reset_validation();
+ $prefix = '<div class="error">';
+ $suffix = '</div>';
+ $this->form_validation->set_error_delimiters($prefix, $suffix);
+ $this->form_validation->set_rules('foo', 'label', 'required');
+ $_POST = array('foo' => '');
+ $this->form_validation->run();
+ $error_msg = $this->form_validation->error('foo');
+
+ $this->assertTrue(strrpos($error_msg, $prefix) === 0);
+ $this->assertTrue(strrpos($error_msg, $suffix, -strlen($suffix)) === (strlen($error_msg) - strlen($suffix)));
+ }
+
+ public function test_error_array()
+ {
+ $this->form_validation->reset_validation();
+ $error_message = 'What a terrible error!';
+ $this->form_validation->set_message('required', $error_message);
+ $this->form_validation->set_rules('foo', 'label', 'required');
+ $_POST = array('foo' => '');
+ $this->form_validation->run();
+ $error_array = $this->form_validation->error_array();
+ $this->assertEquals($error_message, $error_array['foo']);
+ }
+
+ public function test_error_string()
+ {
+ $this->form_validation->reset_validation();
+ $error_message = 'What a terrible error!';
+ $prefix_default = '<foo>';
+ $suffix_default = '</foo>';
+ $prefix_test = '<bar>';
+ $suffix_test = '</bar>';
+ $this->form_validation->set_error_delimiters($prefix_default, $suffix_default);
+ $this->form_validation->set_message('required', $error_message);
+ $this->form_validation->set_rules('foo', 'label', 'required');
+ $_POST = array('foo' => '');
+ $this->form_validation->run();
+
+ $this->assertEquals($prefix_default.$error_message.$suffix_default."\n", $this->form_validation->error_string());
+ $this->assertEquals($prefix_test.$error_message.$suffix_default."\n", $this->form_validation->error_string($prefix_test, ''));
+ $this->assertEquals($prefix_default.$error_message.$suffix_test."\n", $this->form_validation->error_string('', $suffix_test));
+ $this->assertEquals($prefix_test.$error_message.$suffix_test."\n", $this->form_validation->error_string($prefix_test, $suffix_test));
+
+ $this->form_validation->reset_validation();
+ $this->form_validation->set_rules('foo', 'label', 'required');
+ $_POST = array('foo' => 'bar');
+ $this->form_validation->run();
+ $this->assertEquals('', $this->form_validation->error_string());
+ }
+
+ public function test_run()
+ {
+ // form_validation->run() is tested in many of the other unit tests
+ // This test will only test run(group='') when group is not empty
+ $config = array(
+ 'pass' => array(
+ array(
+ 'field' => 'username',
+ 'label' => 'user',
+ 'rules' => 'alpha_numeric'
+ )
+ ),
+ 'fail' => array(
+ array(
+ 'field' => 'username',
+ 'label' => 'user',
+ 'rules' => 'alpha'
+ )
+ )
+ );
+ $_POST = array('username' => 'foo42');
+ $form_validation = new CI_Form_validation($config);
+ $this->assertTrue($form_validation->run('pass'));
+
+ $form_validation = new CI_Form_validation($config);
+ $this->assertFalse($form_validation->run('fail'));
+ }
+
+ public function test_has_rule()
+ {
+ $this->form_validation->reset_validation();
+ $this->form_validation->set_rules('foo', 'label', 'required');
+
+ $this->assertTrue($this->form_validation->has_rule('foo'));
+ $this->assertFalse($this->form_validation->has_rule('bar'));
+ }
+
+ public function test_set_value()
+ {
+ $this->form_validation->reset_validation();
+ $default = 'default';
+ $this->form_validation->set_rules('foo', 'label', 'required');
+ $this->form_validation->set_rules('bar[]', 'label', 'required');
+
+ // No post data yet: should return the default value provided
+ $this->assertEquals($default, $this->form_validation->set_value('foo', $default));
+ $_POST = array('foo' => 'foo', 'bar' => array('bar1', 'bar2'));
+ $this->form_validation->run();
+ $this->assertEquals('foo', $this->form_validation->set_value('foo', $default));
+ $this->assertEquals('bar1', $this->form_validation->set_value('bar[]', $default));
+ $this->assertEquals('bar2', $this->form_validation->set_value('bar[]', $default));
+ }
+
+ public function test_set_select()
+ {
+ // Test 1: No options selected
+ $this->form_validation->reset_validation();
+ $_POST = array();
+ $this->form_validation->run();
+
+ $this->assertEquals('', $this->form_validation->set_select('select', 'foo'));
+ $this->assertEquals(' selected="selected"', $this->form_validation->set_select('select', 'bar', TRUE));
+
+ // Test 2: 1 option selected
+ $this->form_validation->reset_validation();
+ $this->form_validation->set_rules('select', 'label', 'alpha_numeric');
+ $_POST = array('select' => 'foo');
+ $this->form_validation->run();
+
+ $this->assertEquals(' selected="selected"', $this->form_validation->set_select('select', 'foo'));
+ $this->assertEquals(' selected="selected"', $this->form_validation->set_select('select', 'foo', TRUE));
+ $this->assertEquals('', $this->form_validation->set_select('select', 'bar'));
+ $this->assertEquals('', $this->form_validation->set_select('select', 'bar', TRUE));
+
+ // Test 3: Multiple options selected
+ $this->form_validation->reset_validation();
+ $this->form_validation->set_rules('select[]', 'label', 'alpha_numeric');
+ $_POST = array('select' => array('foo', 'bar'));
+ $this->form_validation->run();
+
+ $this->assertEquals(' selected="selected"', $this->form_validation->set_select('select[]', 'foo'));
+ $this->assertEquals(' selected="selected"', $this->form_validation->set_select('select[]', 'foo', TRUE));
+ $this->assertEquals(' selected="selected"', $this->form_validation->set_select('select[]', 'bar'));
+ $this->assertEquals(' selected="selected"', $this->form_validation->set_select('select[]', 'bar', TRUE));
+ $this->assertEquals('', $this->form_validation->set_select('select[]', 'foobar'));
+ $this->assertEquals('', $this->form_validation->set_select('select[]', 'foobar', TRUE));
+ }
+
+ public function test_set_radio()
+ {
+ // Test 1: No options selected
+ $this->form_validation->reset_validation();
+ $_POST = array();
+ $this->form_validation->run();
+
+ $this->assertEquals('', $this->form_validation->set_radio('select', 'foo'));
+ // Default should only work when no rules are set
+ $this->assertEquals(' checked="checked"', $this->form_validation->set_radio('select', 'bar', TRUE));
+
+ // Test 2: 1 option selected
+ $this->form_validation->reset_validation();
+ $this->form_validation->set_rules('select', 'label', 'alpha_numeric');
+ $_POST = array('select' => 'foo');
+ $this->form_validation->run();
+
+ $this->assertEquals(' checked="checked"', $this->form_validation->set_radio('select', 'foo'));
+ $this->assertEquals(' checked="checked"', $this->form_validation->set_radio('select', 'foo', TRUE));
+ $this->assertEquals('', $this->form_validation->set_radio('select', 'bar'));
+ $this->assertEquals('', $this->form_validation->set_radio('select', 'bar', TRUE));
+
+ // Test 3: Multiple options checked
+ $this->form_validation->reset_validation();
+ $this->form_validation->set_rules('select[]', 'label', 'alpha_numeric');
+ $_POST = array('select' => array('foo', 'bar'));
+ $this->form_validation->run();
+
+ $this->assertEquals(' checked="checked"', $this->form_validation->set_radio('select[]', 'foo'));
+ $this->assertEquals(' checked="checked"', $this->form_validation->set_radio('select[]', 'foo', TRUE));
+ $this->assertEquals(' checked="checked"', $this->form_validation->set_radio('select[]', 'bar'));
+ $this->assertEquals(' checked="checked"', $this->form_validation->set_radio('select[]', 'bar', TRUE));
+ $this->assertEquals('', $this->form_validation->set_radio('select[]', 'foobar'));
+ $this->assertEquals('', $this->form_validation->set_radio('select[]', 'foobar', TRUE));
+ }
+
+ public function test_set_checkbox()
+ {
+ // Test 1: No options selected
+ $this->form_validation->reset_validation();
+ $_POST = array();
+ $this->form_validation->run();
+
+ $this->assertEquals('', $this->form_validation->set_checkbox('select', 'foo'));
+ $this->assertEquals(' checked="checked"', $this->form_validation->set_checkbox('select', 'bar', TRUE));
+
+ // Test 2: 1 option selected
+ $this->form_validation->reset_validation();
+ $this->form_validation->set_rules('select', 'label', 'alpha_numeric');
+ $_POST = array('select' => 'foo');
+ $this->form_validation->run();
+
+ $this->assertEquals(' checked="checked"', $this->form_validation->set_checkbox('select', 'foo'));
+ $this->assertEquals(' checked="checked"', $this->form_validation->set_checkbox('select', 'foo', TRUE));
+ $this->assertEquals('', $this->form_validation->set_checkbox('select', 'bar'));
+ $this->assertEquals('', $this->form_validation->set_checkbox('select', 'bar', TRUE));
+
+ // Test 3: Multiple options selected
+ $this->form_validation->reset_validation();
+ $this->form_validation->set_rules('select[]', 'label', 'alpha_numeric');
+ $_POST = array('select' => array('foo', 'bar'));
+ $this->form_validation->run();
+
+ $this->assertEquals(' checked="checked"', $this->form_validation->set_checkbox('select[]', 'foo'));
+ $this->assertEquals(' checked="checked"', $this->form_validation->set_checkbox('select[]', 'foo', TRUE));
+ $this->assertEquals(' checked="checked"', $this->form_validation->set_checkbox('select[]', 'bar'));
+ $this->assertEquals(' checked="checked"', $this->form_validation->set_checkbox('select[]', 'bar', TRUE));
+ $this->assertEquals('', $this->form_validation->set_checkbox('select[]', 'foobar'));
+ $this->assertEquals('', $this->form_validation->set_checkbox('select[]', 'foobar', TRUE));
+ }
+
+ public function test_regex_match()
+ {
+ $regex = '/f[a-zA-Z]+/';
+ $this->assertTrue($this->form_validation->regex_match('foo', $regex));
+ $this->assertFalse($this->form_validation->regex_match('bar', $regex));
+ }
+
+ public function test_prep_for_form()
+ {
+ $this->form_validation->reset_validation();
+ $error_msg_unprepped = '<error =\'foobar\'">';
+ $error_msg_prepped = '&lt;error =&#39;foobar&#39;&quot;&gt;';
+ $this->form_validation->set_rules('foo', 'label', 'required', array('required' => $error_msg_unprepped));
+ $_POST = array('foo' => '');
+ $this->form_validation->run();
+ $error_arr = $this->form_validation->error_array();
+
+ $this->assertEquals('', $this->form_validation->prep_for_form(''));
+ $this->assertEquals(array('foo' => $error_msg_prepped), $this->form_validation->prep_for_form($error_arr));
+ }
+
+ public function test_prep_url()
+ {
+ $this->assertEquals('', $this->form_validation->prep_url(''));
+ $this->assertEquals('http://codeigniter.com', $this->form_validation->prep_url('codeigniter.com'));
+ $this->assertEquals('https://codeigniter.com', $this->form_validation->prep_url('https://codeigniter.com'));
+ $this->assertEquals('http://codeigniter.com', $this->form_validation->prep_url('http://codeigniter.com'));
+ $this->assertEquals('http://www.codeigniter.com', $this->form_validation->prep_url('www.codeigniter.com'));
+ }
+
+ public function test_encode_php_tags()
+ {
+ $this->assertEquals("&lt;?php", $this->form_validation->encode_php_tags('<?php'));
+ $this->assertEquals('?&gt;', $this->form_validation->encode_php_tags('?>'));
+ }
+
/**
* Run rules
*
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index a1b15105f..8fa4d1ef1 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -2,11 +2,25 @@
Change Log
##########
-Version 3.0 (planned)
-=======================
+Version 3.0.1
+=============
Release Date: Not Released
+- Core
+
+ - Added DoS mitigation to :php:func:`hash_pbkdf2()` :doc:`compatibility function <general/compatibility_functions>`.
+
+Bug fixes for 3.0.1
+-------------------
+
+- Fixed a bug (#3733) - Autoloading of libraries with aliases didn't work, although it was advertised to.
+
+Version 3.0.0
+=============
+
+Release Date: March 30, 2015
+
- License
- CodeIgniter has been relicensed with the `MIT License <http://opensource.org/licenses/MIT>`_, eliminating its old proprietary licensing.
@@ -565,7 +579,7 @@ Release Date: Not Released
- Changed the library constructor to try to create the **log_path** directory if it doesn't exist.
- Added support for microseconds ("u" date format character) in ``$config['log_date_format']``.
- - Added `compatibility layers <general/compatibility_functions>` for:
+ - Added :doc:`compatibility layers <general/compatibility_functions>` for:
- `Multibyte String <http://php.net/mbstring>`_ (limited support).
- `Hash <http://php.net/hash>`_ (``hash_equals()``, ``hash_pbkdf2()``).
@@ -579,7 +593,7 @@ Release Date: Not Released
Bug fixes for 3.0
-------------------
+-----------------
- Fixed a bug where ``unlink()`` raised an error if cache file did not exist when you try to delete it.
- Fixed a bug (#181) - a typo in the form validation language file.
diff --git a/user_guide_src/source/conf.py b/user_guide_src/source/conf.py
index d65fe0dfd..1704654b6 100644
--- a/user_guide_src/source/conf.py
+++ b/user_guide_src/source/conf.py
@@ -48,9 +48,9 @@ copyright = u'2014 - 2015, British Columbia Institute of Technology'
# built documents.
#
# The short X.Y version.
-version = '3.0'
+version = '3.0.1'
# The full version, including alpha/beta/rc tags.
-release = '3.0-dev'
+release = '3.0.0-dev'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/user_guide_src/source/database/forge.rst b/user_guide_src/source/database/forge.rst
index 89fac023e..a4edada5c 100644
--- a/user_guide_src/source/database/forge.rst
+++ b/user_guide_src/source/database/forge.rst
@@ -227,7 +227,7 @@ Execute a DROP TABLE statement and optionally add an IF EXISTS clause.
$this->dbforge->drop_table('table_name');
// Produces: DROP TABLE IF EXISTS table_name
- $this->dbforge->drop_table('table_name');
+ $this->dbforge->drop_table('table_name',TRUE);
Renaming a table
@@ -405,4 +405,4 @@ Class Reference
:returns: TRUE on success, FALSE on failure
:rtype: bool
- Renames a table. Usage: See `Renaming a table`_. \ No newline at end of file
+ Renames a table. Usage: See `Renaming a table`_.
diff --git a/user_guide_src/source/general/security.rst b/user_guide_src/source/general/security.rst
index efc821f2b..fcfe4c24b 100644
--- a/user_guide_src/source/general/security.rst
+++ b/user_guide_src/source/general/security.rst
@@ -143,11 +143,15 @@ with that. Please read below.
feature, just randomly generate a new, one-time (this is also important)
password and send that instead.
-- DO NOT put artificial limits on your users' passwords.
+- DO NOT put unnecessary limits on your users' passwords.
- There's no point in forcing a rule that a password can only be up to
- a number of characters, or that it can't contain a certain set of
- special characters.
+ If you're using a hashing algorithm other than BCrypt (which has a limit
+ of 72 characters), you should set a relatively high limit on password
+ lengths in order to mitigate DoS attacks - say, 1024 characters.
+
+ Other than that however, there's no point in forcing a rule that a
+ password can only be up to a number of characters, or that it can't
+ contain a certain set of special characters.
Not only does this **reduce** security instead of improving it, but
there's literally no reason to do it. No technical limitations and
diff --git a/user_guide_src/source/installation/upgrade_300.rst b/user_guide_src/source/installation/upgrade_300.rst
index 7e3479740..a3d712482 100644
--- a/user_guide_src/source/installation/upgrade_300.rst
+++ b/user_guide_src/source/installation/upgrade_300.rst
@@ -2,8 +2,6 @@
Upgrading from 2.2.x to 3.0.0
#############################
-.. note:: These upgrade notes are for a version that is yet to be released.
-
Before performing an update you should take your site offline by replacing the index.php file with a static one.
*************************************
diff --git a/user_guide_src/source/tutorial/static_pages.rst b/user_guide_src/source/tutorial/static_pages.rst
index 210d9f8d6..62b3469ad 100644
--- a/user_guide_src/source/tutorial/static_pages.rst
+++ b/user_guide_src/source/tutorial/static_pages.rst
@@ -12,14 +12,14 @@ It is the glue of your web application.
For example, when a call is made to:
- http&#58;//example.com/news/latest/10
+ http://example.com/news/latest/10
We might imagine that there is a controller named "news". The method
being called on news would be "latest". The news method's job could be to
grab 10 news items, and render them on the page. Very often in MVC,
you'll see URL patterns that match:
- http&#58;//example.com/[controller-class]/[controller-method]/[arguments]
+ http://example.com/[controller-class]/[controller-method]/[arguments]
As URL schemes become more complex, this may change. But for now, this
is all we will need to know.
@@ -64,7 +64,7 @@ following code.
</head>
<body>
- <h1>CodeIgniter Tutorial</h1>
+ <h1><?php echo $title ?></h1>
The header contains the basic HTML code that you'll want to display
before loading the main view, together with a heading. It will also