summaryrefslogtreecommitdiffstats
path: root/system
diff options
context:
space:
mode:
authorJonatas Miguel <jonatas.df.miguel@gmail.com>2012-10-24 19:30:36 +0200
committerJonatas Miguel <jonatas.df.miguel@gmail.com>2012-10-24 19:30:36 +0200
commitb51823dde5fbae508b8ebf99258d2f514a8bece8 (patch)
tree4db09a22f85e0ddf151c940cd3e6fbaa799b8513 /system
parenta53f402b78ad07fb0f6da19cff0c7bec3a09a4c0 (diff)
parenta7001e968a4791312391eb245ad84888893cda8f (diff)
Merge branch 'develop' of git://github.com/EllisLab/CodeIgniter into develop
Conflicts: user_guide_src/source/changelog.rst
Diffstat (limited to 'system')
-rw-r--r--system/core/CodeIgniter.php2
-rw-r--r--system/core/Common.php80
-rw-r--r--system/core/Config.php4
-rw-r--r--system/core/Controller.php2
-rw-r--r--system/core/Input.php140
-rw-r--r--system/core/Loader.php53
-rw-r--r--system/core/Output.php9
-rw-r--r--system/core/Security.php2
-rw-r--r--system/core/URI.php7
-rw-r--r--system/core/Utf8.php39
-rw-r--r--system/database/DB_cache.php31
-rw-r--r--system/database/DB_driver.php79
-rw-r--r--system/database/DB_forge.php15
-rw-r--r--system/database/DB_query_builder.php592
-rw-r--r--system/database/DB_result.php43
-rw-r--r--system/database/DB_utility.php6
-rw-r--r--system/database/drivers/cubrid/cubrid_driver.php43
-rw-r--r--system/database/drivers/cubrid/cubrid_result.php1
-rw-r--r--system/database/drivers/ibase/ibase_driver.php72
-rw-r--r--system/database/drivers/mssql/mssql_driver.php111
-rw-r--r--system/database/drivers/mssql/mssql_result.php1
-rw-r--r--system/database/drivers/mysql/mysql_driver.php52
-rw-r--r--system/database/drivers/mysql/mysql_result.php1
-rw-r--r--system/database/drivers/mysqli/mysqli_driver.php70
-rw-r--r--system/database/drivers/mysqli/mysqli_result.php1
-rw-r--r--system/database/drivers/oci8/oci8_driver.php51
-rw-r--r--system/database/drivers/odbc/odbc_driver.php43
-rw-r--r--system/database/drivers/pdo/pdo_driver.php20
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_4d_driver.php59
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php34
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php98
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php62
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php53
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_informix_driver.php59
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php41
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_oci_driver.php41
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php60
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php99
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php104
-rw-r--r--system/database/drivers/postgre/postgre_driver.php116
-rw-r--r--system/database/drivers/postgre/postgre_forge.php14
-rw-r--r--system/database/drivers/postgre/postgre_result.php1
-rw-r--r--system/database/drivers/sqlite/sqlite_driver.php5
-rw-r--r--system/database/drivers/sqlite/sqlite_result.php1
-rw-r--r--system/database/drivers/sqlite3/sqlite3_driver.php31
-rw-r--r--system/database/drivers/sqlite3/sqlite3_result.php1
-rw-r--r--system/database/drivers/sqlsrv/sqlsrv_driver.php117
-rw-r--r--system/helpers/captcha_helper.php3
-rw-r--r--system/helpers/date_helper.php148
-rw-r--r--system/helpers/directory_helper.php2
-rw-r--r--system/helpers/download_helper.php5
-rw-r--r--system/helpers/file_helper.php4
-rw-r--r--system/helpers/html_helper.php30
-rw-r--r--system/helpers/text_helper.php25
-rw-r--r--system/helpers/typography_helper.php9
-rw-r--r--system/helpers/url_helper.php73
-rw-r--r--system/language/english/date_lang.php28
-rw-r--r--system/language/english/form_validation_lang.php5
-rw-r--r--system/libraries/Driver.php23
-rw-r--r--system/libraries/Email.php266
-rw-r--r--system/libraries/Encrypt.php6
-rw-r--r--system/libraries/Form_validation.php20
-rw-r--r--system/libraries/Ftp.php7
-rw-r--r--system/libraries/Image_lib.php7
-rw-r--r--system/libraries/Javascript.php32
-rw-r--r--system/libraries/Pagination.php23
-rw-r--r--system/libraries/Session.php955
-rwxr-xr-xsystem/libraries/Session/Session.php714
-rwxr-xr-xsystem/libraries/Session/drivers/Session_cookie.php821
-rwxr-xr-xsystem/libraries/Session/drivers/Session_native.php241
-rw-r--r--system/libraries/Trackback.php5
-rw-r--r--system/libraries/Unit_test.php39
-rw-r--r--system/libraries/Upload.php4
-rwxr-xr-x[-rw-r--r--]system/libraries/Xmlrpc.php24
-rw-r--r--system/libraries/javascript/Jquery.php83
75 files changed, 3562 insertions, 2606 deletions
diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php
index 8159b19f5..f3592eaf9 100644
--- a/system/core/CodeIgniter.php
+++ b/system/core/CodeIgniter.php
@@ -50,7 +50,7 @@
* Load the global functions
* ------------------------------------------------------
*/
- require(BASEPATH.'core/Common.php');
+ require_once(BASEPATH.'core/Common.php');
/*
* ------------------------------------------------------
diff --git a/system/core/Common.php b/system/core/Common.php
index 06b162264..2dd31d3e9 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -150,7 +150,7 @@ if ( ! function_exists('load_class'))
if (class_exists($name) === FALSE)
{
- require($path.$directory.'/'.$class.'.php');
+ require_once($path.$directory.'/'.$class.'.php');
}
break;
@@ -164,7 +164,7 @@ if ( ! function_exists('load_class'))
if (class_exists($name) === FALSE)
{
- require(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php');
+ require_once(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php');
}
}
@@ -330,6 +330,24 @@ if ( ! function_exists('get_mimes'))
// ------------------------------------------------------------------------
+if ( ! function_exists('is_https'))
+{
+ /**
+ * Is HTTPS?
+ *
+ * Determines if the application is accessed via an encrypted
+ * (HTTPS) connection.
+ *
+ * @return bool
+ */
+ function is_https()
+ {
+ return ( ! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off');
+ }
+}
+
+// ------------------------------------------------------------------------
+
if ( ! function_exists('show_error'))
{
/**
@@ -488,13 +506,9 @@ if ( ! function_exists('set_status_header'))
{
header('Status: '.$code.' '.$text, TRUE);
}
- elseif ($server_protocol === 'HTTP/1.0')
- {
- header('HTTP/1.0 '.$code.' '.$text, TRUE, $code);
- }
else
{
- header('HTTP/1.1 '.$code.' '.$text, TRUE, $code);
+ header(($server_protocol ? $server_protocol : 'HTTP/1.1').' '.$code.' '.$text, TRUE, $code);
}
}
}
@@ -524,18 +538,17 @@ if ( ! function_exists('_exception_handler'))
{
$_error =& load_class('Exceptions', 'core');
- // Should we display the error? We'll get the current error_reporting
+ // Should we ignore the error? We'll get the current error_reporting
// level and add its bits with the severity bits to find out.
- // And respect display_errors
- if (($severity & error_reporting()) === $severity && (bool) ini_get('display_errors') === TRUE)
+ if (($severity & error_reporting()) !== $severity)
{
- $_error->show_php_error($severity, $message, $filepath, $line);
+ return;
}
- // Should we log the error? No? We're done...
- if (config_item('log_threshold') === 0)
+ // Should we display the error?
+ if ((bool) ini_get('display_errors') === TRUE)
{
- return;
+ $_error->show_php_error($severity, $message, $filepath, $line);
}
$_error->log_exception($severity, $message, $filepath, $line);
@@ -598,5 +611,44 @@ if ( ! function_exists('html_escape'))
}
}
+// ------------------------------------------------------------------------
+
+if ( ! function_exists('_stringify_attributes'))
+{
+ /**
+ * Stringify attributes for use in HTML tags.
+ *
+ * Helper function used to convert a string, array, or object
+ * of attributes to a string.
+ *
+ * @param mixed string, array, object
+ * @param bool
+ * @return string
+ */
+ function _stringify_attributes($attributes, $js = FALSE)
+ {
+ $atts = NULL;
+
+ if (empty($attributes))
+ {
+ return $atts;
+ }
+
+ if (is_string($attributes))
+ {
+ return ' '.$attributes;
+ }
+
+ $attributes = (array) $attributes;
+
+ foreach ($attributes as $key => $val)
+ {
+ $atts .= ($js) ? $key.'='.$val.',' : ' '.$key.'="'.$val.'"';
+ }
+
+ return rtrim($atts, ',');
+ }
+}
+
/* End of file Common.php */
/* Location: ./system/core/Common.php */ \ No newline at end of file
diff --git a/system/core/Config.php b/system/core/Config.php
index 2f6a9e085..e78128c76 100644
--- a/system/core/Config.php
+++ b/system/core/Config.php
@@ -75,7 +75,7 @@ class CI_Config {
{
if (isset($_SERVER['HTTP_HOST']))
{
- $base_url = ( ! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off') ? 'https' : 'http';
+ $base_url = is_https() ? 'https' : 'http';
$base_url .= '://'.$_SERVER['HTTP_HOST']
.str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']);
}
@@ -102,7 +102,7 @@ class CI_Config {
{
$file = ($file === '') ? 'config' : str_replace('.php', '', $file);
$found = $loaded = FALSE;
-
+
$check_locations = defined('ENVIRONMENT')
? array(ENVIRONMENT.'/'.$file, $file)
: array($file);
diff --git a/system/core/Controller.php b/system/core/Controller.php
index 491414807..9196958ae 100644
--- a/system/core/Controller.php
+++ b/system/core/Controller.php
@@ -42,6 +42,7 @@ class CI_Controller {
/**
* Reference to the global CI instance
*
+ * @static
* @var object
*/
private static $instance;
@@ -71,6 +72,7 @@ class CI_Controller {
/**
* Return the CI object
*
+ * @static
* @return object
*/
public static function &get_instance()
diff --git a/system/core/Input.php b/system/core/Input.php
index 162e40c85..ec935d531 100644
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -328,39 +328,121 @@ class CI_Input {
return $this->ip_address;
}
- if (config_item('proxy_ips') != '' && $this->server('HTTP_X_FORWARDED_FOR') && $this->server('REMOTE_ADDR'))
+ $proxy_ips = config_item('proxy_ips');
+ if ( ! empty($proxy_ips) && ! is_array($proxy_ips))
{
- $proxies = preg_split('/[\s,]/', config_item('proxy_ips'), -1, PREG_SPLIT_NO_EMPTY);
- $proxies = is_array($proxies) ? $proxies : array($proxies);
-
- $this->ip_address = in_array($_SERVER['REMOTE_ADDR'], $proxies) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
- }
- elseif ( ! $this->server('HTTP_CLIENT_IP') && $this->server('REMOTE_ADDR'))
- {
- $this->ip_address = $_SERVER['REMOTE_ADDR'];
- }
- elseif ($this->server('REMOTE_ADDR') && $this->server('HTTP_CLIENT_IP'))
- {
- $this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
- }
- elseif ($this->server('HTTP_CLIENT_IP'))
- {
- $this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
- }
- elseif ($this->server('HTTP_X_FORWARDED_FOR'))
- {
- $this->ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
+ $proxy_ips = explode(',', str_replace(' ', '', $proxy_ips));
}
- if ($this->ip_address === FALSE)
- {
- return $this->ip_address = '0.0.0.0';
- }
+ $this->ip_address = $this->server('REMOTE_ADDR');
- if (strpos($this->ip_address, ',') !== FALSE)
+ if ($proxy_ips)
{
- $x = explode(',', $this->ip_address);
- $this->ip_address = trim(end($x));
+ foreach (array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_X_CLIENT_IP', 'HTTP_X_CLUSTER_CLIENT_IP') as $header)
+ {
+ if (($spoof = $this->server($header)) !== NULL)
+ {
+ // Some proxies typically list the whole chain of IP
+ // addresses through which the client has reached us.
+ // e.g. client_ip, proxy_ip1, proxy_ip2, etc.
+ if (strpos($spoof, ',') !== FALSE)
+ {
+ $spoof = explode(',', $spoof, 2);
+ $spoof = $spoof[0];
+ }
+
+ if ( ! $this->valid_ip($spoof))
+ {
+ $spoof = NULL;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ if ($spoof)
+ {
+ for ($i = 0, $c = count($proxy_ips); $i < $c; $i++)
+ {
+ // Check if we have an IP address or a subnet
+ if (strpos($proxy_ips[$i], '/') === FALSE)
+ {
+ // An IP address (and not a subnet) is specified.
+ // We can compare right away.
+ if ($proxy_ips[$i] === $this->ip_address)
+ {
+ $this->ip_address = $spoof;
+ break;
+ }
+
+ continue;
+ }
+
+ // We have a subnet ... now the heavy lifting begins
+ isset($separator) OR $separator = $this->valid_ip($this->ip_address, 'ipv6') ? ':' : '.';
+
+ // If the proxy entry doesn't match the IP protocol - skip it
+ if (strpos($proxy_ips[$i], $separator) === FALSE)
+ {
+ continue;
+ }
+
+ // Convert the REMOTE_ADDR IP address to binary, if needed
+ if ( ! isset($ip, $sprintf))
+ {
+ if ($separator === ':')
+ {
+ // Make sure we're have the "full" IPv6 format
+ $ip = explode(':',
+ str_replace('::',
+ str_repeat(':', 9 - substr_count($this->ip_address, ':')),
+ $this->ip_address
+ )
+ );
+
+ for ($i = 0; $i < 8; $i++)
+ {
+ $ip[$i] = intval($ip[$i], 16);
+ }
+
+ $sprintf = '%016b%016b%016b%016b%016b%016b%016b%016b';
+ }
+ else
+ {
+ $ip = explode('.', $this->ip_address);
+ $sprintf = '%08b%08b%08b%08b';
+ }
+
+ $ip = vsprintf($sprintf, $ip);
+ }
+
+ // Split the netmask length off the network address
+ list($netaddr, $masklen) = explode('/', $proxy_ips[$i], 2);
+
+ // Again, an IPv6 address is most likely in a compressed form
+ if ($separator === ':')
+ {
+ $netaddr = explode(':', str_replace('::', str_repeat(':', 9 - substr_count($netaddr, ':')), $netaddr));
+ for ($i = 0; $i < 8; $i++)
+ {
+ $netaddr[$i] = intval($netaddr[$i], 16);
+ }
+ }
+ else
+ {
+ $netaddr = explode('.', $netaddr);
+ }
+
+ // Convert to binary and finally compare
+ if (strncmp($ip, vsprintf($sprintf, $netaddr), $masklen) === 0)
+ {
+ $this->ip_address = $spoof;
+ break;
+ }
+ }
+ }
}
if ( ! $this->valid_ip($this->ip_address))
@@ -518,7 +600,7 @@ class CI_Input {
$_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']);
// CSRF Protection check
- if ($this->_enable_csrf === TRUE)
+ if ($this->_enable_csrf === TRUE && ! $this->is_cli_request())
{
$this->security->csrf_verify();
}
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 0bc6e844a..5de2e5dde 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -409,8 +409,8 @@ class CI_Loader {
* 1. The name of the "view" file to be included.
* 2. An associative array of data to be extracted for use in the view.
* 3. TRUE/FALSE - whether to return the data or load it. In
- * some cases it's advantageous to be able to return data so that
- * a developer can process it in some way.
+ * some cases it's advantageous to be able to return data so that
+ * a developer can process it in some way.
*
* @param string
* @param array
@@ -633,13 +633,7 @@ class CI_Loader {
{
$this->driver($driver);
}
- return FALSE;
- }
-
- if ( ! class_exists('CI_Driver_Library'))
- {
- // we aren't instantiating an object here, that'll be done by the Library itself
- require BASEPATH.'libraries/Driver.php';
+ return;
}
if ($library === '')
@@ -695,7 +689,7 @@ class CI_Loader {
*/
public function get_package_paths($include_base = FALSE)
{
- return $include_base === TRUE ? $this->_ci_library_paths : $this->_ci_model_paths;
+ return ($include_base === TRUE) ? $this->_ci_library_paths : $this->_ci_model_paths;
}
// --------------------------------------------------------------------
@@ -785,11 +779,11 @@ class CI_Loader {
$_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION);
$_ci_file = ($_ci_ext === '') ? $_ci_view.'.php' : $_ci_view;
- foreach ($this->_ci_view_paths as $view_file => $cascade)
+ foreach ($this->_ci_view_paths as $_ci_view_file => $cascade)
{
- if (file_exists($view_file.$_ci_file))
+ if (file_exists($_ci_view_file.$_ci_file))
{
- $_ci_path = $view_file.$_ci_file;
+ $_ci_path = $_ci_view_file.$_ci_file;
$file_exists = TRUE;
break;
}
@@ -837,10 +831,10 @@ class CI_Loader {
* We buffer the output for two reasons:
* 1. Speed. You get a significant speed boost.
* 2. So that the final rendered template can be post-processed by
- * the output class. Why do we need post processing? For one thing,
- * in order to show the elapsed page load time. Unless we can
- * intercept the content right before it's sent to the browser and
- * then stop the timer it won't be accurate.
+ * the output class. Why do we need post processing? For one thing,
+ * in order to show the elapsed page load time. Unless we can
+ * intercept the content right before it's sent to the browser and
+ * then stop the timer it won't be accurate.
*/
ob_start();
@@ -915,6 +909,13 @@ class CI_Loader {
// Get the filename from the path
$class = substr($class, $last_slash);
+
+ // Check for match and driver base class
+ if (strtolower(trim($subdir, '/')) == strtolower($class) && ! class_exists('CI_Driver_Library'))
+ {
+ // We aren't instantiating an object here, just making the base class available
+ require BASEPATH.'libraries/Driver.php';
+ }
}
// We'll test for both lowercase and capitalized versions of the file name
@@ -996,14 +997,19 @@ class CI_Loader {
$this->_ci_loaded_files[] = $filepath;
return $this->_ci_init_class($class, '', $params, $object_name);
}
-
} // END FOREACH
// One last attempt. Maybe the library is in a subdirectory, but it wasn't specified?
if ($subdir === '')
{
$path = strtolower($class).'/'.$class;
- return $this->_ci_load_class($path, $params);
+ return $this->_ci_load_class($path, $params, $object_name);
+ }
+ elseif (ucfirst($subdir) != $subdir)
+ {
+ // Lowercase subdir failed - retry capitalized
+ $path = ucfirst($subdir).$class;
+ return $this->_ci_load_class($path, $params, $object_name);
}
// If we got this far we were unable to find the requested class.
@@ -1193,6 +1199,15 @@ class CI_Loader {
}
}
+ // Autoload drivers
+ if (isset($autoload['drivers']))
+ {
+ foreach ($autoload['drivers'] as $item)
+ {
+ $this->driver($item);
+ }
+ }
+
// Autoload models
if (isset($autoload['model']))
{
diff --git a/system/core/Output.php b/system/core/Output.php
index 5ec8c4bc0..aa0e05dc4 100644
--- a/system/core/Output.php
+++ b/system/core/Output.php
@@ -204,7 +204,8 @@ class CI_Output {
/**
* Set Content Type Header
*
- * @param string extension of the file we're outputting
+ * @param string $mime_type extension of the file we're outputting
+ * @param string $charset = NULL
* @return void
*/
public function set_content_type($mime_type, $charset = NULL)
@@ -552,13 +553,13 @@ class CI_Output {
fclose($fp);
// Strip out the embedded timestamp
- if ( ! preg_match('/(\d+TS--->)/', $cache, $match))
+ if ( ! preg_match('/^(\d+)TS--->/', $cache, $match))
{
return FALSE;
}
$last_modified = filemtime($cache_path);
- $expire = trim(str_replace('TS--->', '', $match[1]));
+ $expire = $match[1];
// Has the file expired?
if ($_SERVER['REQUEST_TIME'] >= $expire && is_really_writable($cache_path))
@@ -575,7 +576,7 @@ class CI_Output {
}
// Display the cache
- $this->_display(str_replace($match[0], '', $cache));
+ $this->_display(substr($cache, strlen($match[0])));
log_message('debug', 'Cache file is current. Sending it to browser.');
return TRUE;
}
diff --git a/system/core/Security.php b/system/core/Security.php
index b22d2cf19..2fbc5b34c 100644
--- a/system/core/Security.php
+++ b/system/core/Security.php
@@ -198,7 +198,7 @@ class CI_Security {
$expire = time() + $this->_csrf_expire;
$secure_cookie = (bool) config_item('cookie_secure');
- if ($secure_cookie && (empty($_SERVER['HTTPS']) OR strtolower($_SERVER['HTTPS']) === 'off'))
+ if ($secure_cookie && ! is_https())
{
return FALSE;
}
diff --git a/system/core/URI.php b/system/core/URI.php
index 6a8b1a5ac..15e6a5599 100644
--- a/system/core/URI.php
+++ b/system/core/URI.php
@@ -165,11 +165,8 @@ class CI_URI {
*/
protected function _set_uri_string($str)
{
- // Filter out control characters
- $str = remove_invisible_characters($str, FALSE);
-
- // If the URI contains only a slash we'll kill it
- $this->uri_string = ($str === '/') ? '' : $str;
+ // Filter out control characters and trim slashes
+ $this->uri_string = trim(remove_invisible_characters($str, FALSE), '/');
}
// --------------------------------------------------------------------
diff --git a/system/core/Utf8.php b/system/core/Utf8.php
index 0a7ec501c..1ff02981b 100644
--- a/system/core/Utf8.php
+++ b/system/core/Utf8.php
@@ -49,30 +49,31 @@ class CI_Utf8 {
{
log_message('debug', 'Utf8 Class Initialized');
- global $CFG;
+ $charset = strtoupper(config_item('charset'));
+
+ // set internal encoding for multibyte string functions if necessary
+ // and set a flag so we don't have to repeatedly use extension_loaded()
+ // or function_exists()
+ if (extension_loaded('mbstring'))
+ {
+ define('MB_ENABLED', TRUE);
+ mb_internal_encoding($charset);
+ }
+ else
+ {
+ define('MB_ENABLED', FALSE);
+ }
+
if (
- @preg_match('/./u', 'é') === 1 // PCRE must support UTF-8
- && function_exists('iconv') // iconv must be installed
- && (bool) @ini_get('mbstring.func_overload') !== TRUE // Multibyte string function overloading cannot be enabled
- && $CFG->item('charset') === 'UTF-8' // Application charset must be UTF-8
+ @preg_match('/./u', 'é') === 1 // PCRE must support UTF-8
+ && function_exists('iconv') // iconv must be installed
+ && MB_ENABLED === TRUE // mbstring must be enabled
+ && $charset === 'UTF-8' // Application charset must be UTF-8
)
{
define('UTF8_ENABLED', TRUE);
log_message('debug', 'UTF-8 Support Enabled');
-
- // set internal encoding for multibyte string functions if necessary
- // and set a flag so we don't have to repeatedly use extension_loaded()
- // or function_exists()
- if (extension_loaded('mbstring'))
- {
- define('MB_ENABLED', TRUE);
- mb_internal_encoding('UTF-8');
- }
- else
- {
- define('MB_ENABLED', FALSE);
- }
}
else
{
@@ -135,7 +136,7 @@ class CI_Utf8 {
{
return @iconv($encoding, 'UTF-8', $str);
}
- elseif (function_exists('mb_convert_encoding'))
+ elseif (MB_ENABLED === TRUE)
{
return @mb_convert_encoding($str, 'UTF-8', $encoding);
}
diff --git a/system/database/DB_cache.php b/system/database/DB_cache.php
index ba9110382..d07c755c6 100644
--- a/system/database/DB_cache.php
+++ b/system/database/DB_cache.php
@@ -37,12 +37,20 @@ class CI_DB_Cache {
public $CI;
public $db; // allows passing of db object so that multiple database connections and returned db objects can be supported
+ /**
+ * Constructor
+ *
+ * @param object &$db
+ * @return void
+ */
public function __construct(&$db)
{
// Assign the main CI object to $this->CI and load the file helper since we use it a lot
$this->CI =& get_instance();
$this->db =& $db;
$this->CI->load->helper('file');
+
+ $this->check_path();
}
// --------------------------------------------------------------------
@@ -66,7 +74,9 @@ class CI_DB_Cache {
}
// Add a trailing slash to the path if needed
- $path = preg_replace('/(.+?)\/*$/', '\\1/', $path);
+ $path = realpath($path)
+ ? rtrim(realpath($path), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR
+ : rtrim($path, '/').'/';
if ( ! is_dir($path) OR ! is_really_writable($path))
{
@@ -86,15 +96,11 @@ class CI_DB_Cache {
* The URI being requested will become the name of the cache sub-folder.
* An MD5 hash of the SQL statement will become the cache file name
*
+ * @param string $sql
* @return string
*/
public function read($sql)
{
- if ( ! $this->check_path())
- {
- return $this->db->cache_off();
- }
-
$segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1);
$segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2);
$filepath = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'.md5($sql);
@@ -112,15 +118,12 @@ class CI_DB_Cache {
/**
* Write a query to a cache file
*
+ * @param string $sql
+ * @param object $object
* @return bool
*/
public function write($sql, $object)
{
- if ( ! $this->check_path())
- {
- return $this->db->cache_off();
- }
-
$segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1);
$segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2);
$dir_path = $this->db->cachedir.$segment_one.'+'.$segment_two.'/';
@@ -150,7 +153,9 @@ class CI_DB_Cache {
/**
* Delete cache files within a particular directory
*
- * @return bool
+ * @param string $segment_one = ''
+ * @param string $segment_two = ''
+ * @return void
*/
public function delete($segment_one = '', $segment_two = '')
{
@@ -173,7 +178,7 @@ class CI_DB_Cache {
/**
* Delete all existing cache files
*
- * @return bool
+ * @return void
*/
public function delete_all()
{
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index d63a1d955..7f1434fc1 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -51,6 +51,7 @@ abstract class CI_DB_driver {
public $char_set = 'utf8';
public $dbcollat = 'utf8_general_ci';
public $autoinit = TRUE; // Whether to automatically initialize the DB
+ public $encrypt = FALSE;
public $swap_pre = '';
public $port = '';
public $pconnect = FALSE;
@@ -78,6 +79,10 @@ abstract class CI_DB_driver {
protected $_protect_identifiers = TRUE;
protected $_reserved_identifiers = array('*'); // Identifiers that should NOT be escaped
+ // clause and character used for LIKE escape sequences
+ protected $_like_escape_str = " ESCAPE '%s' ";
+ protected $_like_escape_chr = '!';
+
/**
* The syntax to count rows is slightly different across different
* database engines, so this string appears in each driver and is
@@ -305,8 +310,9 @@ abstract class CI_DB_driver {
* FALSE upon failure, and if the $db_debug variable is set to TRUE
* will raise an error.
*
- * @param string An SQL query string
- * @param array An array of binding data
+ * @param string $sql
+ * @param array $binds = FALSE An array of binding data
+ * @param bool $return_object = NULL
* @return mixed
*/
public function query($sql, $binds = FALSE, $return_object = NULL)
@@ -509,6 +515,7 @@ abstract class CI_DB_driver {
* If strict mode is disabled, each group is treated autonomously, meaning
* a failure of one group will not affect any others
*
+ * @param bool $mode = TRUE
* @return void
*/
public function trans_strict($mode = TRUE)
@@ -521,6 +528,7 @@ abstract class CI_DB_driver {
/**
* Start Transaction
*
+ * @param bool $test_mode = FALSE
* @return void
*/
public function trans_start($test_mode = FALSE)
@@ -669,7 +677,7 @@ abstract class CI_DB_driver {
*/
public function is_write_type($sql)
{
- return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s+/i', $sql);
+ return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s+/i', $sql);
}
// --------------------------------------------------------------------
@@ -805,6 +813,7 @@ abstract class CI_DB_driver {
/**
* Returns an array of table names
*
+ * @param string $constrain_by_prefix = FALSE
* @return array
*/
public function list_tables($constrain_by_prefix = FALSE)
@@ -859,6 +868,7 @@ abstract class CI_DB_driver {
/**
* Determine if a particular table exists
*
+ * @param string $table_name
* @return bool
*/
public function table_exists($table_name)
@@ -1119,30 +1129,19 @@ abstract class CI_DB_driver {
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause
- * @param array the limit clause
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
foreach ($values as $key => $val)
{
$valstr[] = $key.' = '.$val;
}
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
- .$where
- .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '')
- .($limit ? ' LIMIT '.$limit : '');
+ .$this->_compile_wh('qb_where')
+ .$this->_compile_order_by()
+ .($this->qb_limit ? ' LIMIT '.$this->qb_limit : '');
}
// --------------------------------------------------------------------
@@ -1155,7 +1154,7 @@ abstract class CI_DB_driver {
*/
protected function _has_operator($str)
{
- return (bool) preg_match('/(\s|<|>|!|=|IS NULL|IS NOT NULL|BETWEEN)/i', trim($str));
+ return (bool) preg_match('/(<|>|!|=|\sIS NULL|\sIS NOT NULL|\sBETWEEN|\sLIKE|\sIN\s*\(|\s)/i', trim($str));
}
// --------------------------------------------------------------------
@@ -1168,8 +1167,30 @@ abstract class CI_DB_driver {
*/
protected function _get_operator($str)
{
- return preg_match('/(=|!|<|>| IS NULL| IS NOT NULL| BETWEEN)/i', $str, $match)
- ? $match[1] : FALSE;
+ static $_operators;
+
+ if (empty($_operators))
+ {
+ $_les = ($this->_like_escape_str !== '')
+ ? '\s+'.preg_quote(trim(sprintf($this->_like_escape_str, $this->_like_escape_chr)))
+ : '';
+ $_operators = array(
+ '\s*(?:<|>|!)?=\s*', // =, <=, >=, !=
+ '\s*<>?\s*', // <, <>
+ '\s*>\s*', // >
+ '\s+IS NULL', // IS NULL
+ '\s+IS NOT NULL', // IS NOT NULL
+ '\s+BETWEEN\s+\S+\s+AND\s+\S+', // BETWEEN value AND value
+ '\s+IN\s*\([^\)]+\)', // IN(list)
+ '\s+NOT IN\s*\([^\)]+\)', // NOT IN (list)
+ '\s+LIKE\s+\S+'.$_les, // LIKE 'expr'[ ESCAPE '%s']
+ '\s+NOT LIKE\s+\S+'.$_les // NOT LIKE 'expr'[ ESCAPE '%s']
+ );
+
+ }
+
+ return preg_match('/'.implode('|', $_operators).'/i', $str, $match)
+ ? $match[0] : FALSE;
}
// --------------------------------------------------------------------
@@ -1177,8 +1198,8 @@ abstract class CI_DB_driver {
/**
* Enables a native PHP function to be run, using a platform agnostic wrapper.
*
- * @param string the function name
- * @param mixed any parameters needed by the function
+ * @param string $function the function name
+ * @param mixed $param,... optional parameters needed by the function
* @return mixed
*/
public function call_function($function)
@@ -1242,6 +1263,8 @@ abstract class CI_DB_driver {
/**
* Delete the cache files associated with a particular URI
*
+ * @param string $segment_one = ''
+ * @param string $segment_two = ''
* @return bool
*/
public function cache_delete($segment_one = '', $segment_two = '')
@@ -1343,7 +1366,7 @@ abstract class CI_DB_driver {
}
else
{
- $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
+ $message = is_array($error) ? $error : array(str_replace('%s', $swap, $LANG->line($error)));
}
// Find the most likely culprit of the error by going through
@@ -1352,7 +1375,13 @@ abstract class CI_DB_driver {
$trace = debug_backtrace();
foreach ($trace as $call)
{
- if (isset($call['file']) && strpos($call['file'], BASEPATH.'database') === FALSE)
+ // We'll need this on Windows, as APPPATH and BASEPATH will always use forward slashes
+ if (DIRECTORY_SEPARATOR !== '/')
+ {
+ $call['file'] = str_replace('\\', '/', $call['file']);
+ }
+
+ if (isset($call['file'], $call['class']) && strpos($call['file'], BASEPATH.'database') === FALSE && strpos($call['class'], 'Loader') !== FALSE)
{
// Found it - use a relative path for safety
$message[] = 'Filename: '.str_replace(array(APPPATH, BASEPATH), '', $call['file']);
diff --git a/system/database/DB_forge.php b/system/database/DB_forge.php
index 91f9d560c..119d78d38 100644
--- a/system/database/DB_forge.php
+++ b/system/database/DB_forge.php
@@ -37,7 +37,7 @@ abstract class CI_DB_forge {
public $fields = array();
public $keys = array();
public $primary_keys = array();
- public $db_char_set = '';
+ public $db_char_set = '';
// Platform specific SQL strings
protected $_create_database = 'CREATE DATABASE %s';
@@ -45,6 +45,11 @@ abstract class CI_DB_forge {
protected $_drop_table = 'DROP TABLE IF EXISTS %s';
protected $_rename_table = 'ALTER TABLE %s RENAME TO %s';
+ /**
+ * Constructor
+ *
+ * @return void
+ */
public function __construct()
{
// Assign the main database object to $this->db
@@ -206,7 +211,8 @@ abstract class CI_DB_forge {
/**
* Create Table
*
- * @param string the table name
+ * @param string $table = ''
+ * @param bool $if_not_exists = FALSE
* @return bool
*/
public function create_table($table = '', $if_not_exists = FALSE)
@@ -378,9 +384,8 @@ abstract class CI_DB_forge {
/**
* Column Modify
*
- * @param string the table name
- * @param string the column name
- * @param string the column definition
+ * @param string $table = ''
+ * @param string $field = array() column definition
* @return bool
*/
public function modify_column($table = '', $field = array())
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php
index 479b7f24a..5ea9643fe 100644
--- a/system/database/DB_query_builder.php
+++ b/system/database/DB_query_builder.php
@@ -47,7 +47,6 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
protected $qb_from = array();
protected $qb_join = array();
protected $qb_where = array();
- protected $qb_like = array();
protected $qb_groupby = array();
protected $qb_having = array();
protected $qb_keys = array();
@@ -55,7 +54,6 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
protected $qb_offset = FALSE;
protected $qb_orderby = array();
protected $qb_set = array();
- protected $qb_wherein = array();
protected $qb_aliased_tables = array();
protected $qb_store_array = array();
protected $qb_where_group_started = FALSE;
@@ -184,15 +182,17 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * Processing Function for the four functions above:
+ * Processing Function for the following functions:
*
* select_max()
* select_min()
* select_avg()
* select_sum()
*
- * @param string the field
- * @param string an alias
+ *
+ * @param string $select = '' field name
+ * @param string $alias = ''
+ * @param string $type = 'MAX'
* @return object
*/
protected function _max_min_avg_sum($select = '', $alias = '', $type = 'MAX')
@@ -417,7 +417,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
*/
public function where($key, $value = NULL, $escape = NULL)
{
- return $this->_where($key, $value, 'AND ', $escape);
+ return $this->_wh('qb_where', $key, $value, 'AND ', $escape);
}
// --------------------------------------------------------------------
@@ -435,24 +435,27 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
*/
public function or_where($key, $value = NULL, $escape = NULL)
{
- return $this->_where($key, $value, 'OR ', $escape);
+ return $this->_wh('qb_where', $key, $value, 'OR ', $escape);
}
// --------------------------------------------------------------------
/**
- * Where
+ * WHERE, HAVING
*
- * Called by where() or or_where()
+ * Called by where(), or_where(), having(), or_having()
*
+ * @param string 'qb_where' or 'qb_having'
* @param mixed
* @param mixed
* @param string
- * @param mixed
+ * @param bool
* @return object
*/
- protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
+ protected function _wh($qb_key, $key, $value = NULL, $type = 'AND ', $escape = NULL)
{
+ $qb_cache_key = ($qb_key === 'qb_having') ? 'qb_cache_having' : 'qb_cache_where';
+
if ( ! is_array($key))
{
$key = array($key => $value);
@@ -463,17 +466,10 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
foreach ($key as $k => $v)
{
- $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0)
+ $prefix = (count($this->$qb_key) === 0 && count($this->$qb_cache_key) === 0)
? $this->_group_get_type('')
: $this->_group_get_type($type);
- if ($escape === TRUE)
- {
- $k = (($op = $this->_get_operator($k)) !== FALSE)
- ? $this->escape_identifiers(trim(substr($k, 0, strpos($k, $op)))).' '.strstr($k, $op)
- : $this->escape_identifiers(trim($k));
- }
-
if (is_null($v) && ! $this->_has_operator($k))
{
// value appears not to have been set, assign the test to IS NULL
@@ -484,7 +480,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
{
if ($escape === TRUE)
{
- $v = ' '.$this->escape($v);
+ $v = ' '.(is_int($v) ? $v : $this->escape($v));
}
if ( ! $this->_has_operator($k))
@@ -493,11 +489,11 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
}
}
- $this->qb_where[] = $prefix.$k.$v;
+ $this->{$qb_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape);
if ($this->qb_caching === TRUE)
{
- $this->qb_cache_where[] = $prefix.$k.$v;
- $this->qb_cache_exists[] = 'where';
+ $this->{$qb_cache_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape);
+ $this->qb_cache_exists[] = substr($qb_key, 3);
}
}
@@ -510,11 +506,12 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
/**
* Where_in
*
- * Generates a WHERE field IN ('item', 'item') SQL query joined with
+ * Generates a WHERE field IN('item', 'item') SQL query joined with
* AND if appropriate
*
- * @param string The field to search
- * @param array The values searched on
+ * @param string $key = NULL The field to search
+ * @param array $values = NULL The values searched on
+ * @param bool $escape = NULL
* @return object
*/
public function where_in($key = NULL, $values = NULL, $escape = NULL)
@@ -525,13 +522,14 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * Where_in_or
+ * Or_where_in
*
- * Generates a WHERE field IN ('item', 'item') SQL query joined with
+ * Generates a WHERE field IN('item', 'item') SQL query joined with
* OR if appropriate
*
- * @param string The field to search
- * @param array The values searched on
+ * @param string $key = NULL The field to search
+ * @param array $values = NULL The values searched on
+ * @param bool $escape = NULL
* @return object
*/
public function or_where_in($key = NULL, $values = NULL, $escape = NULL)
@@ -544,11 +542,12 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
/**
* Where_not_in
*
- * Generates a WHERE field NOT IN ('item', 'item') SQL query joined
+ * Generates a WHERE field NOT IN('item', 'item') SQL query joined
* with AND if appropriate
*
- * @param string The field to search
- * @param array The values searched on
+ * @param string $key = NULL The field to search
+ * @param array $values = NULL The values searched on
+ * @param bool $escape = NULL
* @return object
*/
public function where_not_in($key = NULL, $values = NULL, $escape = NULL)
@@ -559,13 +558,14 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * Where_not_in_or
+ * Or_where_not_in
*
- * Generates a WHERE field NOT IN ('item', 'item') SQL query joined
+ * Generates a WHERE field NOT IN('item', 'item') SQL query joined
* with OR if appropriate
*
- * @param string The field to search
- * @param array The values searched on
+ * @param string $key = NULL The field to search
+ * @param array $values = NULL The values searched on
+ * @param bool $escape = NULL
* @return object
*/
public function or_where_not_in($key = NULL, $values = NULL, $escape = NULL)
@@ -578,12 +578,13 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
/**
* Where_in
*
- * Called by where_in, where_in_or, where_not_in, where_not_in_or
+ * Called by where_in(), or_where_in(), where_not_in(), or_where_not_in()
*
- * @param string The field to search
- * @param array The values searched on
- * @param bool If the statement would be IN or NOT IN
- * @param string
+ * @param string $key = NULL The field to search
+ * @param array $values = NULL The values searched on
+ * @param bool $not = FALSE If the statement would be IN or NOT IN
+ * @param string $type = 'AND '
+ * @param bool $escape = NULL
* @return object
*/
protected function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ', $escape = NULL)
@@ -602,27 +603,25 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
$not = ($not) ? ' NOT' : '';
+ $where_in = array();
foreach ($values as $value)
{
- $this->qb_wherein[] = $this->escape($value);
- }
-
- if ($escape === TRUE)
- {
- $key = $this->escape_identifiers(trim($key));
+ $where_in[] = $this->escape($value);
}
$prefix = (count($this->qb_where) === 0) ? $this->_group_get_type('') : $this->_group_get_type($type);
- $this->qb_where[] = $where_in = $prefix.$key.$not.' IN ('.implode(', ', $this->qb_wherein).') ';
+ $where_in = array(
+ 'condition' => $prefix.$key.$not.' IN('.implode(', ', $where_in).')',
+ 'escape' => $escape
+ );
+ $this->qb_where[] = $where_in;
if ($this->qb_caching === TRUE)
{
$this->qb_cache_where[] = $where_in;
$this->qb_cache_exists[] = 'where';
}
- // reset the array for multiple calls
- $this->qb_wherein = array();
return $this;
}
@@ -635,12 +634,14 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* multiple calls with AND
*
* @param mixed
- * @param mixed
+ * @param string
+ * @param string
+ * @param bool
* @return object
*/
- public function like($field, $match = '', $side = 'both')
+ public function like($field, $match = '', $side = 'both', $escape = NULL)
{
- return $this->_like($field, $match, 'AND ', $side);
+ return $this->_like($field, $match, 'AND ', $side, '', $escape);
}
// --------------------------------------------------------------------
@@ -652,12 +653,14 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* multiple calls with AND
*
* @param mixed
- * @param mixed
+ * @param string
+ * @param string
+ * @param bool
* @return object
*/
- public function not_like($field, $match = '', $side = 'both')
+ public function not_like($field, $match = '', $side = 'both', $escape = NULL)
{
- return $this->_like($field, $match, 'AND ', $side, 'NOT');
+ return $this->_like($field, $match, 'AND ', $side, 'NOT', $escape);
}
// --------------------------------------------------------------------
@@ -669,12 +672,14 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* multiple calls with OR
*
* @param mixed
- * @param mixed
+ * @param string
+ * @param string
+ * @param bool
* @return object
*/
- public function or_like($field, $match = '', $side = 'both')
+ public function or_like($field, $match = '', $side = 'both', $escape = NULL)
{
- return $this->_like($field, $match, 'OR ', $side);
+ return $this->_like($field, $match, 'OR ', $side, '', $escape);
}
// --------------------------------------------------------------------
@@ -686,12 +691,14 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* multiple calls with OR
*
* @param mixed
- * @param mixed
+ * @param string
+ * @param string
+ * @param bool
* @return object
*/
- public function or_not_like($field, $match = '', $side = 'both')
+ public function or_not_like($field, $match = '', $side = 'both', $escape = NULL)
{
- return $this->_like($field, $match, 'OR ', $side, 'NOT');
+ return $this->_like($field, $match, 'OR ', $side, 'NOT', $escape);
}
// --------------------------------------------------------------------
@@ -699,56 +706,60 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
/**
* Like
*
- * Called by like() or orlike()
+ * Called by like(), or_like(), not_like, or_not_like()
*
* @param mixed
- * @param mixed
* @param string
+ * @param string
+ * @param string
+ * @param string
+ * @param bool
* @return object
*/
- protected function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '')
+ protected function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '', $escape = NULL)
{
if ( ! is_array($field))
{
$field = array($field => $match);
}
+ is_bool($escape) OR $escape = $this->_protect_identifiers;
+ $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0)
+ ? $this->_group_get_type('') : $this->_group_get_type($type);
+
foreach ($field as $k => $v)
{
- $k = $this->protect_identifiers($k);
- $prefix = (count($this->qb_like) === 0) ? $this->_group_get_type('') : $this->_group_get_type($type);
$v = $this->escape_like_str($v);
if ($side === 'none')
{
- $like_statement = "{$prefix} $k $not LIKE '{$v}'";
+ $like_statement = "{$prefix} {$k} {$not} LIKE '{$v}'";
}
elseif ($side === 'before')
{
- $like_statement = "{$prefix} $k $not LIKE '%{$v}'";
+ $like_statement = "{$prefix} {$k} {$not} LIKE '%{$v}'";
}
elseif ($side === 'after')
{
- $like_statement = "{$prefix} $k $not LIKE '{$v}%'";
+ $like_statement = "{$prefix} {$k} {$not} LIKE '{$v}%'";
}
else
{
- $like_statement = "{$prefix} $k $not LIKE '%{$v}%'";
+ $like_statement = "{$prefix} {$k} {$not} LIKE '%{$v}%'";
}
// some platforms require an escape sequence definition for LIKE wildcards
if ($this->_like_escape_str !== '')
{
- $like_statement = $like_statement.sprintf($this->_like_escape_str, $this->_like_escape_chr);
+ $like_statement .= sprintf($this->_like_escape_str, $this->_like_escape_chr);
}
- $this->qb_like[] = $like_statement;
+ $this->qb_where[] = array('condition' => $like_statement, 'escape' => $escape);
if ($this->qb_caching === TRUE)
{
- $this->qb_cache_like[] = $like_statement;
- $this->qb_cache_exists[] = 'like';
+ $this->qb_cache_where[] = $like_statement;
+ $this->qb_cache_exists[] = 'where';
}
-
}
return $this;
@@ -769,11 +780,15 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
$this->qb_where_group_started = TRUE;
$prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0) ? '' : $type;
- $this->qb_where[] = $value = $prefix.$not.str_repeat(' ', ++$this->qb_where_group_count).' (';
+ $where = array(
+ 'condition' => $prefix.$not.str_repeat(' ', ++$this->qb_where_group_count).' (',
+ 'escape' => FALSE
+ );
+ $this->qb_where[] = $where;
if ($this->qb_caching)
{
- $this->qb_cache_where[] = $value;
+ $this->qb_cache_where[] = $where;
}
return $this;
@@ -825,11 +840,15 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
public function group_end()
{
$this->qb_where_group_started = FALSE;
- $this->qb_where[] = $value = str_repeat(' ', $this->qb_where_group_count--) . ')';
+ $where = array(
+ 'condition' => str_repeat(' ', $this->qb_where_group_count--).')',
+ 'escape' => FALSE
+ );
+ $this->qb_where[] = $where;
if ($this->qb_caching)
{
- $this->qb_cache_where[] = $value;
+ $this->qb_cache_where[] = $where;
}
return $this;
@@ -862,13 +881,18 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* GROUP BY
*
* @param string
+ * @param bool
* @return object
*/
- public function group_by($by)
+ public function group_by($by, $escape = NULL)
{
+ is_bool($escape) OR $escape = $this->_protect_identifiers;
+
if (is_string($by))
{
- $by = explode(',', $by);
+ $by = ($escape === TRUE)
+ ? explode(',', $by)
+ : array($by);
}
foreach ($by as $val)
@@ -877,8 +901,9 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
if ($val !== '')
{
- $this->qb_groupby[] = $val = $this->protect_identifiers($val);
+ $val = array('field' => $val, 'escape' => $escape);
+ $this->qb_groupby[] = $val;
if ($this->qb_caching === TRUE)
{
$this->qb_cache_groupby[] = $val;
@@ -902,9 +927,9 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* @param bool
* @return object
*/
- public function having($key, $value = '', $escape = NULL)
+ public function having($key, $value = NULL, $escape = NULL)
{
- return $this->_having($key, $value, 'AND ', $escape);
+ return $this->_wh('qb_having', $key, $value, 'AND ', $escape);
}
// --------------------------------------------------------------------
@@ -919,60 +944,9 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* @param bool
* @return object
*/
- public function or_having($key, $value = '', $escape = NULL)
+ public function or_having($key, $value = NULL, $escape = NULL)
{
- return $this->_having($key, $value, 'OR ', $escape);
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Sets the HAVING values
- *
- * Called by having() or or_having()
- *
- * @param string
- * @param string
- * @param string
- * @param bool
- * @return object
- */
- protected function _having($key, $value = '', $type = 'AND ', $escape = NULL)
- {
- if ( ! is_array($key))
- {
- $key = array($key => $value);
- }
-
- is_bool($escape) OR $escape = $this->_protect_identifiers;
-
- foreach ($key as $k => $v)
- {
- $prefix = (count($this->qb_having) === 0) ? '' : $type;
-
- $k = $this->_has_operator($k)
- ? $this->protect_identifiers(substr($k, 0, strpos(rtrim($k), ' ')), FALSE, $escape).strchr(rtrim($k), ' ')
- : $this->protect_identifiers($k, FALSE, $escape);
-
- if ( ! $this->_has_operator($k))
- {
- $k .= ' = ';
- }
-
- if ($v !== '')
- {
- $v = ' '.$this->escape($v);
- }
-
- $this->qb_having[] = $prefix.$k.$v;
- if ($this->qb_caching === TRUE)
- {
- $this->qb_cache_having[] = $prefix.$k.$v;
- $this->qb_cache_exists[] = 'having';
- }
- }
-
- return $this;
+ return $this->_wh('qb_having', $key, $value, 'OR ', $escape);
}
// --------------------------------------------------------------------
@@ -981,54 +955,50 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* Sets the ORDER BY value
*
* @param string
- * @param string direction: asc or desc
+ * @param string direction: ASC or DESC
* @param bool enable field name escaping
* @return object
*/
public function order_by($orderby, $direction = '', $escape = NULL)
{
- if (strtolower($direction) === 'random')
+ $direction = trim($direction);
+
+ if (strtolower($direction) === 'random' OR $orderby === $this->_random_keyword)
+ {
+ // Random ordered results don't need a field name
+ $orderby = $this->_random_keyword;
+ $direction = '';
+ }
+ elseif (empty($orderby))
{
- $orderby = ''; // Random results want or don't need a field name
- $direction = $this->_random_keyword;
+ return $this;
}
- elseif (trim($direction) !== '')
+ elseif ($direction !== '')
{
- $direction = in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE) ? ' '.$direction : ' ASC';
+ $direction = in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE) ? ' '.$direction : '';
}
is_bool($escape) OR $escape = $this->_protect_identifiers;
- if ($escape === TRUE && strpos($orderby, ',') !== FALSE)
+ if ($escape === FALSE)
{
- $temp = array();
- foreach (explode(',', $orderby) as $part)
- {
- $part = trim($part);
- if ( ! in_array($part, $this->qb_aliased_tables))
- {
- $part = preg_match('/^(.+)\s+(ASC|DESC)$/i', $part, $matches)
- ? $this->protect_identifiers(rtrim($matches[1])).' '.$matches[2]
- : $this->protect_identifiers($part);
- }
-
- $temp[] = $part;
- }
-
- $orderby = implode(', ', $temp);
+ $qb_orderby[] = array('field' => $orderby, 'direction' => $direction, 'escape' => FALSE);
}
- elseif ($direction !== $this->_random_keyword && $escape === TRUE)
+ else
{
- $orderby = preg_match('/^(.+)\s+(ASC|DESC)$/i', $orderby, $matches)
- ? $this->protect_identifiers(rtrim($matches[1])).' '.$matches[2]
- : $this->protect_identifiers($orderby);
+ $qb_orderby = array();
+ foreach (explode(',', $orderby) as $field)
+ {
+ $qb_orderby[] = ($direction === '' && preg_match('/\s+(ASC|DESC)$/i', rtrim($field), $match, PREG_OFFSET_CAPTURE))
+ ? array('field' => ltrim(substr($field, 0, $match[0][1])), 'direction' => ' '.$match[1][0], 'escape' => TRUE)
+ : array('field' => trim($field), 'direction' => $direction, 'escape' => TRUE);
+ }
}
- $this->qb_orderby[] = $orderby_statement = $orderby.$direction;
-
+ $this->qb_orderby = array_merge($this->qb_orderby, $qb_orderby);
if ($this->qb_caching === TRUE)
{
- $this->qb_cache_orderby[] = $orderby_statement;
+ $this->qb_cache_orderby = array_merge($this->qb_cache_orderby, $qb_orderby);
$this->qb_cache_exists[] = 'orderby';
}
@@ -1044,7 +1014,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* @param int the offset value
* @return object
*/
- public function limit($value, $offset = NULL)
+ public function limit($value, $offset = FALSE)
{
is_null($value) OR $this->qb_limit = (int) $value;
empty($offset) OR $this->qb_offset = (int) $offset;
@@ -1074,13 +1044,11 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- return $sql.' LIMIT '.($offset ? $offset.', ' : '').$limit;
+ return $sql.' LIMIT '.($this->qb_offset ? $this->qb_offset.', ' : '').$this->qb_limit;
}
// --------------------------------------------------------------------
@@ -1213,9 +1181,10 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
*
* Allows the where clause, limit and offset to be added directly
*
- * @param string the where clause
- * @param string the limit clause
- * @param string the offset clause
+ * @param string $table = ''
+ * @param string $where = NULL
+ * @param int $limit = NULL
+ * @param int $offset = NULL
* @return object
*/
public function get_where($table = '', $where = NULL, $limit = NULL, $offset = NULL)
@@ -1247,9 +1216,9 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
*
* Compiles batch insert strings and runs the queries
*
- * @param string the table to retrieve the results from
- * @param array an associative array of insert values
- * @return object
+ * @param string $table = '' table to insert into
+ * @param array $set an associative array of insert values
+ * @return int number of rows inserted or FALSE on failure
*/
public function insert_batch($table = '', $set = NULL)
{
@@ -1260,12 +1229,8 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
if (count($this->qb_set) === 0)
{
- if ($this->db_debug)
- {
- // No valid data array. Folds in cases where keys and values did not match up
- return $this->display_error('db_must_use_set');
- }
- return FALSE;
+ // No valid data array. Folds in cases where keys and values did not match up
+ return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE;
}
if ($table === '')
@@ -1279,13 +1244,15 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
}
// Batch this baby
+ $affected_rows = 0;
for ($i = 0, $total = count($this->qb_set); $i < $total; $i += 100)
{
$this->query($this->_insert_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), $this->qb_keys, array_slice($this->qb_set, $i, 100)));
+ $affected_rows += $this->affected_rows();
}
$this->_reset_write();
- return TRUE;
+ return $affected_rows;
}
// --------------------------------------------------------------------
@@ -1522,19 +1489,18 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * From Tables
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
*
- * This public function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
+ * Note: This is only used (and overriden) by MySQL and CUBRID.
*
- * @param array
- * @return string
+ * @return string
*/
- protected function _from_tables($tables)
+ protected function _from_tables()
{
- is_array($tables) OR $tables = array($tables);
-
- return (count($tables) === 1) ? $tables[0] : '('.implode(', ', $tables).')';
+ return implode(', ', $this->qb_from);
}
// --------------------------------------------------------------------
@@ -1558,7 +1524,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
return FALSE;
}
- $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set, $this->qb_where, $this->qb_orderby, $this->qb_limit);
+ $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set);
if ($reset === TRUE)
{
@@ -1575,9 +1541,10 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
*
* Compiles an update string and runs the query
*
- * @param string the table to retrieve the results from
- * @param array an associative array of update values
- * @param mixed the where clause
+ * @param string $table = ''
+ * @param array $set = NULL an associative array of update values
+ * @param mixed $where = NULL
+ * @param int $limit = NULL
* @return object
*/
public function update($table = '', $set = NULL, $where = NULL, $limit = NULL)
@@ -1605,7 +1572,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
$this->limit($limit);
}
- $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set, $this->qb_where, $this->qb_orderby, $this->qb_limit, $this->qb_like);
+ $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set);
$this->_reset_write();
return $this->query($sql);
@@ -1652,7 +1619,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* @param string the table to retrieve the results from
* @param array an associative array of update values
* @param string the where key
- * @return bool
+ * @return int number of rows affected or FALSE on failure
*/
public function update_batch($table = '', $set = NULL, $index = NULL)
{
@@ -1685,13 +1652,15 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
}
// Batch this baby
+ $affected_rows = 0;
for ($i = 0, $total = count($this->qb_set); $i < $total; $i += 100)
{
- $this->query($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->qb_set, $i, 100), $this->protect_identifiers($index), $this->qb_where));
+ $this->query($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->qb_set, $i, 100), $this->protect_identifiers($index)));
+ $affected_rows += $this->affected_rows();
}
$this->_reset_write();
- return TRUE;
+ return $affected_rows;
}
// --------------------------------------------------------------------
@@ -1852,7 +1821,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* @param mixed the where clause
* @param mixed the limit clause
* @param bool
- * @return object
+ * @return mixed
*/
public function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE)
{
@@ -1872,10 +1841,8 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
{
foreach ($table as $single_table)
{
- $this->delete($single_table, $where, $limit, FALSE);
+ $this->delete($single_table, $where, $limit, $reset_data);
}
-
- $this->_reset_write();
return;
}
else
@@ -1893,12 +1860,12 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
$this->limit($limit);
}
- if (count($this->qb_where) === 0 && count($this->qb_wherein) === 0 && count($this->qb_like) === 0)
+ if (count($this->qb_where) === 0)
{
return ($this->db_debug) ? $this->display_error('db_del_must_use_where') : FALSE;
}
- $sql = $this->_delete($table, $this->qb_where, $this->qb_like, $this->qb_limit);
+ $sql = $this->_delete($table);
if ($reset_data)
{
$this->_reset_write();
@@ -1915,21 +1882,12 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- return 'DELETE FROM '.$table
- .(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '')
- .($limit ? ' LIMIT '.(int) $limit : '');
+ return 'DELETE FROM '.$table.$this->_compile_wh('qb_where')
+ .($this->qb_limit ? ' LIMIT '.$this->qb_limit : '');
}
// --------------------------------------------------------------------
@@ -2018,8 +1976,9 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* Compile the SELECT statement
*
* Generates a query string based on which functions were used.
- * Should not be called directly. The get() function calls it.
+ * Should not be called directly.
*
+ * @param bool $select_override = FALSE
* @return string
*/
protected function _compile_select($select_override = FALSE)
@@ -2058,7 +2017,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// Write the "FROM" portion of the query
if (count($this->qb_from) > 0)
{
- $sql .= "\nFROM ".$this->_from_tables($this->qb_from);
+ $sql .= "\nFROM ".$this->_from_tables();
}
// Write the "JOIN" portion of the query
@@ -2067,50 +2026,156 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
$sql .= "\n".implode("\n", $this->qb_join);
}
- // Write the "WHERE" portion of the query
- if (count($this->qb_where) > 0 OR count($this->qb_like) > 0)
+ $sql .= $this->_compile_wh('qb_where')
+ .$this->_compile_group_by()
+ .$this->_compile_wh('qb_having')
+ .$this->_compile_order_by(); // ORDER BY
+
+ // LIMIT
+ if ($this->qb_limit)
{
- $sql .= "\nWHERE ";
+ return $this->_limit($sql."\n");
}
- $sql .= implode("\n", $this->qb_where);
+ return $sql;
+ }
+
+ // --------------------------------------------------------------------
- // Write the "LIKE" portion of the query
- if (count($this->qb_like) > 0)
+ /**
+ * Compile WHERE, HAVING statements
+ *
+ * Escapes identifiers in WHERE and HAVING statements at execution time.
+ *
+ * Required so that aliases are tracked properly, regardless of wether
+ * where(), or_where(), having(), or_having are called prior to from(),
+ * join() and dbprefix is added only if needed.
+ *
+ * @param string 'qb_where' or 'qb_having'
+ * @return string SQL statement
+ */
+ protected function _compile_wh($qb_key)
+ {
+ if (count($this->$qb_key) > 0)
{
- if (count($this->qb_where) > 0)
+ for ($i = 0, $c = count($this->$qb_key); $i < $c; $i++)
{
- $sql .= "\nAND ";
+ if ($this->{$qb_key}[$i]['escape'] === FALSE)
+ {
+ $this->{$qb_key}[$i] = $this->{$qb_key}[$i]['condition'];
+ continue;
+ }
+
+ // Split multiple conditions
+ $conditions = preg_split(
+ '/(\s*AND\s+|\s*OR\s+)/i',
+ $this->{$qb_key}[$i]['condition'],
+ -1,
+ PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
+ );
+
+ for ($ci = 0, $cc = count($conditions); $ci < $cc; $ci++)
+ {
+ if (($op = $this->_get_operator($conditions[$ci])) === FALSE
+ OR ! preg_match('/^(\(?)(.*)('.preg_quote($op).')\s*(.*(?<!\)))?(\)?)$/i', $conditions[$ci], $matches))
+ {
+ continue;
+ }
+
+ // $matches = array(
+ // 0 => '(test <= foo)', /* the whole thing */
+ // 1 => '(', /* optional */
+ // 2 => 'test', /* the field name */
+ // 3 => ' <= ', /* $op */
+ // 4 => 'foo', /* optional, if $op is e.g. 'IS NULL' */
+ // 5 => ')' /* optional */
+ // );
+
+ if ( ! empty($matches[4]))
+ {
+ $this->_is_literal($matches[4]) OR $matches[4] = $this->protect_identifiers(trim($matches[4]));
+ $matches[4] = ' '.$matches[4];
+ }
+
+ $conditions[$ci] = $matches[1].$this->protect_identifiers(trim($matches[2]))
+ .' '.trim($matches[3]).$matches[4].$matches[5];
+ }
+
+ $this->{$qb_key}[$i] = implode('', $conditions);
}
- $sql .= implode("\n", $this->qb_like);
+ return ($qb_key === 'qb_having' ? "\nHAVING " : "\nWHERE ")
+ .implode("\n", $this->$qb_key);
}
- // Write the "GROUP BY" portion of the query
+ return '';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Compile GROUP BY
+ *
+ * Escapes identifiers in GROUP BY statements at execution time.
+ *
+ * Required so that aliases are tracked properly, regardless of wether
+ * group_by() is called prior to from(), join() and dbprefix is added
+ * only if needed.
+ *
+ * @return string SQL statement
+ */
+ protected function _compile_group_by()
+ {
if (count($this->qb_groupby) > 0)
{
- $sql .= "\nGROUP BY ".implode(', ', $this->qb_groupby);
- }
+ for ($i = 0, $c = count($this->qb_groupby); $i < $c; $i++)
+ {
+ $this->qb_groupby[$i] = ($this->qb_groupby[$i]['escape'] === FALSE OR $this->_is_literal($this->qb_groupby[$i]['field']))
+ ? $this->qb_groupby[$i]['field']
+ : $this->protect_identifiers($this->qb_groupby[$i]['field']);
+ }
- // Write the "HAVING" portion of the query
- if (count($this->qb_having) > 0)
- {
- $sql .= "\nHAVING ".implode("\n", $this->qb_having);
+ return "\nGROUP BY ".implode(', ', $this->qb_groupby);
}
- // Write the "ORDER BY" portion of the query
- if (count($this->qb_orderby) > 0)
+ return '';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Compile ORDER BY
+ *
+ * Escapes identifiers in ORDER BY statements at execution time.
+ *
+ * Required so that aliases are tracked properly, regardless of wether
+ * order_by() is called prior to from(), join() and dbprefix is added
+ * only if needed.
+ *
+ * @return string SQL statement
+ */
+ protected function _compile_order_by()
+ {
+ if (is_array($this->qb_orderby) && count($this->qb_orderby) > 0)
{
- $sql .= "\nORDER BY ".implode(', ', $this->qb_orderby);
- }
+ for ($i = 0, $c = count($this->qb_orderby); $i < $c; $i++)
+ {
+ if ($this->qb_orderby[$i]['escape'] !== FALSE && ! $this->_is_literal($this->qb_orderby[$i]['field']))
+ {
+ $this->qb_orderby[$i]['field'] = $this->protect_identifiers($this->qb_orderby[$i]['field']);
+ }
+
+ $this->qb_orderby[$i] = $this->qb_orderby[$i]['field'].$this->qb_orderby[$i]['direction'];
+ }
- // Write the "LIMIT" portion of the query
- if (is_numeric($this->qb_limit))
+ return $this->qb_orderby = "\nORDER BY ".implode(', ', $this->qb_orderby);
+ }
+ elseif (is_string($this->qb_orderby))
{
- return $this->_limit($sql."\n", $this->qb_limit, $this->qb_offset);
+ return $this->qb_orderby;
}
- return $sql;
+ return '';
}
// --------------------------------------------------------------------
@@ -2277,6 +2342,36 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
+ * Is literal
+ *
+ * Determines if a string represents a literal value or a field name
+ *
+ * @param string
+ * @return bool
+ */
+ protected function _is_literal($str)
+ {
+ $str = trim($str);
+
+ if (empty($str))
+ {
+ return TRUE;
+ }
+
+ static $_str;
+
+ if (empty($_str))
+ {
+ $_str = ($this->_escape_char !== '"')
+ ? array('"', "'") : array("'");
+ }
+
+ return (ctype_digit($str) OR in_array($str[0], $_str, TRUE));
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Reset Query Builder values.
*
* Publicly-visible method to reset the QB values.
@@ -2322,11 +2417,9 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
'qb_from' => array(),
'qb_join' => array(),
'qb_where' => array(),
- 'qb_like' => array(),
'qb_groupby' => array(),
'qb_having' => array(),
'qb_orderby' => array(),
- 'qb_wherein' => array(),
'qb_aliased_tables' => array(),
'qb_no_escape' => array(),
'qb_distinct' => FALSE,
@@ -2351,7 +2444,6 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
'qb_set' => array(),
'qb_from' => array(),
'qb_where' => array(),
- 'qb_like' => array(),
'qb_orderby' => array(),
'qb_keys' => array(),
'qb_limit' => FALSE
diff --git a/system/database/DB_result.php b/system/database/DB_result.php
index d44df6c02..76093f918 100644
--- a/system/database/DB_result.php
+++ b/system/database/DB_result.php
@@ -251,27 +251,24 @@ class CI_DB_result {
/**
* Query result. Acts as a wrapper function for the following functions.
*
- * @param string
- * @param string can be "object" or "array"
- * @return mixed either a result object or array
+ * @param mixed $n = 0
+ * @param string $type = 'object' 'object' or 'array'
+ * @return mixed
*/
public function row($n = 0, $type = 'object')
{
if ( ! is_numeric($n))
{
// We cache the row data for subsequent uses
- if ( ! is_array($this->row_data))
- {
- $this->row_data = $this->row_array(0);
- }
+ is_array($this->row_data) OR $this->row_data = $this->row_array(0);
- // array_key_exists() instead of isset() to allow for MySQL NULL values
- if (array_key_exists($n, $this->row_data))
+ // array_key_exists() instead of isset() to allow for NULL values
+ if (empty($this->row_data) OR ! array_key_exists($n, $this->row_data))
{
- return $this->row_data[$n];
+ return NULL;
}
- // reset the $n variable if the result was not achieved
- $n = 0;
+
+ return $this->row_data[$n];
}
if ($type === 'object') return $this->row_object($n);
@@ -284,6 +281,8 @@ class CI_DB_result {
/**
* Assigns an item into a particular column slot
*
+ * @param mixed $key
+ * @param mixed $value
* @return void
*/
public function set_row($key, $value = NULL)
@@ -314,6 +313,8 @@ class CI_DB_result {
/**
* Returns a single result row - custom object version
*
+ * @param int $n
+ * @param string $type
* @return object
*/
public function custom_row_object($n, $type)
@@ -338,6 +339,7 @@ class CI_DB_result {
/**
* Returns a single result row - object version
*
+ * @param int $n = 0
* @return object
*/
public function row_object($n = 0)
@@ -361,6 +363,7 @@ class CI_DB_result {
/**
* Returns a single result row - array version
*
+ * @param int $n = 0
* @return array
*/
public function row_array($n = 0)
@@ -384,7 +387,8 @@ class CI_DB_result {
/**
* Returns the "first" row
*
- * @return object
+ * @param string $type = 'object'
+ * @return mixed
*/
public function first_row($type = 'object')
{
@@ -397,7 +401,8 @@ class CI_DB_result {
/**
* Returns the "last" row
*
- * @return object
+ * @param string $type = 'object'
+ * @return mixed
*/
public function last_row($type = 'object')
{
@@ -410,7 +415,8 @@ class CI_DB_result {
/**
* Returns the "next" row
*
- * @return object
+ * @param string $type = 'object'
+ * @return mixed
*/
public function next_row($type = 'object')
{
@@ -433,7 +439,8 @@ class CI_DB_result {
/**
* Returns the "previous" row
*
- * @return object
+ * @param string $type = 'object'
+ * @return mixed
*/
public function previous_row($type = 'object')
{
@@ -455,8 +462,8 @@ class CI_DB_result {
/**
* Returns an unbuffered row and move pointer to next row
*
- * @param string 'array', 'object' or a custom class name
- * @return mixed either a result object or array
+ * @param string $type = 'object' 'array', 'object' or a custom class name
+ * @return mixed
*/
public function unbuffered_row($type = 'object')
{
diff --git a/system/database/DB_utility.php b/system/database/DB_utility.php
index 6a3b40779..8078e2bf6 100644
--- a/system/database/DB_utility.php
+++ b/system/database/DB_utility.php
@@ -41,6 +41,11 @@ abstract class CI_DB_utility extends CI_DB_forge {
protected $_optimize_table = FALSE;
protected $_repair_table = FALSE;
+ /**
+ * Constructor
+ *
+ * @return void
+ */
public function __construct()
{
// Assign the main database object to $this->db
@@ -275,6 +280,7 @@ abstract class CI_DB_utility extends CI_DB_forge {
/**
* Database Backup
*
+ * @param array $params = array()
* @return void
*/
public function backup($params = array())
diff --git a/system/database/drivers/cubrid/cubrid_driver.php b/system/database/drivers/cubrid/cubrid_driver.php
index a3d0287f5..8e77d8396 100644
--- a/system/database/drivers/cubrid/cubrid_driver.php
+++ b/system/database/drivers/cubrid/cubrid_driver.php
@@ -45,15 +45,17 @@ class CI_DB_cubrid_driver extends CI_DB {
// The character used for escaping - no need in CUBRID
protected $_escape_char = '`';
- // clause and character used for LIKE escape sequences - not used in CUBRID
- protected $_like_escape_str = '';
- protected $_like_escape_chr = '';
-
protected $_random_keyword = ' RAND()'; // database specific random keyword
// CUBRID-specific properties
public $auto_commit = TRUE;
+ /**
+ * Constructor
+ *
+ * @param array $params
+ * @return void
+ */
public function __construct($params)
{
parent::__construct($params);
@@ -72,6 +74,8 @@ class CI_DB_cubrid_driver extends CI_DB {
}
}
+ // --------------------------------------------------------------------
+
/**
* Non-persistent database connection
*
@@ -182,6 +186,7 @@ class CI_DB_cubrid_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode = FALSE
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -396,10 +401,10 @@ class CI_DB_cubrid_driver extends CI_DB {
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -423,9 +428,29 @@ class CI_DB_cubrid_driver extends CI_DB {
.'ELSE '.$k.' END, ';
}
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN ('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
+ *
+ * @return string
+ */
+ protected function _from_tables()
+ {
+ if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
+ {
+ return '('.implode(', ', $this->qb_from).')';
+ }
+
+ return implode(', ', $this->qb_from);
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/cubrid/cubrid_result.php b/system/database/drivers/cubrid/cubrid_result.php
index 4a06a2d39..360c50dc2 100644
--- a/system/database/drivers/cubrid/cubrid_result.php
+++ b/system/database/drivers/cubrid/cubrid_result.php
@@ -132,6 +132,7 @@ class CI_DB_cubrid_result extends CI_DB_result {
* this internally before fetching results to make sure the
* result set starts at zero
*
+ * @param int $n = 0
* @return bool
*/
protected function _data_seek($n = 0)
diff --git a/system/database/drivers/ibase/ibase_driver.php b/system/database/drivers/ibase/ibase_driver.php
index c9027670d..c3be519bf 100644
--- a/system/database/drivers/ibase/ibase_driver.php
+++ b/system/database/drivers/ibase/ibase_driver.php
@@ -45,10 +45,6 @@ class CI_DB_ibase_driver extends CI_DB {
// The character used to escape with
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
-
protected $_random_keyword = ' Random()'; // database specific random keyword
// Keeps track of the resource for the current transaction
@@ -120,6 +116,7 @@ class CI_DB_ibase_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode = FALSE
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -285,7 +282,10 @@ class CI_DB_ibase_driver extends CI_DB {
*/
protected function _field_data($table)
{
- return $this->_limit('SELECT * FROM '.$this->protect_identifiers($table), 1, NULL);
+ $this->qb_limit = 1;
+ $sql = $this->_limit('SELECT * FROM '.$this->protect_identifiers($table));
+ $this->qb_limit = 0;
+ return $sql;
}
// --------------------------------------------------------------------
@@ -306,51 +306,18 @@ class CI_DB_ibase_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This public function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
- .$where
- .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '');
+ $this->qb_limit = FALSE;
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -379,19 +346,12 @@ class CI_DB_ibase_driver extends CI_DB {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -402,22 +362,20 @@ class CI_DB_ibase_driver extends CI_DB {
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
// Limit clause depends on if Interbase or Firebird
if (stripos($this->version(), 'firebird') !== FALSE)
{
- $select = 'FIRST '. (int) $limit
- .($offset ? ' SKIP '. (int) $offset : '');
+ $select = 'FIRST '.$this->qb_limit
+ .($this->qb_offset ? ' SKIP '.$this->qb_offset : '');
}
else
{
$select = 'ROWS '
- .($offset ? (int) $offset.' TO '.($limit + $offset) : (int) $limit);
+ .($this->qb_offset ? $this->qb_offset.' TO '.($this->qb_limit + $this->qb_offset) : $this->qb_limit);
}
return preg_replace('`SELECT`i', 'SELECT '.$select, $sql);
diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php
index 1714704a8..2063dad90 100644
--- a/system/database/drivers/mssql/mssql_driver.php
+++ b/system/database/drivers/mssql/mssql_driver.php
@@ -45,21 +45,17 @@ class CI_DB_mssql_driver extends CI_DB {
// The character used for escaping
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
-
protected $_random_keyword = ' NEWID()';
// MSSQL-specific properties
protected $_quoted_identifier = TRUE;
- /*
+ /**
* Constructor
*
* Appends the port number to the hostname, if needed.
*
- * @param array
+ * @param array $params
* @return void
*/
public function __construct($params)
@@ -156,6 +152,7 @@ class CI_DB_mssql_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode = FALSE
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -366,49 +363,19 @@ class CI_DB_mssql_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).' WHERE '.$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -437,23 +404,16 @@ class CI_DB_mssql_driver extends CI_DB {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
+ if ($this->qb_limit)
+ {
+ return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete';
+ }
- return ($limit)
- ? 'WITH ci_delete AS (SELECT TOP '.$limit.' * FROM '.$table.$conditions.') DELETE FROM ci_delete'
- : 'DELETE FROM '.$table.$conditions;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -464,33 +424,44 @@ class CI_DB_mssql_driver extends CI_DB {
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- // As of SQL Server 2012 (11.0.*) OFFSET is supported
- if (version_compare($this->version(), '11', '>='))
- {
- return $sql.' OFFSET '.(int) $offset.' ROWS FETCH NEXT '.(int) $limit.' ROWS ONLY';
- }
-
- $limit = $offset + $limit;
+ $limit = $this->qb_offset + $this->qb_limit;
// As of SQL Server 2005 (9.0.*) ROW_NUMBER() is supported,
// however an ORDER BY clause is required for it to work
- if (version_compare($this->version(), '9', '>=') && $offset && ! empty($this->qb_orderby))
+ if (version_compare($this->version(), '9', '>=') && $this->qb_offset && ! empty($this->qb_orderby))
{
- $orderby = 'ORDER BY '.implode(', ', $this->qb_orderby);
+ $orderby = $this->_compile_order_by();
// We have to strip the ORDER BY clause
- $sql = trim(substr($sql, 0, strrpos($sql, 'ORDER BY '.$orderby)));
+ $sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
+
+ // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results
+ if (count($this->qb_select) === 0)
+ {
+ $select = '*'; // Inevitable
+ }
+ else
+ {
+ // Use only field names and their aliases, everything else is out of our scope.
+ $select = array();
+ $field_regexp = ($this->_quoted_identifier)
+ ? '("[^\"]+")' : '(\[[^\]]+\])';
+ for ($i = 0, $c = count($this->qb_select); $i < $c; $i++)
+ {
+ $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m)
+ ? $m[1] : $this->qb_select[$i];
+ }
+ $select = implode(', ', $select);
+ }
- return 'SELECT '.(count($this->qb_select) === 0 ? '*' : implode(', ', $this->qb_select))." FROM (\n"
- .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.$orderby.') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
- ."\n) ".$this->escape_identifiers('CI_subquery')
- ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.((int) $offset + 1).' AND '.$limit;
+ return 'SELECT '.$select." FROM (\n\n"
+ .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+ ."\n\n) ".$this->escape_identifiers('CI_subquery')
+ ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
}
return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
diff --git a/system/database/drivers/mssql/mssql_result.php b/system/database/drivers/mssql/mssql_result.php
index aeede3f4b..84d2814f1 100644
--- a/system/database/drivers/mssql/mssql_result.php
+++ b/system/database/drivers/mssql/mssql_result.php
@@ -133,6 +133,7 @@ class CI_DB_mssql_result extends CI_DB_result {
* this internally before fetching results to make sure the
* result set starts at zero
*
+ * @param int $n = 0
* @return bool
*/
protected function _data_seek($n = 0)
diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php
index 29db90408..f82e775e6 100644
--- a/system/database/drivers/mysql/mysql_driver.php
+++ b/system/database/drivers/mysql/mysql_driver.php
@@ -41,14 +41,11 @@
class CI_DB_mysql_driver extends CI_DB {
public $dbdriver = 'mysql';
+ public $compress = FALSE;
// The character used for escaping
protected $_escape_char = '`';
- // clause and character used for LIKE escape sequences - not used in MySQL
- protected $_like_escape_str = '';
- protected $_like_escape_chr = '\\';
-
protected $_random_keyword = ' RAND()'; // database specific random keyword
/**
@@ -79,11 +76,21 @@ class CI_DB_mysql_driver extends CI_DB {
/**
* Non-persistent database connection
*
+ * @param bool
* @return resource
*/
- public function db_connect()
+ public function db_connect($persistent = FALSE)
{
- return @mysql_connect($this->hostname, $this->username, $this->password, TRUE);
+ $client_flags = ($this->compress === FALSE) ? 0 : MYSQL_CLIENT_COMPRESS;
+
+ if ($this->encrypt === TRUE)
+ {
+ $client_flags = $client_flags | MYSQL_CLIENT_SSL;
+ }
+
+ return ($persistent === TRUE)
+ ? @mysql_pconnect($this->hostname, $this->username, $this->password, $client_flags)
+ : @mysql_connect($this->hostname, $this->username, $this->password, TRUE, $client_flags);
}
// --------------------------------------------------------------------
@@ -95,7 +102,7 @@ class CI_DB_mysql_driver extends CI_DB {
*/
public function db_pconnect()
{
- return @mysql_pconnect($this->hostname, $this->username, $this->password);
+ return $this->db_connect(TRUE);
}
// --------------------------------------------------------------------
@@ -207,6 +214,7 @@ class CI_DB_mysql_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode = FALSE
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -420,10 +428,10 @@ class CI_DB_mysql_driver extends CI_DB {
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -447,9 +455,29 @@ class CI_DB_mysql_driver extends CI_DB {
.'ELSE '.$k.' END, ';
}
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
+ *
+ * @return string
+ */
+ protected function _from_tables()
+ {
+ if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
+ {
+ return '('.implode(', ', $this->qb_from).')';
+ }
+
+ return implode(', ', $this->qb_from);
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysql/mysql_result.php b/system/database/drivers/mysql/mysql_result.php
index 7fbb65496..b3f669e40 100644
--- a/system/database/drivers/mysql/mysql_result.php
+++ b/system/database/drivers/mysql/mysql_result.php
@@ -146,6 +146,7 @@ class CI_DB_mysql_result extends CI_DB_result {
* this internally before fetching results to make sure the
* result set starts at zero
*
+ * @param int $n = 0
* @return bool
*/
protected function _data_seek($n = 0)
diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index be61aab20..6c4f87513 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -41,14 +41,11 @@
class CI_DB_mysqli_driver extends CI_DB {
public $dbdriver = 'mysqli';
+ public $compress = FALSE;
// The character used for escaping
protected $_escape_char = '`';
- // clause and character used for LIKE escape sequences - not used in MySQL
- protected $_like_escape_str = '';
- protected $_like_escape_chr = '\\';
-
protected $_random_keyword = ' RAND()'; // database specific random keyword
/**
@@ -61,13 +58,21 @@ class CI_DB_mysqli_driver extends CI_DB {
/**
* Non-persistent database connection
*
+ * @param bool
* @return object
+ * @todo SSL support
*/
- public function db_connect()
+ public function db_connect($persistent = FALSE)
{
- return empty($this->port)
- ? @new mysqli($this->hostname, $this->username, $this->password, $this->database)
- : @new mysqli($this->hostname, $this->username, $this->password, $this->database, $this->port);
+ // Persistent connection support was added in PHP 5.3.0
+ $hostname = ($persistent === TRUE && is_php('5.3'))
+ ? 'p:'.$this->hostname : $this->hostname;
+ $port = empty($this->port) ? NULL : $this->port;
+ $client_flags = ($this->compress === TRUE) ? MYSQLI_CLIENT_COMPRESS : 0;
+ $mysqli = mysqli_init();
+
+ return @$mysqli->real_connect($hostname, $this->username, $this->password, $this->database, $port, NULL, $client_flags)
+ ? $mysqli : FALSE;
}
// --------------------------------------------------------------------
@@ -79,15 +84,7 @@ class CI_DB_mysqli_driver extends CI_DB {
*/
public function db_pconnect()
{
- // Persistent connection support was added in PHP 5.3.0
- if ( ! is_php('5.3'))
- {
- return $this->db_connect();
- }
-
- return empty($this->port)
- ? @new mysqli('p:'.$this->hostname, $this->username, $this->password, $this->database)
- : @new mysqli('p:'.$this->hostname, $this->username, $this->password, $this->database, $this->port);
+ return $this->db_connect(TRUE);
}
// --------------------------------------------------------------------
@@ -199,6 +196,7 @@ class CI_DB_mysqli_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode = FALSE
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -400,6 +398,14 @@ class CI_DB_mysqli_driver extends CI_DB {
*/
public function error()
{
+ if ( ! empty($this->conn_id->connect_errno))
+ {
+ return array(
+ 'code' => $this->conn_id->connect_errno,
+ 'message' => is_php('5.2.9') ? $this->conn_id->connect_error : mysqli_connect_error()
+ );
+ }
+
return array('code' => $this->conn_id->errno, 'message' => $this->conn_id->error);
}
@@ -412,10 +418,10 @@ class CI_DB_mysqli_driver extends CI_DB {
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -439,11 +445,29 @@ class CI_DB_mysqli_driver extends CI_DB {
.'ELSE '.$k.' END, ';
}
- $where = ($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
+ *
+ * @return string
+ */
+ protected function _from_tables()
+ {
+ if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
+ {
+ return '('.implode(', ', $this->qb_from).')';
+ }
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN('.implode(',', $ids).')';
+ return implode(', ', $this->qb_from);
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysqli/mysqli_result.php b/system/database/drivers/mysqli/mysqli_result.php
index c1ec4da76..f036302bb 100644
--- a/system/database/drivers/mysqli/mysqli_result.php
+++ b/system/database/drivers/mysqli/mysqli_result.php
@@ -132,6 +132,7 @@ class CI_DB_mysqli_result extends CI_DB_result {
* this internally before fetching results to make sure the
* result set starts at zero
*
+ * @param int $n = 0
* @return bool
*/
protected function _data_seek($n = 0)
diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php
index 691247fee..81d73d073 100644
--- a/system/database/drivers/oci8/oci8_driver.php
+++ b/system/database/drivers/oci8/oci8_driver.php
@@ -54,10 +54,6 @@ class CI_DB_oci8_driver extends CI_DB {
// The character used for excaping
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
-
/**
* The syntax to count rows is slightly different across different
* database engines, so this string appears in each driver and is
@@ -79,6 +75,12 @@ class CI_DB_oci8_driver extends CI_DB {
// throw off num_fields later
public $limit_used;
+ /**
+ * Constructor
+ *
+ * @param array $params
+ * @return void
+ */
public function __construct($params)
{
parent::__construct($params);
@@ -547,22 +549,6 @@ class CI_DB_oci8_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Insert_batch statement
*
* Generates a platform-specific insert string from the supplied data
@@ -611,20 +597,17 @@ class CI_DB_oci8_driver extends CI_DB {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
- empty($limit) OR $conditions[] = 'rownum <= '.$limit;
+ if ($this->qb_limit)
+ {
+ $this->where('rownum <= ',$this->qb_limit, FALSE);
+ $this->qb_limit = FALSE;
+ }
- return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -635,15 +618,13 @@ class CI_DB_oci8_driver extends CI_DB {
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
$this->limit_used = TRUE;
- return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($offset + $limit + 1).')'
- .($offset ? ' WHERE rnum >= '.($offset + 1): '');
+ return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($this->qb_offset + $this->qb_limit + 1).')'
+ .($this->qb_offset ? ' WHERE rnum >= '.($this->qb_offset + 1): '');
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php
index 8f0a474b0..063a04b98 100644
--- a/system/database/drivers/odbc/odbc_driver.php
+++ b/system/database/drivers/odbc/odbc_driver.php
@@ -45,12 +45,16 @@ class CI_DB_odbc_driver extends CI_DB {
// the character used to excape - not necessary for ODBC
protected $_escape_char = '';
- // clause and character used for LIKE escape sequences
protected $_like_escape_str = " {escape '%s'} ";
- protected $_like_escape_chr = '!';
protected $_random_keyword;
+ /**
+ * Constructor
+ *
+ * @param array $params
+ * @return void
+ */
public function __construct($params)
{
parent::__construct($params);
@@ -64,6 +68,8 @@ class CI_DB_odbc_driver extends CI_DB {
}
}
+ // --------------------------------------------------------------------
+
/**
* Non-persistent database connection
*
@@ -104,6 +110,7 @@ class CI_DB_odbc_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode = FALSE
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -291,17 +298,19 @@ class CI_DB_odbc_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
+ * Update statement
*
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
+ * Generates a platform-specific update string from the supplied data
*
- * @param array
+ * @param string the table name
+ * @param array the update data
* @return string
- */
- protected function _from_tables($tables)
+ */
+ protected function _update($table, $values)
{
- return is_array($tables) ? implode(', ', $tables) : $tables;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -325,6 +334,22 @@ class CI_DB_odbc_driver extends CI_DB {
// --------------------------------------------------------------------
/**
+ * Delete statement
+ *
+ * Generates a platform-specific delete string from the supplied data
+ *
+ * @param string the table name
+ * @return string
+ */
+ protected function _delete($table)
+ {
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Close DB Connection
*
* @return void
diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php
index 705b16560..32a9e7509 100644
--- a/system/database/drivers/pdo/pdo_driver.php
+++ b/system/database/drivers/pdo/pdo_driver.php
@@ -45,10 +45,6 @@ class CI_DB_pdo_driver extends CI_DB {
// The character used to escaping
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
-
protected $_random_keyword;
public $trans_enabled = FALSE;
@@ -61,7 +57,7 @@ class CI_DB_pdo_driver extends CI_DB {
*
* Validates the DSN string and/or detects the subdriver
*
- * @param array
+ * @param array $params
* @return void
*/
public function __construct($params)
@@ -187,6 +183,7 @@ class CI_DB_pdo_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode = FALSE
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -360,14 +357,12 @@ class CI_DB_pdo_driver extends CI_DB {
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
- $where = ($where !== '' && count($where) >=1) ? implode(' ', $where).' AND ' : '';
-
foreach ($values as $key => $val)
{
$ids[] = $val[$index];
@@ -381,9 +376,7 @@ class CI_DB_pdo_driver extends CI_DB {
}
}
- $sql = 'UPDATE '.$table.' SET ';
$cases = '';
-
foreach ($final as $k => $v)
{
$cases .= $k.' = CASE '."\n";
@@ -396,10 +389,9 @@ class CI_DB_pdo_driver extends CI_DB {
$cases .= 'ELSE '.$k.' END, ';
}
- $sql .= substr($cases, 0, -2);
- $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
- return $sql;
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php b/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php
index e287f5c63..438d312a1 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php
@@ -130,49 +130,19 @@ class CI_DB_pdo_4d_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -183,21 +153,12 @@ class CI_DB_pdo_4d_driver extends CI_DB_pdo_driver {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
-
- return 'DELETE FROM '.$table.$conditions;
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -208,13 +169,11 @@ class CI_DB_pdo_4d_driver extends CI_DB_pdo_driver {
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- return $sql.' LIMIT '.$limit.($offset ? ' OFFSET '.$offset : '');
+ return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : '');
}
}
diff --git a/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php b/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php
index 05eeacfe6..d2a484d9e 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php
@@ -44,10 +44,6 @@ class CI_DB_pdo_cubrid_driver extends CI_DB_pdo_driver {
protected $_escape_char = '`';
- // clause and character used for LIKE escape sequences - not used in CUBRID
- protected $_like_escape_str = '';
- protected $_like_escape_chr = '\\';
-
protected $_random_keyword = ' RAND()';
/**
@@ -133,10 +129,10 @@ class CI_DB_pdo_cubrid_driver extends CI_DB_pdo_driver {
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -160,9 +156,9 @@ class CI_DB_pdo_cubrid_driver extends CI_DB_pdo_driver {
.'ELSE '.$k.' END), ';
}
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
}
// --------------------------------------------------------------------
@@ -183,6 +179,26 @@ class CI_DB_pdo_cubrid_driver extends CI_DB_pdo_driver {
return 'TRUNCATE '.$table;
}
+ // --------------------------------------------------------------------
+
+ /**
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
+ *
+ * @return string
+ */
+ protected function _from_tables()
+ {
+ if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
+ {
+ return '('.implode(', ', $this->qb_from).')';
+ }
+
+ return implode(', ', $this->qb_from);
+ }
+
}
/* End of file pdo_cubrid_driver.php */
diff --git a/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php b/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php
index 7060c9eb9..785b2795c 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php
@@ -153,49 +153,19 @@ class CI_DB_pdo_dblib_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -206,23 +176,16 @@ class CI_DB_pdo_dblib_driver extends CI_DB_pdo_driver {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
+ if ($this->qb_limit)
+ {
+ return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete';
+ }
- return ($limit)
- ? 'WITH ci_delete AS (SELECT TOP '.$limit.' * FROM '.$table.$conditions.') DELETE FROM ci_delete'
- : 'DELETE FROM '.$table.$conditions;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -233,27 +196,44 @@ class CI_DB_pdo_dblib_driver extends CI_DB_pdo_driver {
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- $limit = $offset + $limit;
+ $limit = $this->qb_offset + $this->qb_limit;
// As of SQL Server 2005 (9.0.*) ROW_NUMBER() is supported,
// however an ORDER BY clause is required for it to work
- if (version_compare($this->version(), '9', '>=') && $offset && ! empty($this->qb_orderby))
+ if (version_compare($this->version(), '9', '>=') && $this->qb_offset && ! empty($this->qb_orderby))
{
- $orderby = 'ORDER BY '.implode(', ', $this->qb_orderby);
+ $orderby = $this->_compile_order_by();
// We have to strip the ORDER BY clause
- $sql = trim(substr($sql, 0, strrpos($sql, 'ORDER BY '.$orderby)));
+ $sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
+
+ // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results
+ if (count($this->qb_select) === 0)
+ {
+ $select = '*'; // Inevitable
+ }
+ else
+ {
+ // Use only field names and their aliases, everything else is out of our scope.
+ $select = array();
+ $field_regexp = ($this->_quoted_identifier)
+ ? '("[^\"]+")' : '(\[[^\]]+\])';
+ for ($i = 0, $c = count($this->qb_select); $i < $c; $i++)
+ {
+ $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m)
+ ? $m[1] : $this->qb_select[$i];
+ }
+ $select = implode(', ', $select);
+ }
- return 'SELECT '.(count($this->qb_select) === 0 ? '*' : implode(', ', $this->qb_select))." FROM (\n"
- .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.$orderby.') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
- ."\n) ".$this->escape_identifiers('CI_subquery')
- ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.((int) $offset + 1).' AND '.$limit;
+ return 'SELECT '.$select." FROM (\n\n"
+ .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+ ."\n\n) ".$this->escape_identifiers('CI_subquery')
+ ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
}
return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
@@ -262,4 +242,4 @@ class CI_DB_pdo_dblib_driver extends CI_DB_pdo_driver {
}
/* End of file pdo_dblib_driver.php */
-/* Location: ./system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php b/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php
index c074a9a78..32d1f219a 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php
@@ -139,51 +139,18 @@ class CI_DB_pdo_firebird_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
- .$where
- .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '');
+ $this->qb_limit = FALSE;
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -212,19 +179,12 @@ class CI_DB_pdo_firebird_driver extends CI_DB_pdo_driver {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -235,22 +195,20 @@ class CI_DB_pdo_firebird_driver extends CI_DB_pdo_driver {
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
// Limit clause depends on if Interbase or Firebird
if (stripos($this->version(), 'firebird') !== FALSE)
{
- $select = 'FIRST '. (int) $limit
- .($offset > 0 ? ' SKIP '. (int) $offset : '');
+ $select = 'FIRST '.$this->qb_limit
+ .($this->qb_offset > 0 ? ' SKIP '.$this->qb_offset : '');
}
else
{
$select = 'ROWS '
- .($offset > 0 ? (int) $offset.' TO '.($limit + $offset) : (int) $limit);
+ .($this->qb_offset > 0 ? $this->qb_offset.' TO '.($this->qb_limit + $this->qb_offset) : $this->qb_limit);
}
return preg_replace('`SELECT`i', 'SELECT '.$select, $sql);
diff --git a/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php b/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php
index 832c03c96..22a5f928c 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php
@@ -165,49 +165,19 @@ class CI_DB_pdo_ibm_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -218,21 +188,12 @@ class CI_DB_pdo_ibm_driver extends CI_DB_pdo_driver {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
-
- return 'DELETE FROM '.$table.$conditions;
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php b/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php
index a3efc63dc..8dd430184 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php
@@ -159,49 +159,19 @@ class CI_DB_pdo_informix_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -230,21 +200,12 @@ class CI_DB_pdo_informix_driver extends CI_DB_pdo_driver {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
-
- return 'DELETE FROM '.$table.$conditions;
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -255,13 +216,11 @@ class CI_DB_pdo_informix_driver extends CI_DB_pdo_driver {
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- $select = 'SELECT '.($offset ? 'SKIP '.$offset : '').'FIRST '.$limit.' ';
+ $select = 'SELECT '.($this->qb_offset ? 'SKIP '.$this->qb_offset : '').'FIRST '.$this->qb_limit.' ';
return preg_replace('/^(SELECT\s)/i', $select, $sql, 1);
}
diff --git a/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
index 78afe246c..0fb5d8f12 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
@@ -41,13 +41,10 @@
class CI_DB_pdo_mysql_driver extends CI_DB_pdo_driver {
public $subdriver = 'mysql';
+ public $compress = FALSE;
protected $_escape_char = '`';
- // clause and character used for LIKE escape sequences - not used in MySQL
- protected $_like_escape_str = '';
- protected $_like_escape_chr = '\\';
-
protected $_random_keyword = ' RAND()';
/**
@@ -83,6 +80,7 @@ class CI_DB_pdo_mysql_driver extends CI_DB_pdo_driver {
*
* @param bool
* @return object
+ * @todo SSL support
*/
public function db_connect($persistent = FALSE)
{
@@ -97,6 +95,11 @@ class CI_DB_pdo_mysql_driver extends CI_DB_pdo_driver {
.(empty($this->dbcollat) ? '' : ' COLLATE '.$this->dbcollat);
}
+ if ($this->compress === TRUE)
+ {
+ $this->options[PDO::MYSQL_ATTR_COMPRESS] = TRUE;
+ }
+
return parent::db_connect($persistent);
}
@@ -161,10 +164,10 @@ class CI_DB_pdo_mysql_driver extends CI_DB_pdo_driver {
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -188,9 +191,9 @@ class CI_DB_pdo_mysql_driver extends CI_DB_pdo_driver {
.'ELSE '.$k.' END), ';
}
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
}
// --------------------------------------------------------------------
@@ -211,6 +214,26 @@ class CI_DB_pdo_mysql_driver extends CI_DB_pdo_driver {
return 'TRUNCATE '.$table;
}
+ // --------------------------------------------------------------------
+
+ /**
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
+ *
+ * @return string
+ */
+ protected function _from_tables()
+ {
+ if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
+ {
+ return '('.implode(', ', $this->qb_from).')';
+ }
+
+ return implode(', ', $this->qb_from);
+ }
+
}
/* End of file pdo_mysql_driver.php */
diff --git a/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php b/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php
index 56ec1bce1..b03218fad 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php
@@ -146,22 +146,6 @@ class CI_DB_pdo_oci_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Insert_batch statement
*
* @param string the table name
@@ -190,20 +174,17 @@ class CI_DB_pdo_oci_driver extends CI_DB_pdo_driver {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
- empty($limit) OR $conditions[] = 'rownum <= '.$limit;
+ if ($this->qb_limit)
+ {
+ $this->where('rownum <= ',$this->qb_limit, FALSE);
+ $this->qb_limit = FALSE;
+ }
- return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -214,14 +195,12 @@ class CI_DB_pdo_oci_driver extends CI_DB_pdo_driver {
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($offset + $limit + 1).')'
- .($offset ? ' WHERE rnum >= '.($offset + 1): '');
+ return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($this->qb_offset + $this->qb_limit + 1).')'
+ .($this->qb_offset ? ' WHERE rnum >= '.($this->qb_offset + 1): '');
}
}
diff --git a/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php b/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php
index 392754ff7..5944d55f4 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php
@@ -46,7 +46,6 @@ class CI_DB_pdo_odbc_driver extends CI_DB_pdo_driver {
protected $_escape_char = '';
// clause and character used for LIKE escape sequences
- protected $_like_escape_chr = '!';
protected $_like_escape_str = " {escape '%s'} ";
protected $_random_keyword = ' RAND()';
@@ -157,49 +156,19 @@ class CI_DB_pdo_odbc_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -228,21 +197,12 @@ class CI_DB_pdo_odbc_driver extends CI_DB_pdo_driver {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
-
- return 'DELETE FROM '.$table.$conditions;
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -253,13 +213,11 @@ class CI_DB_pdo_odbc_driver extends CI_DB_pdo_driver {
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
+ return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$this->qb_limit.' ', $sql);
}
}
diff --git a/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php b/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php
index 9a476f143..74d56e6b8 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php
@@ -142,49 +142,19 @@ class CI_DB_pdo_pgsql_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -196,10 +166,10 @@ class CI_DB_pdo_pgsql_driver extends CI_DB_pdo_driver {
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -218,14 +188,14 @@ class CI_DB_pdo_pgsql_driver extends CI_DB_pdo_driver {
$cases = '';
foreach ($final as $k => $v)
{
- $cases .= $k.' = (CASE '.$k."\n"
+ $cases .= $k.' = (CASE '.$index."\n"
.implode("\n", $v)."\n"
.'ELSE '.$k.' END), ';
}
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
}
// --------------------------------------------------------------------
@@ -236,19 +206,12 @@ class CI_DB_pdo_pgsql_driver extends CI_DB_pdo_driver {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -259,29 +222,31 @@ class CI_DB_pdo_pgsql_driver extends CI_DB_pdo_driver {
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- return $sql.' LIMIT '.$limit.($offset ? ' OFFSET '.$offset : '');
+ return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : '');
}
// --------------------------------------------------------------------
/**
- * Where
+ * WHERE, HAVING
*
- * Called by where() or or_where()
+ * Called by where(), or_where(), having(), or_having()
*
+ * @param string 'qb_where' or 'qb_having'
* @param mixed
* @param mixed
* @param string
+ * @param bool
* @return object
*/
- protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
+ protected function _wh($qb_key, $key, $value = NULL, $type = 'AND ', $escape = NULL)
{
+ $qb_cache_key = ($qb_key === 'qb_having') ? 'qb_cache_having' : 'qb_cache_where';
+
if ( ! is_array($key))
{
$key = array($key => $value);
@@ -292,14 +257,10 @@ class CI_DB_pdo_pgsql_driver extends CI_DB_pdo_driver {
foreach ($key as $k => $v)
{
- $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0)
+ $prefix = (count($this->$qb_key) === 0 && count($this->$qb_cache_key) === 0)
? $this->_group_get_type('')
: $this->_group_get_type($type);
- $k = (($op = $this->_get_operator($k)) !== FALSE)
- ? $this->protect_identifiers(substr($k, 0, strpos($k, $op)), FALSE, $escape).strstr($k, $op)
- : $this->protect_identifiers($k, FALSE, $escape);
-
if (is_null($v) && ! $this->_has_operator($k))
{
// value appears not to have been set, assign the test to IS NULL
@@ -308,13 +269,13 @@ class CI_DB_pdo_pgsql_driver extends CI_DB_pdo_driver {
if ( ! is_null($v))
{
- if ($escape === TRUE)
+ if (is_bool($v))
{
- $v = ' '.$this->escape($v);
+ $v = ' '.($v ? 'TRUE' : 'FALSE');
}
- elseif (is_bool($v))
+ elseif ($escape === TRUE)
{
- $v = ($v ? ' TRUE' : ' FALSE');
+ $v = ' '.(is_int($v) ? $v : $this->escape($v));
}
if ( ! $this->_has_operator($k))
@@ -323,11 +284,11 @@ class CI_DB_pdo_pgsql_driver extends CI_DB_pdo_driver {
}
}
- $this->qb_where[] = $prefix.$k.$v;
+ $this->{$qb_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape);
if ($this->qb_caching === TRUE)
{
- $this->qb_cache_where[] = $prefix.$k.$v;
- $this->qb_cache_exists[] = 'where';
+ $this->{$qb_cache_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape);
+ $this->qb_cache_exists[] = substr($qb_key, 3);
}
}
diff --git a/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php
index f125b8f50..33bd7bea5 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php
@@ -78,9 +78,9 @@ class CI_DB_pdo_sqlsrv_driver extends CI_DB_pdo_driver {
$this->dsn .= ';ConnectionPooling='.$this->ConnectionPooling;
}
- if (isset($this->Encrypt))
+ if ($this->encrypt === TRUE)
{
- $this->dsn .= ';Encrypt='.$this->Encrypt;
+ $this->dsn .= ';Encrypt=1';
}
if (isset($this->TraceOn))
@@ -182,49 +182,19 @@ class CI_DB_pdo_sqlsrv_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -235,23 +205,16 @@ class CI_DB_pdo_sqlsrv_driver extends CI_DB_pdo_driver {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
+ if ($this->qb_limit)
+ {
+ return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete';
+ }
- return ($limit)
- ? 'WITH ci_delete AS (SELECT TOP '.$limit.' * FROM '.$table.$conditions.') DELETE FROM ci_delete'
- : 'DELETE FROM '.$table.$conditions;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -262,32 +225,49 @@ class CI_DB_pdo_sqlsrv_driver extends CI_DB_pdo_driver {
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
// As of SQL Server 2012 (11.0.*) OFFSET is supported
if (version_compare($this->version(), '11', '>='))
{
- return $sql.' OFFSET '.(int) $offset.' ROWS FETCH NEXT '.(int) $limit.' ROWS ONLY';
+ return $sql.' OFFSET '.(int) $this->qb_offset.' ROWS FETCH NEXT '.$this->qb_limit.' ROWS ONLY';
}
- $limit = $offset + $limit;
+ $limit = $this->qb_offset + $this->qb_limit;
// An ORDER BY clause is required for ROW_NUMBER() to work
- if ($offset && ! empty($this->qb_orderby))
+ if ($this->qb_offset && ! empty($this->qb_orderby))
{
- $orderby = 'ORDER BY '.implode(', ', $this->qb_orderby);
+ $orderby = $this->_compile_order_by();
// We have to strip the ORDER BY clause
- $sql = trim(substr($sql, 0, strrpos($sql, 'ORDER BY '.$orderby)));
+ $sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
+
+ // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results
+ if (count($this->qb_select) === 0)
+ {
+ $select = '*'; // Inevitable
+ }
+ else
+ {
+ // Use only field names and their aliases, everything else is out of our scope.
+ $select = array();
+ $field_regexp = ($this->_quoted_identifier)
+ ? '("[^\"]+")' : '(\[[^\]]+\])';
+ for ($i = 0, $c = count($this->qb_select); $i < $c; $i++)
+ {
+ $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m)
+ ? $m[1] : $this->qb_select[$i];
+ }
+ $select = implode(', ', $select);
+ }
- return 'SELECT '.(count($this->qb_select) === 0 ? '*' : implode(', ', $this->qb_select))." FROM (\n"
- .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.$orderby.') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
- ."\n) ".$this->escape_identifiers('CI_subquery')
- ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.((int) $offset + 1).' AND '.$limit;
+ return 'SELECT '.$select." FROM (\n\n"
+ .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+ ."\n\n) ".$this->escape_identifiers('CI_subquery')
+ ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
}
return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
@@ -296,4 +276,4 @@ class CI_DB_pdo_sqlsrv_driver extends CI_DB_pdo_driver {
}
/* End of file pdo_sqlsrv_driver.php */
-/* Location: ./system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php */ \ No newline at end of file
diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index 031740851..1b9474920 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -44,10 +44,6 @@ class CI_DB_postgre_driver extends CI_DB {
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
-
protected $_random_keyword = ' RANDOM()'; // database specific random keyword
/**
@@ -55,6 +51,7 @@ class CI_DB_postgre_driver extends CI_DB {
*
* Creates a DSN string to be used for db_connect() and db_pconnect()
*
+ * @param array $params
* @return void
*/
public function __construct($params)
@@ -132,7 +129,15 @@ class CI_DB_postgre_driver extends CI_DB {
*/
public function db_pconnect()
{
- return @pg_pconnect($this->dsn);
+ $conn = @pg_pconnect($this->dsn);
+ if ($conn && pg_connection_status($conn) === PGSQL_CONNECTION_BAD)
+ {
+ if (pg_ping($conn) === FALSE)
+ {
+ return FALSE;
+ }
+ }
+ return $conn;
}
// --------------------------------------------------------------------
@@ -453,49 +458,19 @@ class CI_DB_postgre_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -507,10 +482,10 @@ class CI_DB_postgre_driver extends CI_DB {
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -534,9 +509,9 @@ class CI_DB_postgre_driver extends CI_DB {
.'ELSE '.$k.' END), ';
}
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
}
// --------------------------------------------------------------------
@@ -547,19 +522,12 @@ class CI_DB_postgre_driver extends CI_DB {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -570,30 +538,31 @@ class CI_DB_postgre_driver extends CI_DB {
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- return $sql.' LIMIT '.$limit.($offset ? ' OFFSET '.$offset : '');
+ return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : '');
}
// --------------------------------------------------------------------
/**
- * Where
+ * WHERE, HAVING
*
- * Called by where() or or_where()
+ * Called by where(), or_where(), having(), or_having()
*
+ * @param string 'qb_where' or 'qb_having'
* @param mixed
* @param mixed
* @param string
- * @param mixed
+ * @param bool
* @return object
*/
- protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
+ protected function _wh($qb_key, $key, $value = NULL, $type = 'AND ', $escape = NULL)
{
+ $qb_cache_key = ($qb_key === 'qb_having') ? 'qb_cache_having' : 'qb_cache_where';
+
if ( ! is_array($key))
{
$key = array($key => $value);
@@ -604,17 +573,10 @@ class CI_DB_postgre_driver extends CI_DB {
foreach ($key as $k => $v)
{
- $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0)
+ $prefix = (count($this->$qb_key) === 0 && count($this->$qb_cache_key) === 0)
? $this->_group_get_type('')
: $this->_group_get_type($type);
- if ($escape === TRUE)
- {
- $k = (($op = $this->_get_operator($k)) !== FALSE)
- ? $this->escape_identifiers(trim(substr($k, 0, strpos($k, $op)))).' '.strstr($k, $op)
- : $this->escape_identifiers(trim($k));
- }
-
if (is_null($v) && ! $this->_has_operator($k))
{
// value appears not to have been set, assign the test to IS NULL
@@ -623,13 +585,13 @@ class CI_DB_postgre_driver extends CI_DB {
if ( ! is_null($v))
{
- if ($escape === TRUE)
+ if (is_bool($v))
{
- $v = ' '.$this->escape($v);
+ $v = ' '.($v ? 'TRUE' : 'FALSE');
}
- elseif (is_bool($v))
+ elseif ($escape === TRUE)
{
- $v = ($v ? ' TRUE' : ' FALSE');
+ $v = ' '.(is_int($v) ? $v : $this->escape($v));
}
if ( ! $this->_has_operator($k))
@@ -638,11 +600,11 @@ class CI_DB_postgre_driver extends CI_DB {
}
}
- $this->qb_where[] = $prefix.$k.$v;
+ $this->{$qb_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape);
if ($this->qb_caching === TRUE)
{
- $this->qb_cache_where[] = $prefix.$k.$v;
- $this->qb_cache_exists[] = 'where';
+ $this->{$qb_cache_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape);
+ $this->qb_cache_exists[] = substr($qb_key, 3);
}
}
diff --git a/system/database/drivers/postgre/postgre_forge.php b/system/database/drivers/postgre/postgre_forge.php
index c434e9510..1164d9bb3 100644
--- a/system/database/drivers/postgre/postgre_forge.php
+++ b/system/database/drivers/postgre/postgre_forge.php
@@ -39,7 +39,8 @@ class CI_DB_postgre_forge extends CI_DB_forge {
/**
* Process Fields
*
- * @param mixed the fields
+ * @param mixed $fields
+ * @param array $primary_keys = array()
* @return string
*/
protected function _process_fields($fields, $primary_keys = array())
@@ -190,13 +191,10 @@ class CI_DB_postgre_forge extends CI_DB_forge {
* Generates a platform-specific query so that a table can be altered
* Called by add_column(), drop_column(), and column_alter(),
*
- * @param string the ALTER type (ADD, DROP, CHANGE)
- * @param string the column name
- * @param string the table name
- * @param string the column definition
- * @param string the default value
- * @param bool should 'NOT NULL' be added
- * @param string the field after which we should add the new field
+ * @param string $alter_type the ALTER type (ADD, DROP, CHANGE)
+ * @param string $table the table name
+ * @param string $fields the column definition
+ * @param string $after_field = ''
* @return string
*/
protected function _alter_table($alter_type, $table, $fields, $after_field = '')
diff --git a/system/database/drivers/postgre/postgre_result.php b/system/database/drivers/postgre/postgre_result.php
index eb9d647e7..458ae869c 100644
--- a/system/database/drivers/postgre/postgre_result.php
+++ b/system/database/drivers/postgre/postgre_result.php
@@ -131,6 +131,7 @@ class CI_DB_postgre_result extends CI_DB_result {
* this internally before fetching results to make sure the
* result set starts at zero
*
+ * @param int $n = 0
* @return bool
*/
protected function _data_seek($n = 0)
diff --git a/system/database/drivers/sqlite/sqlite_driver.php b/system/database/drivers/sqlite/sqlite_driver.php
index 19824dbbf..2fd39346f 100644
--- a/system/database/drivers/sqlite/sqlite_driver.php
+++ b/system/database/drivers/sqlite/sqlite_driver.php
@@ -45,10 +45,6 @@ class CI_DB_sqlite_driver extends CI_DB {
// The character used to escape with - not needed for SQLite
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
-
protected $_random_keyword = ' Random()'; // database specific random keyword
/**
@@ -131,6 +127,7 @@ class CI_DB_sqlite_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode = FALSE
* @return bool
*/
public function trans_begin($test_mode = FALSE)
diff --git a/system/database/drivers/sqlite/sqlite_result.php b/system/database/drivers/sqlite/sqlite_result.php
index eef9787a1..214841412 100644
--- a/system/database/drivers/sqlite/sqlite_result.php
+++ b/system/database/drivers/sqlite/sqlite_result.php
@@ -115,6 +115,7 @@ class CI_DB_sqlite_result extends CI_DB_result {
* this internally before fetching results to make sure the
* result set starts at zero
*
+ * @param int $n = 0
* @return bool
*/
protected function _data_seek($n = 0)
diff --git a/system/database/drivers/sqlite3/sqlite3_driver.php b/system/database/drivers/sqlite3/sqlite3_driver.php
index cc35d319f..22c72b9b8 100644
--- a/system/database/drivers/sqlite3/sqlite3_driver.php
+++ b/system/database/drivers/sqlite3/sqlite3_driver.php
@@ -46,10 +46,6 @@ class CI_DB_sqlite3_driver extends CI_DB {
// The character used for escaping
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = ' ESCAPE \'%s\' ';
- protected $_like_escape_chr = '!';
-
protected $_random_keyword = ' RANDOM()';
/**
@@ -107,13 +103,12 @@ class CI_DB_sqlite3_driver extends CI_DB {
/**
* Execute the query
*
- * @param string an SQL query
+ * @todo Implement use of SQLite3::querySingle(), if needed
+ * @param string $sql
* @return mixed SQLite3Result object or bool
*/
protected function _execute($sql)
{
- // TODO: Implement use of SQLite3::querySingle(), if needed
-
return $this->is_write_type($sql)
? $this->conn_id->exec($sql)
: $this->conn_id->query($sql);
@@ -124,6 +119,7 @@ class CI_DB_sqlite3_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode = FALSE
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -288,25 +284,16 @@ class CI_DB_sqlite3_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * The error message string
+ * Error
*
- * @return string
- */
- protected function _error_message()
- {
- return $this->conn_id->lastErrorMsg();
- }
-
- // --------------------------------------------------------------------
-
- /**
- * The error message number
+ * Returns an array containing code and message of the last
+ * database error that has occured.
*
- * @return int
+ * @return array
*/
- protected function _error_number()
+ public function error()
{
- return $this->conn_id->lastErrorCode();
+ return array('code' => $this->conn_id->lastErrorCode(), 'message' => $this->conn_id->lastErrorMsg());
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/sqlite3/sqlite3_result.php b/system/database/drivers/sqlite3/sqlite3_result.php
index 117fb3ce8..35aecda36 100644
--- a/system/database/drivers/sqlite3/sqlite3_result.php
+++ b/system/database/drivers/sqlite3/sqlite3_result.php
@@ -167,6 +167,7 @@ class CI_DB_sqlite3_result extends CI_DB_result {
* this internally before fetching results to make sure the
* result set starts at zero
*
+ * @param $n = 0 (ignored)
* @return array
*/
protected function _data_seek($n = 0)
diff --git a/system/database/drivers/sqlsrv/sqlsrv_driver.php b/system/database/drivers/sqlsrv/sqlsrv_driver.php
index 8bd18bd76..32f1a59d6 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_driver.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_driver.php
@@ -45,10 +45,6 @@ class CI_DB_sqlsrv_driver extends CI_DB {
// The character used for escaping
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
-
protected $_random_keyword = ' NEWID()';
// SQLSRV-specific properties
@@ -57,19 +53,21 @@ class CI_DB_sqlsrv_driver extends CI_DB {
/**
* Non-persistent database connection
*
+ * @param bool $pooling = FALSE
* @return resource
*/
public function db_connect($pooling = FALSE)
{
- // Check for a UTF-8 charset being passed as CI's default 'utf8'.
- $character_set = (0 === strcasecmp('utf8', $this->char_set)) ? 'UTF-8' : $this->char_set;
+ $charset = in_array(strtolower($this->char_set), array('utf-8', 'utf8'), TRUE)
+ ? 'UTF-8' : SQLSRV_ENC_CHAR;
$connection = array(
'UID' => empty($this->username) ? '' : $this->username,
'PWD' => empty($this->password) ? '' : $this->password,
'Database' => $this->database,
- 'ConnectionPooling' => $pooling ? 1 : 0,
- 'CharacterSet' => $character_set,
+ 'ConnectionPooling' => ($pooling === TRUE) ? 1 : 0,
+ 'CharacterSet' => $charset,
+ 'Encrypt' => ($this->encrypt === TRUE) ? 1 : 0,
'ReturnDatesAsStrings' => 1
);
@@ -147,6 +145,7 @@ class CI_DB_sqlsrv_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode = FALSE
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -225,7 +224,7 @@ class CI_DB_sqlsrv_driver extends CI_DB {
*/
public function affected_rows()
{
- return sqlrv_rows_affected($this->result_id);
+ return sqlsrv_rows_affected($this->result_id);
}
// --------------------------------------------------------------------
@@ -362,49 +361,19 @@ class CI_DB_sqlsrv_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -433,23 +402,16 @@ class CI_DB_sqlsrv_driver extends CI_DB {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
+ if ($this->qb_limit)
+ {
+ return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete';
+ }
- return ($limit)
- ? 'WITH ci_delete AS (SELECT TOP '.$limit.' * FROM '.$table.$conditions.') DELETE FROM ci_delete'
- : 'DELETE FROM '.$table.$conditions;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -460,32 +422,49 @@ class CI_DB_sqlsrv_driver extends CI_DB {
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
// As of SQL Server 2012 (11.0.*) OFFSET is supported
if (version_compare($this->version(), '11', '>='))
{
- return $sql.' OFFSET '.(int) $offset.' ROWS FETCH NEXT '.(int) $limit.' ROWS ONLY';
+ return $sql.' OFFSET '.(int) $this->qb_offset.' ROWS FETCH NEXT '.$this->qb_limit.' ROWS ONLY';
}
- $limit = $offset + $limit;
+ $limit = $this->qb_offset + $this->qb_limit;
// An ORDER BY clause is required for ROW_NUMBER() to work
- if ($offset && ! empty($this->qb_orderby))
+ if ($this->qb_offset && ! empty($this->qb_orderby))
{
- $orderby = 'ORDER BY '.implode(', ', $this->qb_orderby);
+ $orderby = $this->_compile_order_by();
// We have to strip the ORDER BY clause
- $sql = trim(substr($sql, 0, strrpos($sql, 'ORDER BY '.$orderby)));
-
- return 'SELECT '.(count($this->qb_select) === 0 ? '*' : implode(', ', $this->qb_select))." FROM (\n"
- .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.$orderby.') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
- ."\n) ".$this->escape_identifiers('CI_subquery')
- ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.((int) $offset + 1).' AND '.$limit;
+ $sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
+
+ // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results
+ if (count($this->qb_select) === 0)
+ {
+ $select = '*'; // Inevitable
+ }
+ else
+ {
+ // Use only field names and their aliases, everything else is out of our scope.
+ $select = array();
+ $field_regexp = ($this->_quoted_identifier)
+ ? '("[^\"]+")' : '(\[[^\]]+\])';
+ for ($i = 0, $c = count($this->qb_select); $i < $c; $i++)
+ {
+ $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m)
+ ? $m[1] : $this->qb_select[$i];
+ }
+ $select = implode(', ', $select);
+ }
+
+ return 'SELECT '.$select." FROM (\n\n"
+ .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+ ."\n\n) ".$this->escape_identifiers('CI_subquery')
+ ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
}
return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
diff --git a/system/helpers/captcha_helper.php b/system/helpers/captcha_helper.php
index a4383c9d3..3aac14db8 100644
--- a/system/helpers/captcha_helper.php
+++ b/system/helpers/captcha_helper.php
@@ -80,8 +80,7 @@ if ( ! function_exists('create_captcha'))
$current_dir = @opendir($img_path);
while ($filename = @readdir($current_dir))
{
- if ($filename !== '.' && $filename !== '..' && $filename !== 'index.html'
- && (str_replace('.jpg', '', $filename) + $expiration) < $now)
+ if (substr($filename, -4) === '.jpg' && (str_replace('.jpg', '', $filename) + $expiration) < $now)
{
@unlink($img_path.$filename);
}
diff --git a/system/helpers/date_helper.php b/system/helpers/date_helper.php
index a45b3d7ac..51b2b76db 100644
--- a/system/helpers/date_helper.php
+++ b/system/helpers/date_helper.php
@@ -575,22 +575,7 @@ if ( ! function_exists('timezone_menu'))
$menu .= ' class="'.$class.'"';
}
- // Generate a string from the attributes submitted, if any
- if (is_array($attributes))
- {
- $atts = '';
- foreach ($attributes as $key => $val)
- {
- $atts .= ' '.$key.'="'.$val.'"';
- }
- $attributes = $atts;
- }
- elseif (is_string($attributes) && strlen($attributes) > 0)
- {
- $attributes = ' '.$attributes;
- }
-
- $menu .= $attributes.">\n";
+ $menu .= _stringify_attributes($attributes).">\n";
foreach (timezones() as $key => $val)
{
@@ -672,5 +657,136 @@ if ( ! function_exists('timezones'))
}
}
+// ------------------------------------------------------------------------
+
+if ( ! function_exists('date_range'))
+{
+ /**
+ * Date range
+ *
+ * Returns a list of dates within a specified period.
+ *
+ * @param int unix_start UNIX timestamp of period start date
+ * @param int unix_end|days UNIX timestamp of period end date
+ * or interval in days.
+ * @param mixed is_unix Specifies whether the second parameter
+ * is a UNIX timestamp or a day interval
+ * - TRUE or 'unix' for a timestamp
+ * - FALSE or 'days' for an interval
+ * @param string date_format Output date format, same as in date()
+ * @return array
+ */
+ function date_range($unix_start = '', $mixed = '', $is_unix = TRUE, $format = 'Y-m-d')
+ {
+ if ($unix_start == '' OR $mixed == '' OR $format == '')
+ {
+ return FALSE;
+ }
+
+ $is_unix = ! ( ! $is_unix OR $is_unix === 'days');
+
+ // Validate input and try strtotime() on invalid timestamps/intervals, just in case
+ if ( ( ! preg_match('/^[0-9]+$/', $unix_start) && ($unix_start = @strtotime($unix_time)) === FALSE)
+ OR ( ! preg_match('/^[0-9]+$/', $mixed) && ($is_unix === FALSE OR ($mixed = @strtotime($mixed)) === FALSE))
+ OR ($is_unix === TRUE && $mixed < $unix_start))
+ {
+ return FALSE;
+ }
+
+ if ($is_unix && ($unix_start == $mixed OR date($format, $unix_start) === date($format, $mixed)))
+ {
+ return array($start_date);
+ }
+
+ $range = array();
+
+ /* NOTE: Even though the DateTime object has many useful features, it appears that
+ * it doesn't always handle properly timezones, when timestamps are passed
+ * directly to its constructor. Neither of the following gave proper results:
+ *
+ * new DateTime('<timestamp>')
+ * new DateTime('<timestamp>', '<timezone>')
+ *
+ * --- available in PHP 5.3:
+ *
+ * DateTime::createFromFormat('<format>', '<timestamp>')
+ * DateTime::createFromFormat('<format>', '<timestamp>', '<timezone')
+ *
+ * ... so we'll have to set the timestamp after the object is instantiated.
+ * Furthermore, in PHP 5.3 we can use DateTime::setTimestamp() to do that and
+ * given that we have UNIX timestamps - we should use it.
+ */
+ $from = new DateTime();
+
+ if (is_php('5.3'))
+ {
+ $from->setTimestamp($unix_start);
+ if ($is_unix)
+ {
+ $arg = new DateTime();
+ $arg->setTimestamp($mixed);
+ }
+ else
+ {
+ $arg = (int) $mixed;
+ }
+
+ $period = new DatePeriod($from, new DateInterval('P1D'), $arg);
+ foreach ($period as $date)
+ {
+ $range[] = $date->format($format);
+ }
+
+ /* If a period end date was passed to the DatePeriod constructor, it might not
+ * be in our results. Not sure if this is a bug or it's just possible because
+ * the end date might actually be less than 24 hours away from the previously
+ * generated DateTime object, but either way - we have to append it manually.
+ */
+ if ( ! is_int($arg) && $range[count($range) - 1] !== $arg->format($format))
+ {
+ $range[] = $arg->format($format);
+ }
+
+ return $range;
+ }
+
+ $from->setDate(date('Y', $unix_start), date('n', $unix_start), date('j', $unix_start));
+ $from->setTime(date('G', $unix_start), date('i', $unix_start), date('s', $unix_start));
+ if ($is_unix)
+ {
+ $arg = new DateTime();
+ $arg->setDate(date('Y', $mixed), date('n', $mixed), date('j', $mixed));
+ $arg->setTime(date('G', $mixed), date('i', $mixed), date('s', $mixed));
+ }
+ else
+ {
+ $arg = (int) $mixed;
+ }
+ $range[] = $from->format($format);
+
+ if (is_int($arg)) // Day intervals
+ {
+ do
+ {
+ $from->modify('+1 day');
+ $range[] = $from->format($format);
+ }
+ while (--$arg > 0);
+ }
+ else // end date UNIX timestamp
+ {
+ for ($from->modify('+1 day'), $end_check = $arg->format('Ymd'); $from->format('Ymd') < $end_check; $from->modify('+1 day'))
+ {
+ $range[] = $from->format($format);
+ }
+
+ // Our loop only appended dates prior to our end date
+ $range[] = $arg->format($format);
+ }
+
+ return $range;
+ }
+}
+
/* End of file date_helper.php */
/* Location: ./system/helpers/date_helper.php */ \ No newline at end of file
diff --git a/system/helpers/directory_helper.php b/system/helpers/directory_helper.php
index e7d3b5e8a..7d6b6770e 100644
--- a/system/helpers/directory_helper.php
+++ b/system/helpers/directory_helper.php
@@ -62,7 +62,7 @@ if ( ! function_exists('directory_map'))
while (FALSE !== ($file = readdir($fp)))
{
// Remove '.', '..', and hidden files [optional]
- if ( ! trim($file, '.') OR ($hidden === FALSE && $file[0] === '.'))
+ if ($file === '.' OR $file === '..' OR ($hidden === FALSE && $file[0] === '.'))
{
continue;
}
diff --git a/system/helpers/download_helper.php b/system/helpers/download_helper.php
index 09c4de578..0232adfe4 100644
--- a/system/helpers/download_helper.php
+++ b/system/helpers/download_helper.php
@@ -95,7 +95,10 @@ if ( ! function_exists('force_download'))
}
// Clean output buffer
- ob_clean();
+ if (ob_get_level() !== 0)
+ {
+ ob_clean();
+ }
// Generate the server headers
header('Content-Type: '.$mime);
diff --git a/system/helpers/file_helper.php b/system/helpers/file_helper.php
index 3834d4895..441345b05 100644
--- a/system/helpers/file_helper.php
+++ b/system/helpers/file_helper.php
@@ -109,7 +109,7 @@ if ( ! function_exists('delete_files'))
function delete_files($path, $del_dir = FALSE, $level = 0, $htdocs = FALSE)
{
// Trim the trailing slash
- $path = rtrim($path, DIRECTORY_SEPARATOR);
+ $path = rtrim($path, '/\\');
if ( ! $current_dir = @opendir($path))
{
@@ -124,7 +124,7 @@ if ( ! function_exists('delete_files'))
{
delete_files($path.DIRECTORY_SEPARATOR.$filename, $del_dir, $level + 1, $htdocs);
}
- elseif ($htdocs === TRUE && ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename))
+ elseif ($htdocs !== TRUE OR ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename))
{
@unlink($path.DIRECTORY_SEPARATOR.$filename);
}
diff --git a/system/helpers/html_helper.php b/system/helpers/html_helper.php
index 68ce70248..2372e8174 100644
--- a/system/helpers/html_helper.php
+++ b/system/helpers/html_helper.php
@@ -51,7 +51,7 @@ if ( ! function_exists('heading'))
*/
function heading($data = '', $h = '1', $attributes = '')
{
- return '<h'.$h.($attributes !== '' ? ' ' : '').$attributes.'>'.$data.'</h'.$h.'>';
+ return '<h'.$h._stringify_attributes($attributes).'>'.$data.'</h'.$h.'>';
}
}
@@ -119,23 +119,8 @@ if ( ! function_exists('_list'))
// Set the indentation based on the depth
$out = str_repeat(' ', $depth);
- // Were any attributes submitted? If so generate a string
- if (is_array($attributes))
- {
- $atts = '';
- foreach ($attributes as $key => $val)
- {
- $atts .= ' '.$key.'="'.$val.'"';
- }
- $attributes = $atts;
- }
- elseif (is_string($attributes) && strlen($attributes) > 0)
- {
- $attributes = ' '.$attributes;
- }
-
// Write the opening list tag
- $out .= '<'.$type.$attributes.">\n";
+ $out .= '<'.$type._stringify_attributes($attributes).">\n";
// Cycle through the list elements. If an array is
// encountered we will recursively call _list()
@@ -191,9 +176,10 @@ if ( ! function_exists('img'))
*
* @param mixed
* @param bool
+ * @param mixed
* @return string
*/
- function img($src = '', $index_page = FALSE)
+ function img($src = '', $index_page = FALSE, $attributes = '')
{
if ( ! is_array($src) )
{
@@ -229,7 +215,7 @@ if ( ! function_exists('img'))
}
}
- return $img.'/>';
+ return $img._stringify_attributes($attributes).' />';
}
}
@@ -242,9 +228,9 @@ if ( ! function_exists('doctype'))
*
* Generates a page document type declaration
*
- * Valid options are xhtml-11, xhtml-strict, xhtml-trans, xhtml-frame,
- * html4-strict, html4-trans, and html4-frame. Values are saved in the
- * doctypes config file.
+ * Examples of valid options: html5, xhtml-11, xhtml-strict, xhtml-trans,
+ * xhtml-frame, html4-strict, html4-trans, and html4-frame.
+ * All values are saved in the doctypes config file.
*
* @param string type The doctype to be generated
* @return string
diff --git a/system/helpers/text_helper.php b/system/helpers/text_helper.php
index 8a1f01b51..016a36c57 100644
--- a/system/helpers/text_helper.php
+++ b/system/helpers/text_helper.php
@@ -89,7 +89,8 @@ if ( ! function_exists('character_limiter'))
return $str;
}
- $str = preg_replace('/\s+/', ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str));
+ // a bit complicated, but faster than preg_replace with \s+
+ $str = preg_replace('/ {2,}/', ' ', str_replace(array("\r", "\n", "\t", "\x0B", "\x0C"), ' ', $str));
if (strlen($str) <= $n)
{
@@ -389,19 +390,19 @@ if ( ! function_exists('convert_accented_characters'))
// ------------------------------------------------------------------------
-/**
- * Word Wrap
- *
- * Wraps text at the specified character. Maintains the integrity of words.
- * Anything placed between {unwrap}{/unwrap} will not be word wrapped, nor
- * will URLs.
- *
- * @param string the text string
- * @param int the number of characters to wrap at
- * @return string
- */
if ( ! function_exists('word_wrap'))
{
+ /**
+ * Word Wrap
+ *
+ * Wraps text at the specified character. Maintains the integrity of words.
+ * Anything placed between {unwrap}{/unwrap} will not be word wrapped, nor
+ * will URLs.
+ *
+ * @param string $str the text string
+ * @param int $charlim = 76 the number of characters to wrap at
+ * @return string
+ */
function word_wrap($str, $charlim = 76)
{
// Set the character limit
diff --git a/system/helpers/typography_helper.php b/system/helpers/typography_helper.php
index af9d16a89..96bedd026 100644
--- a/system/helpers/typography_helper.php
+++ b/system/helpers/typography_helper.php
@@ -60,16 +60,15 @@ if ( ! function_exists('auto_typography'))
/**
* Auto Typography Wrapper Function
*
- * @param string
- * @param bool whether to allow javascript event handlers
- * @param bool whether to reduce multiple instances of double newlines to two
+ * @param string $str
+ * @param bool $reduce_linebreaks = FALSE whether to reduce multiple instances of double newlines to two
* @return string
*/
- function auto_typography($str, $strip_js_event_handlers = TRUE, $reduce_linebreaks = FALSE)
+ function auto_typography($str, $reduce_linebreaks = FALSE)
{
$CI =& get_instance();
$CI->load->library('typography');
- return $CI->typography->auto_typography($str, $strip_js_event_handlers, $reduce_linebreaks);
+ return $CI->typography->auto_typography($str, $reduce_linebreaks);
}
}
diff --git a/system/helpers/url_helper.php b/system/helpers/url_helper.php
index 39e6343a6..de5bdec31 100644
--- a/system/helpers/url_helper.php
+++ b/system/helpers/url_helper.php
@@ -165,7 +165,7 @@ if ( ! function_exists('anchor'))
if ($attributes !== '')
{
- $attributes = _parse_attributes($attributes);
+ $attributes = _stringify_attributes($attributes);
}
return '<a href="'.$site_url.'"'.$attributes.'>'.$title.'</a>';
@@ -221,10 +221,10 @@ if ( ! function_exists('anchor_popup'))
unset($attributes[$key]);
}
- $attributes = empty($attributes) ? '' : _parse_attributes($attributes);
+ $attributes = _stringify_attributes($attributes);
return '<a href="'.$site_url
- .'" onclick="window.open(\''.$site_url."', '".$window_name."', '"._parse_attributes($atts, TRUE)."'); return false;\""
+ .'" onclick="window.open(\''.$site_url."', '".$window_name."', '"._stringify_attributes($atts, TRUE)."'); return false;\""
.$attributes.'>'.$title.'</a>';
}
}
@@ -250,7 +250,7 @@ if ( ! function_exists('mailto'))
$title = $email;
}
- return '<a href="mailto:'.$email.'"'._parse_attributes($attributes).'>'.$title.'</a>';
+ return '<a href="mailto:'.$email.'"'._stringify_attributes($attributes).'>'.$title.'</a>';
}
}
@@ -388,40 +388,43 @@ if ( ! function_exists('auto_link'))
for ($i = 0, $c = count($matches[0]); $i < $c; $i++)
{
- if (preg_match('|\.$|', $matches[6][$i]))
+ if (preg_match('/(\.|\,)$/i', $matches[6][$i], $m))
{
- $period = '.';
+ $punct = $m[1];
$matches[6][$i] = substr($matches[6][$i], 0, -1);
}
else
{
- $period = '';
+ $punct = '';
}
$str = str_replace($matches[0][$i],
$matches[1][$i].'<a href="http'.$matches[4][$i].'://'
.$matches[5][$i].$matches[6][$i].'"'.$pop.'>http'
.$matches[4][$i].'://'.$matches[5][$i]
- .$matches[6][$i].'</a>'.$period,
+ .$matches[6][$i].'</a>'.$punct,
$str);
}
}
- if ($type !== 'url' && preg_match_all('/([a-zA-Z0-9_\.\-\+]+)@([a-zA-Z0-9\-]+)\.([a-zA-Z0-9\-\.]*)/i', $str, $matches))
+ if ($type !== 'url' && preg_match_all('/([a-zA-Z0-9_\.\-\+]+)@([a-zA-Z0-9\-]+)\.([a-zA-Z0-9\-\.]+)/i', $str, $matches))
{
for ($i = 0, $c = count($matches); $i < $c; $i++)
{
- if (preg_match('|\.$|', $matches[3][$i]))
+ if (preg_match('/(\.|\,)$/i', $matches[3][$i], $m))
{
- $period = '.';
+ $punct = $m[1];
$matches[3][$i] = substr($matches[3][$i], 0, -1);
}
else
{
- $period = '';
+ $punct = '';
}
- $str = str_replace($matches[0][$i], safe_mailto($matches[1][$i].'@'.$matches[2][$i].'.'.$matches[3][$i]).$period, $str);
+ if (filter_var(($m = $matches[1][$i].'@'.$matches[2][$i].'.'.$matches[3][$i]), FILTER_VALIDATE_EMAIL) !== FALSE)
+ {
+ $str = str_replace($matches[0][$i], safe_mailto($m).$punct, $str);
+ }
}
}
@@ -534,7 +537,7 @@ if ( ! function_exists('redirect'))
}
// IIS environment likely? Use 'refresh' for better compatibility
- if (DIRECTORY_SEPARATOR !== '/' && $method === 'auto')
+ if ($method === 'auto' && isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== FALSE)
{
$method = 'refresh';
}
@@ -560,47 +563,5 @@ if ( ! function_exists('redirect'))
}
}
-// ------------------------------------------------------------------------
-
-if ( ! function_exists('_parse_attributes'))
-{
- /**
- * Parse out the attributes
- *
- * Some of the functions use this
- *
- * @param array
- * @param bool
- * @return string
- */
- function _parse_attributes($attributes, $javascript = FALSE)
- {
- if (is_string($attributes))
- {
- return ($attributes !== '') ? ' '.$attributes : '';
- }
-
- $att = '';
- foreach ($attributes as $key => $val)
- {
- if ($javascript === TRUE)
- {
- $att .= $key.'='.$val.',';
- }
- else
- {
- $att .= ' '.$key.'="'.$val.'"';
- }
- }
-
- if ($javascript === TRUE && $att !== '')
- {
- return substr($att, 0, -1);
- }
-
- return $att;
- }
-}
-
/* End of file url_helper.php */
/* Location: ./system/helpers/url_helper.php */ \ No newline at end of file
diff --git a/system/language/english/date_lang.php b/system/language/english/date_lang.php
index 229d33d2e..6683e4c69 100644
--- a/system/language/english/date_lang.php
+++ b/system/language/english/date_lang.php
@@ -25,20 +25,20 @@
* @filesource
*/
-$lang['date_year'] = "Year";
-$lang['date_years'] = "Years";
-$lang['date_month'] = "Month";
-$lang['date_months'] = "Months";
-$lang['date_week'] = "Week";
-$lang['date_weeks'] = "Weeks";
-$lang['date_day'] = "Day";
-$lang['date_days'] = "Days";
-$lang['date_hour'] = "Hour";
-$lang['date_hours'] = "Hours";
-$lang['date_minute'] = "Minute";
-$lang['date_minutes'] = "Minutes";
-$lang['date_second'] = "Second";
-$lang['date_seconds'] = "Seconds";
+$lang['date_year'] = 'Year';
+$lang['date_years'] = 'Years';
+$lang['date_month'] = 'Month';
+$lang['date_months'] = 'Months';
+$lang['date_week'] = 'Week';
+$lang['date_weeks'] = 'Weeks';
+$lang['date_day'] = 'Day';
+$lang['date_days'] = 'Days';
+$lang['date_hour'] = 'Hour';
+$lang['date_hours'] = 'Hours';
+$lang['date_minute'] = 'Minute';
+$lang['date_minutes'] = 'Minutes';
+$lang['date_second'] = 'Second';
+$lang['date_seconds'] = 'Seconds';
$lang['UM12'] = '(UTC -12:00) Baker/Howland Island';
$lang['UM11'] = '(UTC -11:00) Niue';
diff --git a/system/language/english/form_validation_lang.php b/system/language/english/form_validation_lang.php
index 021776161..6ff0cc2f4 100644
--- a/system/language/english/form_validation_lang.php
+++ b/system/language/english/form_validation_lang.php
@@ -42,9 +42,10 @@ $lang['is_numeric'] = 'The %s field must contain only numeric characters.';
$lang['integer'] = 'The %s field must contain an integer.';
$lang['regex_match'] = 'The %s field is not in the correct format.';
$lang['matches'] = 'The %s field does not match the %s field.';
+$lang['differs'] = 'The %s field must differ from the %s field.';
$lang['is_unique'] = 'The %s field must contain a unique value.';
-$lang['is_natural'] = 'The %s field must contain only positive numbers.';
-$lang['is_natural_no_zero'] = 'The %s field must contain a number greater than zero.';
+$lang['is_natural'] = 'The %s field must only contain digits.';
+$lang['is_natural_no_zero'] = 'The %s field must only contain digits and must be greater than zero.';
$lang['decimal'] = 'The %s field must contain a decimal number.';
$lang['less_than'] = 'The %s field must contain a number less than %s.';
$lang['less_than_equal_to'] = 'The %s field must contain a number less than or equal to %s.';
diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php
index d67ee2549..5d642b982 100644
--- a/system/libraries/Driver.php
+++ b/system/libraries/Driver.php
@@ -54,14 +54,30 @@ class CI_Driver_Library {
protected $lib_name;
/**
+ * Get magic method
+ *
* The first time a child is used it won't exist, so we instantiate it
* subsequents calls will go straight to the proper child.
*
- * @param mixed $child
- * @return mixed
+ * @param string Child class name
+ * @return object Child class
*/
public function __get($child)
{
+ // Try to load the driver
+ return $this->load_driver($child);
+ }
+
+ /**
+ * Load driver
+ *
+ * Separate load_driver call to support explicit driver load by library or user
+ *
+ * @param string Child class name
+ * @return object Child class
+ */
+ public function load_driver($child)
+ {
if ( ! isset($this->lib_name))
{
$this->lib_name = get_class($this);
@@ -156,7 +172,8 @@ class CI_Driver {
/**
* Array of methods and properties for the parent class(es)
*
- * @var array
+ * @static
+ * @var array
*/
protected static $_reflections = array();
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index fdb9be4da..83b442f58 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -94,10 +94,13 @@ class CI_Email {
*
* The constructor can be passed an array of config values
*
+ * @param array $config = array()
* @return void
*/
public function __construct($config = array())
{
+ $this->charset = config_item('charset');
+
if (count($config) > 0)
{
$this->initialize($config);
@@ -108,6 +111,8 @@ class CI_Email {
$this->_safe_mode = (bool) @ini_get('safe_mode');
}
+ $this->charset = strtoupper($this->charset);
+
log_message('debug', 'Email Class Initialized');
}
@@ -184,11 +189,12 @@ class CI_Email {
/**
* Set FROM
*
- * @param string
- * @param string
+ * @param string $from
+ * @param string $name
+ * @param string $return_path = NULL Return-Path
* @return object
*/
- public function from($from, $name = '')
+ public function from($from, $name = '', $return_path = NULL)
{
if (preg_match('/\<(.*)\>/', $from, $match))
{
@@ -198,6 +204,10 @@ class CI_Email {
if ($this->validate)
{
$this->validate_email($this->_str_to_array($from));
+ if ($return_path)
+ {
+ $this->validate_email($this->_str_to_array($return_path));
+ }
}
// prepare the display name
@@ -211,12 +221,14 @@ class CI_Email {
}
else
{
- $name = $this->_prep_q_encoding($name, TRUE);
+ $name = $this->_prep_q_encoding($name);
}
}
$this->set_header('From', $name.' <'.$from.'>');
- $this->set_header('Return-Path', '<'.$from.'>');
+
+ isset($return_path) OR $return_path = $from;
+ $this->set_header('Return-Path', '<'.$return_path.'>');
return $this;
}
@@ -281,16 +293,7 @@ class CI_Email {
$this->set_header('To', implode(', ', $to));
}
- switch ($this->_get_protocol())
- {
- case 'smtp':
- $this->_recipients = $to;
- break;
- case 'sendmail':
- case 'mail':
- $this->_recipients = implode(', ', $to);
- break;
- }
+ $this->_recipients = $to;
return $this;
}
@@ -404,7 +407,10 @@ class CI_Email {
/**
* Assign file attachments
*
- * @param string
+ * @param string $filename
+ * @param string $disposition = 'attachment'
+ * @param string $newname = NULL
+ * @param string $mime = ''
* @return object
*/
public function attach($filename, $disposition = '', $newname = NULL, $mime = '')
@@ -741,8 +747,8 @@ class CI_Email {
/**
* Build alternative plain text message
*
- * This public function provides the raw message for use
- * in plain-text headers of HTML-formatted emails.
+ * Provides the raw message for use in plain-text headers of
+ * HTML-formatted emails.
* If the user hasn't specified his own alternative message
* it creates one by stripping the HTML
*
@@ -750,9 +756,11 @@ class CI_Email {
*/
protected function _get_alt_message()
{
- if ($this->alt_message !== '')
+ if ( ! empty($this->alt_message))
{
- return $this->word_wrap($this->alt_message, '76');
+ return ($this->wordwrap)
+ ? $this->word_wrap($this->alt_message, 76)
+ : $this->alt_message;
}
$body = preg_match('/\<body.*?\>(.*)\<\/body\>/si', $this->_body, $match) ? $match[1] : $this->_body;
@@ -763,7 +771,9 @@ class CI_Email {
$body = str_replace(str_repeat("\n", $i), "\n\n", $body);
}
- return $this->word_wrap($body, 76);
+ return ($this->wordwrap)
+ ? $this->word_wrap($body, 76)
+ : $body;
}
// --------------------------------------------------------------------
@@ -772,15 +782,15 @@ class CI_Email {
* Word Wrap
*
* @param string
- * @param int
+ * @param int line-length limit
* @return string
*/
- public function word_wrap($str, $charlim = '')
+ public function word_wrap($str, $charlim = NULL)
{
- // Se the character limit
- if ($charlim === '')
+ // Set the character limit, if not already present
+ if (empty($charlim))
{
- $charlim = ($this->wrapchars === '') ? 76 : $this->wrapchars;
+ $charlim = empty($this->wrapchars) ? 76 : $this->wrapchars;
}
// Reduce multiple spaces
@@ -971,7 +981,6 @@ class CI_Email {
$this->_finalbody = $body.$this->_prep_quoted_printable($this->_body).$this->newline.$this->newline;
-
if ($this->_get_protocol() === 'mail')
{
$this->_header_str .= $hdr;
@@ -1091,17 +1100,28 @@ class CI_Email {
* Refer to RFC 2045 http://www.ietf.org/rfc/rfc2045.txt
*
* @param string
- * @param int
* @return string
*/
- protected function _prep_quoted_printable($str, $charlim = '')
+ protected function _prep_quoted_printable($str)
{
- // Set the character limit
- // Don't allow over 76, as that will make servers and MUAs barf
- // all over quoted-printable data
- if ($charlim === '' OR $charlim > 76)
+ // We are intentionally wrapping so mail servers will encode characters
+ // properly and MUAs will behave, so {unwrap} must go!
+ $str = str_replace(array('{unwrap}', '{/unwrap}'), '', $str);
+
+ // RFC 2045 specifies CRLF as "\r\n".
+ // However, many developers choose to override that and violate
+ // the RFC rules due to (apparently) a bug in MS Exchange,
+ // which only works with "\n".
+ if ($this->crlf === "\r\n")
{
- $charlim = 76;
+ if (is_php('5.3'))
+ {
+ return quoted_printable_encode($str);
+ }
+ elseif (function_exists('imap_8bit'))
+ {
+ return imap_8bit($str);
+ }
}
// Reduce multiple spaces & remove nulls
@@ -1113,10 +1133,6 @@ class CI_Email {
$str = str_replace(array("\r\n", "\r"), "\n", $str);
}
- // We are intentionally wrapping so mail servers will encode characters
- // properly and MUAs will behave, so {unwrap} must go!
- $str = str_replace(array('{unwrap}', '{/unwrap}'), '', $str);
-
$escape = '=';
$output = '';
@@ -1146,7 +1162,7 @@ class CI_Email {
// If we're at the character limit, add the line to the output,
// reset our temp variable, and keep on chuggin'
- if ((strlen($temp) + strlen($char)) >= $charlim)
+ if ((strlen($temp) + strlen($char)) >= 76)
{
$output .= $temp.$escape.$this->crlf;
$temp = '';
@@ -1169,66 +1185,75 @@ class CI_Email {
/**
* Prep Q Encoding
*
- * Performs "Q Encoding" on a string for use in email headers. It's related
- * but not identical to quoted-printable, so it has its own method
+ * Performs "Q Encoding" on a string for use in email headers.
+ * It's related but not identical to quoted-printable, so it has its
+ * own method.
*
* @param string
- * @param bool set to TRUE for processing From: headers
* @return string
*/
- protected function _prep_q_encoding($str, $from = FALSE)
+ protected function _prep_q_encoding($str)
{
- $str = str_replace(array("\r", "\n"), array('', ''), $str);
-
- // Line length must not exceed 76 characters, so we adjust for
- // a space, 7 extra characters =??Q??=, and the charset that we will add to each line
- $limit = 75 - 7 - strlen($this->charset);
+ $str = str_replace(array("\r", "\n"), '', $str);
- // these special characters must be converted too
- $convert = array('_', '=', '?');
-
- if ($from === TRUE)
+ if ($this->charset === 'UTF-8')
{
- $convert[] = ',';
- $convert[] = ';';
+ if (MB_ENABLED === TRUE)
+ {
+ return mb_encode_mimeheader($str, $this->charset, 'Q', $this->crlf);
+ }
+ elseif (extension_loaded('iconv'))
+ {
+ $output = @iconv_mime_encode('', $str,
+ array(
+ 'scheme' => 'Q',
+ 'line-length' => 76,
+ 'input-charset' => $this->charset,
+ 'output-charset' => $this->charset,
+ 'line-break-chars' => $this->crlf
+ )
+ );
+
+ // There are reports that iconv_mime_encode() might fail and return FALSE
+ if ($output !== FALSE)
+ {
+ // iconv_mime_encode() will always put a header field name.
+ // We've passed it an empty one, but it still prepends our
+ // encoded string with ': ', so we need to strip it.
+ return substr($output, 2);
+ }
+
+ $chars = iconv_strlen($str, 'UTF-8');
+ }
}
- $output = '';
- $temp = '';
+ // We might already have this set for UTF-8
+ isset($chars) OR $chars = strlen($str);
- for ($i = 0, $length = strlen($str); $i < $length; $i++)
+ $output = '=?'.$this->charset.'?Q?';
+ for ($i = 0, $length = strlen($output), $iconv = extension_loaded('iconv'); $i < $chars; $i++)
{
- // Grab the next character
- $char = $str[$i];
- $ascii = ord($char);
-
- // convert ALL non-printable ASCII characters and our specials
- if ($ascii < 32 OR $ascii > 126 OR in_array($char, $convert))
- {
- $char = '='.dechex($ascii);
- }
+ $chr = ($this->charset === 'UTF-8' && $iconv === TRUE)
+ ? '='.implode('=', str_split(strtoupper(bin2hex(iconv_substr($str, $i, 1, $this->charset))), 2))
+ : '='.strtoupper(bin2hex($str[$i]));
- // handle regular spaces a bit more compactly than =20
- if ($ascii === 32)
+ // RFC 2045 sets a limit of 76 characters per line.
+ // We'll append ?= to the end of each line though.
+ if ($length + ($l = strlen($chr)) > 74)
{
- $char = '_';
+ $output .= '?='.$this->crlf // EOL
+ .' =?'.$this->charset.'?Q?'.$chr; // New line
+ $length = 6 + strlen($this->charset) + $l; // Reset the length for the new line
}
-
- // If we're at the character limit, add the line to the output,
- // reset our temp variable, and keep on chuggin'
- if ((strlen($temp) + strlen($char)) >= $limit)
+ else
{
- $output .= $temp.$this->crlf;
- $temp = '';
+ $output .= $chr;
+ $length += $l;
}
-
- // Add the character to our temporary line
- $temp .= $char;
}
- // wrap each line with the shebang, charset, and transfer encoding
- // the preceding space on successive lines is required for header "folding"
- return trim(preg_replace('/^(.*)$/m', ' =?'.$this->charset.'?Q?$1?=', $output.$temp));
+ // End the header
+ return $output.'?=';
}
// --------------------------------------------------------------------
@@ -1236,9 +1261,10 @@ class CI_Email {
/**
* Send Email
*
+ * @param bool $auto_clear = TRUE
* @return bool
*/
- public function send()
+ public function send($auto_clear = TRUE)
{
if ($this->_replyto_flag === FALSE)
{
@@ -1257,11 +1283,25 @@ class CI_Email {
if ($this->bcc_batch_mode && count($this->_bcc_array) > $this->bcc_batch_size)
{
- return $this->batch_bcc_send();
+ $result = $this->batch_bcc_send();
+
+ if ($result && $auto_clear)
+ {
+ $this->clear();
+ }
+
+ return $result;
}
$this->_build_message();
- return $this->_spool_email();
+ $result = $this->_spool_email();
+
+ if ($result && $auto_clear)
+ {
+ $this->clear();
+ }
+
+ return $result;
}
// --------------------------------------------------------------------
@@ -1334,6 +1374,7 @@ class CI_Email {
/**
* Strip line-breaks via callback
*
+ * @param string $matches
* @return string
*/
protected function _remove_nl_callback($matches)
@@ -1377,6 +1418,11 @@ class CI_Email {
*/
protected function _send_with_mail()
{
+ if (is_array($this->_recipients))
+ {
+ $this->_recipients = implode(', ', $this->_recipients);
+ }
+
if ($this->_safe_mode === TRUE)
{
return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str);
@@ -1385,7 +1431,7 @@ class CI_Email {
{
// most documentation of sendmail using the "-f" flag lacks a space after it, however
// we've encountered servers that seem to require it to be in place.
- return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, '-f '.$this->clean_email($this->_headers['From']));
+ return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, '-f '.$this->clean_email($this->_headers['Return-Path']));
}
}
@@ -1398,7 +1444,7 @@ class CI_Email {
*/
protected function _send_with_sendmail()
{
- $fp = @popen($this->mailpath.' -oi -f '.$this->clean_email($this->_headers['From']).' -t', 'w');
+ $fp = @popen($this->mailpath.' -oi -f '.$this->clean_email($this->_headers['From']).' -t'.' -r '.$this->clean_email($this->_headers['Return-Path']), 'w');
if ($fp === FALSE OR $fp === NULL)
{
@@ -1496,7 +1542,6 @@ class CI_Email {
/**
* SMTP Connect
*
- * @param string
* @return string
*/
protected function _smtp_connect()
@@ -1671,11 +1716,12 @@ class CI_Email {
/**
* Send SMTP data
*
+ * @param string $data
* @return bool
*/
protected function _send_data($data)
{
- if ( ! fwrite($this->_smtp_connect, $data . $this->newline))
+ if ( ! fwrite($this->_smtp_connect, $data.$this->newline))
{
$this->_set_error_message('lang:email_smtp_data_failure', $data);
return FALSE;
@@ -1723,47 +1769,6 @@ class CI_Email {
// --------------------------------------------------------------------
/**
- * Get IP
- *
- * @return string
- */
- protected function _get_ip()
- {
- if ($this->_IP !== FALSE)
- {
- return $this->_IP;
- }
-
- $cip = ( ! empty($_SERVER['HTTP_CLIENT_IP'])) ? $_SERVER['HTTP_CLIENT_IP'] : FALSE;
- $rip = ( ! empty($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : FALSE;
- if ($cip) $this->_IP = $cip;
- elseif ($rip) $this->_IP = $rip;
- else
- {
- $fip = ( ! empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : FALSE;
- if ($fip)
- {
- $this->_IP = $fip;
- }
- }
-
- if (strpos($this->_IP, ',') !== FALSE)
- {
- $x = explode(',', $this->_IP);
- $this->_IP = end($x);
- }
-
- if ( ! preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $this->_IP))
- {
- $this->_IP = '0.0.0.0';
- }
-
- return $this->_IP;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Get Debug Message
*
* @return string
@@ -1788,7 +1793,8 @@ class CI_Email {
/**
* Set Message
*
- * @param string
+ * @param string $msg
+ * @param string $val = ''
* @return void
*/
protected function _set_error_message($msg, $val = '')
diff --git a/system/libraries/Encrypt.php b/system/libraries/Encrypt.php
index 8ffd93aea..73ab8ca7d 100644
--- a/system/libraries/Encrypt.php
+++ b/system/libraries/Encrypt.php
@@ -165,7 +165,7 @@ class CI_Encrypt {
*/
public function decode($string, $key = '')
{
- if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
+ if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string) OR base64_encode(base64_decode($string)) !== $string)
{
return FALSE;
}
@@ -484,7 +484,7 @@ class CI_Encrypt {
*/
public function set_hash($type = 'sha1')
{
- $this->_hash_type = ($type !== 'sha1' && $type !== 'md5') ? 'sha1' : $type;
+ $this->_hash_type = in_array($type, hash_algos()) ? $type : 'sha1';
}
// --------------------------------------------------------------------
@@ -497,7 +497,7 @@ class CI_Encrypt {
*/
public function hash($str)
{
- return ($this->_hash_type === 'sha1') ? sha1($str) : md5($str);
+ return hash($this->_hash_type, $str);
}
}
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index b490a34ca..91f46b6de 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -134,12 +134,6 @@ class CI_Form_validation {
// Automatically load the form helper
$this->CI->load->helper('form');
- // Set the character encoding in MB.
- if (MB_ENABLED === TRUE)
- {
- mb_internal_encoding($this->CI->config->item('charset'));
- }
-
log_message('debug', 'Form Validation Class Initialized');
}
@@ -977,6 +971,20 @@ class CI_Form_validation {
// --------------------------------------------------------------------
/**
+ * Differs from another field
+ *
+ * @param string
+ * @param string field
+ * @return bool
+ */
+ public function differs($str, $field)
+ {
+ return ! (isset($this->_field_data[$field]) && $this->_field_data[$field]['postdata'] === $str);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Is Unique
*
* Check if the input value doesn't already exist
diff --git a/system/libraries/Ftp.php b/system/libraries/Ftp.php
index 76f5e151a..ae85fdf37 100644
--- a/system/libraries/Ftp.php
+++ b/system/libraries/Ftp.php
@@ -44,6 +44,12 @@ class CI_FTP {
public $debug = FALSE;
public $conn_id = FALSE;
+ /**
+ * Constructor
+ *
+ * @param array $config = array()
+ * @return void
+ */
public function __construct($config = array())
{
if (count($config) > 0)
@@ -474,6 +480,7 @@ class CI_FTP {
/**
* FTP List files in the specified directory
*
+ * @param string $path = '.'
* @return array
*/
public function list_files($path = '.')
diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php
index 899b995d4..ef4187847 100644
--- a/system/libraries/Image_lib.php
+++ b/system/libraries/Image_lib.php
@@ -1320,6 +1320,13 @@ class CI_Image_lib {
imagestring($src_img, $this->wm_font_size, $x_shad, $y_shad, $this->wm_text, $drp_color);
imagestring($src_img, $this->wm_font_size, $x_axis, $y_axis, $this->wm_text, $txt_color);
}
+
+ // We can preserve transparency for PNG images
+ if ($this->image_type === 3)
+ {
+ imagealphablending($src_img, FALSE);
+ imagesavealpha($src_img, TRUE);
+ }
}
// Output the final image
diff --git a/system/libraries/Javascript.php b/system/libraries/Javascript.php
index 5c8b09217..60309cd83 100644
--- a/system/libraries/Javascript.php
+++ b/system/libraries/Javascript.php
@@ -38,6 +38,12 @@ class CI_Javascript {
protected $_javascript_location = 'js';
+ /**
+ * Constructor
+ *
+ * @param array $params = array()
+ * @return void
+ */
public function __construct($params = array())
{
$defaults = array('js_library_driver' => 'jquery', 'autoload' => TRUE);
@@ -312,8 +318,7 @@ class CI_Javascript {
*
* Outputs a javascript library mouseup event
*
- * @param string The element to attach the event to
- * @param string The code to execute
+ * @param string $js Code to execute
* @return string
*/
public function ready($js)
@@ -394,9 +399,10 @@ class CI_Javascript {
*
* Outputs a javascript library animate event
*
- * @param string - element
- * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
- * @param string - Javascript callback function
+ * @param string $element = 'this'
+ * @param array $params = array()
+ * @param mixed $speed 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string $extra
* @return string
*/
public function animate($element = 'this', $params = array(), $speed = '', $extra = '')
@@ -546,10 +552,11 @@ class CI_Javascript {
*
* Outputs a javascript library toggle class event
*
- * @param string - element
+ * @param string $element = 'this'
+ * @param string $class = ''
* @return string
*/
- public function toggleClass($element = 'this', $class='')
+ public function toggleClass($element = 'this', $class = '')
{
return $this->js->_toggleClass($element, $class);
}
@@ -579,7 +586,8 @@ class CI_Javascript {
*
* gather together all script needing to be output
*
- * @param string The element to attach the event to
+ * @param string $view_var = 'script_foot'
+ * @param bool $script_tags = TRUE
* @return string
*/
public function compile($view_var = 'script_foot', $script_tags = TRUE)
@@ -587,6 +595,8 @@ class CI_Javascript {
$this->js->_compile($view_var, $script_tags);
}
+ // --------------------------------------------------------------------
+
/**
* Clear Compile
*
@@ -606,7 +616,8 @@ class CI_Javascript {
*
* Outputs a <script> tag with the source as an external js file
*
- * @param string The element to attach the event to
+ * @param string $external_file = ''
+ * @param bool $relative = FALSE
* @return string
*/
public function external($external_file = '', $relative = FALSE)
@@ -799,7 +810,8 @@ class CI_Javascript {
*
* Ensures a standard json value and escapes values
*
- * @param mixed
+ * @param mixed $result
+ * @param bool $is_key = FALSE
* @return string
*/
protected function _prep_args($result, $is_key = FALSE)
diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php
index 5573f6407..36b57b332 100644
--- a/system/libraries/Pagination.php
+++ b/system/libraries/Pagination.php
@@ -52,20 +52,20 @@ class CI_Pagination {
protected $full_tag_open = '';
protected $full_tag_close = '';
protected $first_tag_open = '';
- protected $first_tag_close = '&nbsp;';
- protected $last_tag_open = '&nbsp;';
+ protected $first_tag_close = '';
+ protected $last_tag_open = '';
protected $last_tag_close = '';
protected $first_url = ''; // Alternative URL for the First Page.
- protected $cur_tag_open = '&nbsp;<strong>';
+ protected $cur_tag_open = '<strong>';
protected $cur_tag_close = '</strong>';
- protected $next_tag_open = '&nbsp;';
- protected $next_tag_close = '&nbsp;';
- protected $prev_tag_open = '&nbsp;';
+ protected $next_tag_open = '';
+ protected $next_tag_close = '';
+ protected $prev_tag_open = '';
protected $prev_tag_close = '';
- protected $num_tag_open = '&nbsp;';
+ protected $num_tag_open = '';
protected $num_tag_close = '';
protected $page_query_string = FALSE;
- protected $query_string_segment = 'per_page';
+ protected $query_string_segment = 'per_page';
protected $display_pages = TRUE;
protected $_attributes = '';
protected $_link_types = array();
@@ -157,7 +157,7 @@ class CI_Pagination {
// See if we are using a prefix or suffix on links
if ($this->prefix !== '' OR $this->suffix !== '')
{
- $this->cur_page = (int) str_replace(array($this->prefix, $this->suffix), '', $CI->uri->segment($this->uri_segment));
+ $this->cur_page = (int) str_replace(array($this->prefix, $this->suffix), '', $CI->uri->rsegment($this->uri_segment));
}
if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE)
@@ -169,7 +169,7 @@ class CI_Pagination {
}
elseif ( ! $this->cur_page && $CI->uri->segment($this->uri_segment) !== $base_page)
{
- $this->cur_page = (int) $CI->uri->segment($this->uri_segment);
+ $this->cur_page = (int) $CI->uri->rsegment($this->uri_segment);
}
// Set current page to 1 if it's not valid or if using page numbers instead of offset
@@ -215,7 +215,8 @@ class CI_Pagination {
// string. If post, add a trailing slash to the base URL if needed
if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE)
{
- $this->base_url = rtrim($this->base_url).'&amp;'.$this->query_string_segment.'=';
+ $segment = (strpos($this->base_url, '?')) ? '&amp;' : '?';
+ $this->base_url = rtrim($this->base_url).$segment.$this->query_string_segment.'=';
}
else
{
diff --git a/system/libraries/Session.php b/system/libraries/Session.php
deleted file mode 100644
index af38dc366..000000000
--- a/system/libraries/Session.php
+++ /dev/null
@@ -1,955 +0,0 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
-/**
- * CodeIgniter
- *
- * An open source application development framework for PHP 5.2.4 or newer
- *
- * NOTICE OF LICENSE
- *
- * Licensed under the Open Software License version 3.0
- *
- * This source file is subject to the Open Software License (OSL 3.0) that is
- * bundled with this package in the files license.txt / license.rst. It is
- * also available through the world wide web at this URL:
- * http://opensource.org/licenses/OSL-3.0
- * If you did not receive a copy of the license and are unable to obtain it
- * through the world wide web, please send an email to
- * licensing@ellislab.com so we can send you a copy immediately.
- *
- * @package CodeIgniter
- * @author EllisLab Dev Team
- * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
- * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
- * @link http://codeigniter.com
- * @since Version 1.0
- * @filesource
- */
-
-/**
- * Session Class
- *
- * @package CodeIgniter
- * @subpackage Libraries
- * @category Sessions
- * @author EllisLab Dev Team
- * @link http://codeigniter.com/user_guide/libraries/sessions.html
- */
-class CI_Session {
-
- /**
- * Whether to encrypt the session cookie
- *
- * @var bool
- */
- public $sess_encrypt_cookie = FALSE;
-
- /**
- * Whether to use to the database for session storage
- *
- * @var bool
- */
- public $sess_use_database = FALSE;
-
- /**
- * Name of the database table in which to store sessions
- *
- * @var string
- */
- public $sess_table_name = '';
-
- /**
- * Length of time (in seconds) for sessions to expire
- *
- * @var int
- */
- public $sess_expiration = 7200;
-
- /**
- * Whether to kill session on close of browser window
- *
- * @var bool
- */
- public $sess_expire_on_close = FALSE;
-
- /**
- * Whether to match session on ip address
- *
- * @var bool
- */
- public $sess_match_ip = FALSE;
-
- /**
- * Whether to match session on user-agent
- *
- * @var bool
- */
- public $sess_match_useragent = TRUE;
-
- /**
- * Name of session cookie
- *
- * @var string
- */
- public $sess_cookie_name = 'ci_session';
-
- /**
- * Session cookie prefix
- *
- * @var string
- */
- public $cookie_prefix = '';
-
- /**
- * Session cookie path
- *
- * @var string
- */
- public $cookie_path = '';
-
- /**
- * Session cookie domain
- *
- * @var string
- */
- public $cookie_domain = '';
-
- /**
- * Whether to set the cookie only on HTTPS connections
- *
- * @var bool
- */
- public $cookie_secure = FALSE;
-
- /**
- * Whether cookie should be allowed only to be sent by the server
- *
- * @var bool
- */
- public $cookie_httponly = FALSE;
-
- /**
- * Interval at which to update session
- *
- * @var int
- */
- public $sess_time_to_update = 300;
-
- /**
- * Key with which to encrypt the session cookie
- *
- * @var string
- */
- public $encryption_key = '';
-
- /**
- * String to indicate flash data cookies
- *
- * @var string
- */
- public $flashdata_key = 'flash';
-
- /**
- * Timezone to use for the current time
- *
- * @var string
- */
- public $time_reference = 'local';
-
-
- /**
- * Session data
- *
- * @var array
- */
- public $userdata = array();
-
- /**
- * Reference to CodeIgniter instance
- *
- * @var object
- */
- public $CI;
-
- /**
- * Current time
- *
- * @var int
- */
- public $now;
-
- /**
- * Session Constructor
- *
- * The constructor runs the session routines automatically
- * whenever the class is instantiated.
- *
- * @param array
- * @return void
- */
- public function __construct($params = array())
- {
- log_message('debug', 'Session Class Initialized');
-
- // Set the super object to a local variable for use throughout the class
- $this->CI =& get_instance();
-
- // Set all the session preferences, which can either be set
- // manually via the $params array above or via the config file
- foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'cookie_httponly', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key)
- {
- $this->$key = isset($params[$key]) ? $params[$key] : $this->CI->config->item($key);
- }
-
- if ($this->encryption_key === '')
- {
- show_error('In order to use the Session class you are required to set an encryption key in your config file.');
- }
-
- // Load the string helper so we can use the strip_slashes() function
- $this->CI->load->helper('string');
-
- // Do we need encryption? If so, load the encryption class
- if ($this->sess_encrypt_cookie === TRUE)
- {
- $this->CI->load->library('encrypt');
- }
-
- // Are we using a database? If so, load it
- if ($this->sess_use_database === TRUE && $this->sess_table_name !== '')
- {
- $this->CI->load->database();
- }
-
- // Set the "now" time. Can either be GMT or server time, based on the
- // config prefs. We use this to set the "last activity" time
- $this->now = $this->_get_time();
-
- // Set the session length. If the session expiration is
- // set to zero we'll set the expiration two years from now.
- if ($this->sess_expiration === 0)
- {
- $this->sess_expiration = (60*60*24*365*2);
- }
-
- // Set the cookie name
- $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
-
- // Run the Session routine. If a session doesn't exist we'll
- // create a new one. If it does, we'll update it.
- if ( ! $this->sess_read())
- {
- $this->sess_create();
- }
- else
- {
- $this->sess_update();
- }
-
- // Delete 'old' flashdata (from last request)
- $this->_flashdata_sweep();
-
- // Mark all new flashdata as old (data will be deleted before next request)
- $this->_flashdata_mark();
-
- // Delete expired sessions if necessary
- $this->_sess_gc();
-
- log_message('debug', 'Session routines successfully run');
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Fetch the current session data if it exists
- *
- * @return bool
- */
- public function sess_read()
- {
- // Fetch the cookie
- $session = $this->CI->input->cookie($this->sess_cookie_name);
-
- // No cookie? Goodbye cruel world!...
- if ($session === NULL)
- {
- log_message('debug', 'A session cookie was not found.');
- return FALSE;
- }
-
- // Decrypt the cookie data
- if ($this->sess_encrypt_cookie === TRUE)
- {
- $session = $this->CI->encrypt->decode($session);
- }
- else
- {
- // encryption was not used, so we need to check the md5 hash
- $hash = substr($session, strlen($session)-32); // get last 32 chars
- $session = substr($session, 0, strlen($session)-32);
-
- // Does the md5 hash match? This is to prevent manipulation of session data in userspace
- if ($hash !== md5($session.$this->encryption_key))
- {
- log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.');
- $this->sess_destroy();
- return FALSE;
- }
- }
-
- // Unserialize the session array
- $session = $this->_unserialize($session);
-
- // Is the session data we unserialized an array with the correct format?
- if ( ! is_array($session) OR ! isset($session['session_id'], $session['ip_address'], $session['user_agent'], $session['last_activity']))
- {
- $this->sess_destroy();
- return FALSE;
- }
-
- // Is the session current?
- if (($session['last_activity'] + $this->sess_expiration) < $this->now)
- {
- $this->sess_destroy();
- return FALSE;
- }
-
- // Does the IP match?
- if ($this->sess_match_ip === TRUE && $session['ip_address'] !== $this->CI->input->ip_address())
- {
- $this->sess_destroy();
- return FALSE;
- }
-
- // Does the User Agent Match?
- if ($this->sess_match_useragent === TRUE && trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
- {
- $this->sess_destroy();
- return FALSE;
- }
-
- // Is there a corresponding session in the DB?
- if ($this->sess_use_database === TRUE)
- {
- $this->CI->db->where('session_id', $session['session_id']);
-
- if ($this->sess_match_ip === TRUE)
- {
- $this->CI->db->where('ip_address', $session['ip_address']);
- }
-
- if ($this->sess_match_useragent === TRUE)
- {
- $this->CI->db->where('user_agent', $session['user_agent']);
- }
-
- $query = $this->CI->db->limit(1)->get($this->sess_table_name);
-
- // No result? Kill it!
- if ($query->num_rows() === 0)
- {
- $this->sess_destroy();
- return FALSE;
- }
-
- // Is there custom data? If so, add it to the main session array
- $row = $query->row();
- if ( ! empty($row->user_data))
- {
- $custom_data = $this->_unserialize($row->user_data);
-
- if (is_array($custom_data))
- {
- foreach ($custom_data as $key => $val)
- {
- $session[$key] = $val;
- }
- }
- }
- }
-
- // Session is valid!
- $this->userdata = $session;
- unset($session);
-
- return TRUE;
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Write the session data
- *
- * @return void
- */
- public function sess_write()
- {
- // Are we saving custom data to the DB? If not, all we do is update the cookie
- if ($this->sess_use_database === FALSE)
- {
- $this->_set_cookie();
- return;
- }
-
- // set the custom userdata, the session data we will set in a second
- $custom_userdata = $this->userdata;
- $cookie_userdata = array();
-
- // Before continuing, we need to determine if there is any custom data to deal with.
- // Let's determine this by removing the default indexes to see if there's anything left in the array
- // and set the session data while we're at it
- foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
- {
- unset($custom_userdata[$val]);
- $cookie_userdata[$val] = $this->userdata[$val];
- }
-
- // Did we find any custom data? If not, we turn the empty array into a string
- // since there's no reason to serialize and store an empty array in the DB
- if (count($custom_userdata) === 0)
- {
- $custom_userdata = '';
- }
- else
- {
- // Serialize the custom data array so we can store it
- $custom_userdata = $this->_serialize($custom_userdata);
- }
-
- // Run the update query
- $this->CI->db->where('session_id', $this->userdata['session_id']);
- $this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata));
-
- // Write the cookie. Notice that we manually pass the cookie data array to the
- // _set_cookie() function. Normally that function will store $this->userdata, but
- // in this case that array contains custom data, which we do not want in the cookie.
- $this->_set_cookie($cookie_userdata);
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Create a new session
- *
- * @return void
- */
- public function sess_create()
- {
- $sessid = '';
- do
- {
- $sessid .= mt_rand(0, mt_getrandmax());
- }
- while (strlen($sessid) < 32);
-
- // To make the session ID even more secure we'll combine it with the user's IP
- $sessid .= $this->CI->input->ip_address();
-
- $this->userdata = array(
- 'session_id' => md5(uniqid($sessid, TRUE)),
- 'ip_address' => $this->CI->input->ip_address(),
- 'user_agent' => substr($this->CI->input->user_agent(), 0, 120),
- 'last_activity' => $this->now,
- 'user_data' => ''
- );
-
- // Save the data to the DB if needed
- if ($this->sess_use_database === TRUE)
- {
- $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));
- }
-
- // Write the cookie
- $this->_set_cookie();
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Update an existing session
- *
- * @return void
- */
- public function sess_update()
- {
- // We only update the session every five minutes by default
- if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
- {
- return;
- }
-
- // _set_cookie() will handle this for us if we aren't using database sessions
- // by pushing all userdata to the cookie.
- $cookie_data = NULL;
-
- /* Changing the session ID during an AJAX call causes problems,
- * so we'll only update our last_activity
- */
- if ($this->CI->input->is_ajax_request())
- {
- $this->userdata['last_activity'] = $this->now;
-
- // Update the session ID and last_activity field in the DB if needed
- if ($this->sess_use_database === TRUE)
- {
- // set cookie explicitly to only have our session data
- $cookie_data = array();
- foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
- {
- $cookie_data[$val] = $this->userdata[$val];
- }
-
- $this->CI->db->query($this->CI->db->update_string($this->sess_table_name,
- array('last_activity' => $this->userdata['last_activity']),
- array('session_id' => $this->userdata['session_id'])));
- }
-
- return $this->_set_cookie($cookie_data);
- }
-
- // Save the old session id so we know which record to
- // update in the database if we need it
- $old_sessid = $this->userdata['session_id'];
- $new_sessid = '';
- do
- {
- $new_sessid .= mt_rand(0, mt_getrandmax());
- }
- while (strlen($new_sessid) < 32);
-
- // To make the session ID even more secure we'll combine it with the user's IP
- $new_sessid .= $this->CI->input->ip_address();
-
- // Turn it into a hash and update the session data array
- $this->userdata['session_id'] = $new_sessid = md5(uniqid($new_sessid, TRUE));
- $this->userdata['last_activity'] = $this->now;
-
- // Update the session ID and last_activity field in the DB if needed
- if ($this->sess_use_database === TRUE)
- {
- // set cookie explicitly to only have our session data
- $cookie_data = array();
- foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
- {
- $cookie_data[$val] = $this->userdata[$val];
- }
-
- $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));
- }
-
- // Write the cookie
- $this->_set_cookie($cookie_data);
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Destroy the current session
- *
- * @return void
- */
- public function sess_destroy()
- {
- // Kill the session DB row
- if ($this->sess_use_database === TRUE && isset($this->userdata['session_id']))
- {
- $this->CI->db->where('session_id', $this->userdata['session_id']);
- $this->CI->db->delete($this->sess_table_name);
- }
-
- // Kill the cookie
- setcookie(
- $this->sess_cookie_name,
- addslashes(serialize(array())),
- ($this->now - 31500000),
- $this->cookie_path,
- $this->cookie_domain,
- 0
- );
-
- // Kill session data
- $this->userdata = array();
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Fetch a specific item from the session array
- *
- * @param string
- * @return string
- */
- public function userdata($item)
- {
- return isset($this->userdata[$item]) ? $this->userdata[$item] : NULL;
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Fetch all session data
- *
- * @return array
- */
- public function all_userdata()
- {
- return $this->userdata;
- }
-
- // --------------------------------------------------------------------------
-
- /**
- * Fetch all flashdata
- *
- * @return array
- */
- public function all_flashdata()
- {
- $out = array();
-
- // loop through all userdata
- foreach ($this->all_userdata() as $key => $val)
- {
- // if it contains flashdata, add it
- if (strpos($key, 'flash:old:') !== FALSE)
- {
- $out[$key] = $val;
- }
- }
- return $out;
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Add or change data in the "userdata" array
- *
- * @param mixed
- * @param string
- * @return void
- */
- public function set_userdata($newdata = array(), $newval = '')
- {
- if (is_string($newdata))
- {
- $newdata = array($newdata => $newval);
- }
-
- if (count($newdata) > 0)
- {
- foreach ($newdata as $key => $val)
- {
- $this->userdata[$key] = $val;
- }
- }
-
- $this->sess_write();
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Delete a session variable from the "userdata" array
- *
- * @param array
- * @return void
- */
- public function unset_userdata($newdata = array())
- {
- if (is_string($newdata))
- {
- $newdata = array($newdata => '');
- }
-
- if (count($newdata) > 0)
- {
- foreach ($newdata as $key => $val)
- {
- unset($this->userdata[$key]);
- }
- }
-
- $this->sess_write();
- }
-
- // ------------------------------------------------------------------------
-
- /**
- * Add or change flashdata, only available
- * until the next request
- *
- * @param mixed
- * @param string
- * @return void
- */
- public function set_flashdata($newdata = array(), $newval = '')
- {
- if (is_string($newdata))
- {
- $newdata = array($newdata => $newval);
- }
-
- if (count($newdata) > 0)
- {
- foreach ($newdata as $key => $val)
- {
- $this->set_userdata($this->flashdata_key.':new:'.$key, $val);
- }
- }
- }
-
- // ------------------------------------------------------------------------
-
- /**
- * Keeps existing flashdata available to next request.
- *
- * @param string
- * @return void
- */
- public function keep_flashdata($key)
- {
- // 'old' flashdata gets removed. Here we mark all
- // flashdata as 'new' to preserve it from _flashdata_sweep()
- // Note the function will return NULL if the $key
- // provided cannot be found
- $value = $this->userdata($this->flashdata_key.':old:'.$key);
-
- $this->set_userdata($this->flashdata_key.':new:'.$key, $value);
- }
-
- // ------------------------------------------------------------------------
-
- /**
- * Fetch a specific flashdata item from the session array
- *
- * @param string
- * @return string
- */
- public function flashdata($key)
- {
- return $this->userdata($this->flashdata_key.':old:'.$key);
- }
-
- // ------------------------------------------------------------------------
-
- /**
- * Identifies flashdata as 'old' for removal
- * when _flashdata_sweep() runs.
- *
- * @return void
- */
- protected function _flashdata_mark()
- {
- $userdata = $this->all_userdata();
- foreach ($userdata as $name => $value)
- {
- $parts = explode(':new:', $name);
- if (is_array($parts) && count($parts) === 2)
- {
- $this->set_userdata($this->flashdata_key.':old:'.$parts[1], $value);
- $this->unset_userdata($name);
- }
- }
- }
-
- // ------------------------------------------------------------------------
-
- /**
- * Removes all flashdata marked as 'old'
- *
- * @return void
- */
- protected function _flashdata_sweep()
- {
- $userdata = $this->all_userdata();
- foreach ($userdata as $key => $value)
- {
- if (strpos($key, ':old:'))
- {
- $this->unset_userdata($key);
- }
- }
-
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Get the "now" time
- *
- * @return string
- */
- protected function _get_time()
- {
- if ($this->time_reference === 'local' OR $this->time_reference === date_default_timezone_get())
- {
- return time();
- }
-
- $datetime = new DateTime('now', new DateTimeZone($this->time_reference));
- sscanf($datetime->format('j-n-Y G:i:s'), '%d-%d-%d %d:%d:%d', $day, $month, $year, $hour, $minute, $second);
-
- return mktime($hour, $minute, $second, $month, $day, $year);
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Write the session cookie
- *
- * @param mixed
- * @return void
- */
- protected function _set_cookie($cookie_data = NULL)
- {
- if (is_null($cookie_data))
- {
- $cookie_data = $this->userdata;
- }
-
- // Serialize the userdata for the cookie
- $cookie_data = $this->_serialize($cookie_data);
-
- if ($this->sess_encrypt_cookie === TRUE)
- {
- $cookie_data = $this->CI->encrypt->encode($cookie_data);
- }
- else
- {
- // if encryption is not used, we provide an md5 hash to prevent userside tampering
- $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
- }
-
- $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();
-
- // Set the cookie
- setcookie(
- $this->sess_cookie_name,
- $cookie_data,
- $expire,
- $this->cookie_path,
- $this->cookie_domain,
- $this->cookie_secure,
- $this->cookie_httponly
- );
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Serialize an array
- *
- * This function first converts any slashes found in the array to a temporary
- * marker, so when it gets unserialized the slashes will be preserved
- *
- * @param array
- * @return string
- */
- protected function _serialize($data)
- {
- if (is_array($data))
- {
- array_walk_recursive($data, array(&$this, '_escape_slashes'));
- }
- elseif (is_string($data))
- {
- $data = str_replace('\\', '{{slash}}', $data);
- }
- return serialize($data);
- }
-
- /**
- * Escape slashes
- *
- * This function converts any slashes found into a temporary marker
- *
- * @param string
- * @param string
- * @return void
- */
- protected function _escape_slashes(&$val, $key)
- {
- if (is_string($val))
- {
- $val = str_replace('\\', '{{slash}}', $val);
- }
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Unserialize
- *
- * This function unserializes a data string, then converts any
- * temporary slash markers back to actual slashes
- *
- * @param array
- * @return string
- */
- protected function _unserialize($data)
- {
- $data = @unserialize(strip_slashes(trim($data)));
-
- if (is_array($data))
- {
- array_walk_recursive($data, array(&$this, '_unescape_slashes'));
- return $data;
- }
-
- return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data;
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Unescape slashes
- *
- * This function converts any slash markers back into actual slashes
- *
- * @param string
- * @param string
- * @return void
- */
- protected function _unescape_slashes(&$val, $key)
- {
- if (is_string($val))
- {
- $val= str_replace('{{slash}}', '\\', $val);
- }
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Garbage collection
- *
- * This deletes expired session rows from database
- * if the probability percentage is met
- *
- * @return void
- */
- protected function _sess_gc()
- {
- if ($this->sess_use_database !== TRUE)
- {
- return;
- }
-
- $probability = ini_get('session.gc_probability');
- $divisor = ini_get('session.gc_divisor');
-
- srand(time());
- if ((mt_rand(0, $divisor) / $divisor) < $probability)
- {
- $expire = $this->now - $this->sess_expiration;
-
- $this->CI->db->where('last_activity < '.$expire);
- $this->CI->db->delete($this->sess_table_name);
-
- log_message('debug', 'Session garbage collection performed.');
- }
- }
-
-}
-
-/* End of file Session.php */
-/* Location: ./system/libraries/Session.php */ \ No newline at end of file
diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php
new file mode 100755
index 000000000..978506062
--- /dev/null
+++ b/system/libraries/Session/Session.php
@@ -0,0 +1,714 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst. It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc.
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 2.0
+ * @filesource
+ */
+
+/**
+ * CodeIgniter Session Class
+ *
+ * The user interface defined by EllisLabs, now with puggable drivers to manage different storage mechanisms.
+ * By default, the cookie session driver will load, but the 'sess_driver' config/param item (see above) can be
+ * used to specify the 'native' driver, or any other you might create.
+ * Once loaded, this driver setup is a drop-in replacement for the former CI_Session library, taking its place as the
+ * 'session' member of the global controller framework (e.g.: $CI->session or $this->session).
+ * In keeping with the CI_Driver methodology, multiple drivers may be loaded, although this might be a bit confusing.
+ * The CI_Session library class keeps track of the most recently loaded driver as "current" to call for driver methods.
+ * Ideally, one driver is loaded and all calls go directly through the main library interface. However, any methods
+ * called through the specific driver will switch the "current" driver to itself before invoking the library method
+ * (which will then call back into the driver for low-level operations). So, alternation between two drivers can be
+ * achieved by specifying which driver to use for each call (e.g.: $this->session->native->set_userdata('foo', 'bar');
+ * $this->session->cookie->userdata('foo'); $this->session->native->unset_userdata('foo');). Notice in the previous
+ * example that the _native_ userdata value 'foo' would be set to 'bar', which would NOT be returned by the call for
+ * the _cookie_ userdata 'foo', nor would the _cookie_ value be unset by the call to unset the _native_ 'foo' value.
+ *
+ * @package CodeIgniter
+ * @subpackage Libraries
+ * @category Sessions
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/libraries/sessions.html
+ */
+class CI_Session extends CI_Driver_Library {
+
+ public $params = array();
+ protected $current = NULL;
+ protected $userdata = array();
+
+ const FLASHDATA_KEY = 'flash';
+ const FLASHDATA_NEW = ':new:';
+ const FLASHDATA_OLD = ':old:';
+ const FLASHDATA_EXP = ':exp:';
+ const EXPIRATION_KEY = '__expirations';
+ const TEMP_EXP_DEF = 300;
+
+ /**
+ * CI_Session constructor
+ *
+ * The constructor loads the configured driver ('sess_driver' in config.php or as a parameter), running
+ * routines in its constructor, and manages flashdata aging.
+ *
+ * @param array Configuration parameters
+ * @return void
+ */
+ public function __construct(array $params = array())
+ {
+ $CI =& get_instance();
+
+ // No sessions under CLI
+ if ($CI->input->is_cli_request())
+ {
+ return;
+ }
+
+ log_message('debug', 'CI_Session Class Initialized');
+
+ // Get valid drivers list
+ $this->valid_drivers = array(
+ 'Session_native',
+ 'Session_cookie'
+ );
+ $key = 'sess_valid_drivers';
+ $drivers = isset($params[$key]) ? $params[$key] : $CI->config->item($key);
+ if ($drivers)
+ {
+ is_array($drivers) OR $drivers = array($drivers);
+
+ // Add driver names to valid list
+ foreach ($drivers as $driver)
+ {
+ if ( ! in_array(strtolower($driver), array_map('strtolower', $this->valid_drivers)))
+ {
+ $this->valid_drivers[] = $driver;
+ }
+ }
+ }
+
+ // Get driver to load
+ $key = 'sess_driver';
+ $driver = isset($params[$key]) ? $params[$key] : $CI->config->item($key);
+ if ( ! $driver)
+ {
+ $driver = 'cookie';
+ }
+
+ if ( ! in_array('session_'.strtolower($driver), array_map('strtolower', $this->valid_drivers)))
+ {
+ $this->valid_drivers[] = 'Session_'.$driver;
+ }
+
+ // Save a copy of parameters in case drivers need access
+ $this->params = $params;
+
+ // Load driver and get array reference
+ $this->load_driver($driver);
+
+ // Delete 'old' flashdata (from last request)
+ $this->_flashdata_sweep();
+
+ // Mark all new flashdata as old (data will be deleted before next request)
+ $this->_flashdata_mark();
+
+ // Delete expired tempdata
+ $this->_tempdata_sweep();
+
+ log_message('debug', 'CI_Session routines successfully run');
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Loads session storage driver
+ *
+ * @param string Driver classname
+ * @return object Loaded driver object
+ */
+ public function load_driver($driver)
+ {
+ // Save reference to most recently loaded driver as library default and sync userdata
+ $this->current = parent::load_driver($driver);
+ $this->userdata =& $this->current->get_userdata();
+ return $this->current;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Select default session storage driver
+ *
+ * @param string Driver classname
+ * @return void
+ */
+ public function select_driver($driver)
+ {
+ // Validate driver name
+ $lowername = strtolower(str_replace('CI_', '', $driver));
+ if (in_array($lowername, array_map('strtolower', $this->valid_drivers)))
+ {
+ // See if driver is loaded
+ $child = str_replace($this->lib_name.'_', '', $driver);
+ if (isset($this->$child))
+ {
+ // See if driver is already current
+ if ($this->$child !== $this->current)
+ {
+ // Make driver current and sync userdata
+ $this->current = $this->$child;
+ $this->userdata =& $this->current->get_userdata();
+ }
+ }
+ else
+ {
+ // Load new driver
+ $this->load_driver($child);
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Destroy the current session
+ *
+ * @return void
+ */
+ public function sess_destroy()
+ {
+ // Just call destroy on driver
+ $this->current->sess_destroy();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Regenerate the current session
+ *
+ * @param bool Destroy session data flag (default: false)
+ * @return void
+ */
+ public function sess_regenerate($destroy = FALSE)
+ {
+ // Call regenerate on driver and resync userdata
+ $this->current->sess_regenerate($destroy);
+ $this->userdata =& $this->current->get_userdata();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch a specific item from the session array
+ *
+ * @param string Item key
+ * @return string Item value or NULL if not found
+ */
+ public function userdata($item)
+ {
+ return isset($this->userdata[$item]) ? $this->userdata[$item] : NULL;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch all session data
+ *
+ * @return array User data array
+ */
+ public function all_userdata()
+ {
+ return isset($this->userdata) ? $this->userdata : NULL;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch all flashdata
+ *
+ * @return array Flash data array
+ */
+ public function all_flashdata()
+ {
+ $out = array();
+
+ // loop through all userdata
+ foreach ($this->all_userdata() as $key => $val)
+ {
+ // if it contains flashdata, add it
+ if (strpos($key, self::FLASHDATA_KEY.self::FLASHDATA_OLD) !== FALSE)
+ {
+ $key = str_replace(self::FLASHDATA_KEY.self::FLASHDATA_OLD, '', $key);
+ $out[$key] = $val;
+ }
+ }
+ return $out;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Add or change data in the "userdata" array
+ *
+ * @param mixed Item name or array of items
+ * @param string Item value or empty string
+ * @return void
+ */
+ public function set_userdata($newdata = array(), $newval = '')
+ {
+ // Wrap params as array if singular
+ if (is_string($newdata))
+ {
+ $newdata = array($newdata => $newval);
+ }
+
+ // Set each name/value pair
+ if (count($newdata) > 0)
+ {
+ foreach ($newdata as $key => $val)
+ {
+ $this->userdata[$key] = $val;
+ }
+ }
+
+ // Tell driver data changed
+ $this->current->sess_save();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Delete a session variable from the "userdata" array
+ *
+ * @param mixed Item name or array of item names
+ * @return void
+ */
+ public function unset_userdata($newdata = array())
+ {
+ // Wrap single name as array
+ if (is_string($newdata))
+ {
+ $newdata = array($newdata => '');
+ }
+
+ // Unset each item name
+ if (count($newdata) > 0)
+ {
+ foreach (array_keys($newdata) as $key)
+ {
+ unset($this->userdata[$key]);
+ }
+ }
+
+ // Tell driver data changed
+ $this->current->sess_save();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Determine if an item exists
+ *
+ * @param string Item name
+ * @return bool
+ */
+ public function has_userdata($item)
+ {
+ return isset($this->userdata[$item]);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Add or change flashdata, only available until the next request
+ *
+ * @param mixed Item name or array of items
+ * @param string Item value or empty string
+ * @return void
+ */
+ public function set_flashdata($newdata = array(), $newval = '')
+ {
+ // Wrap item as array if singular
+ if (is_string($newdata))
+ {
+ $newdata = array($newdata => $newval);
+ }
+
+ // Prepend each key name and set value
+ if (count($newdata) > 0)
+ {
+ foreach ($newdata as $key => $val)
+ {
+ $flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_NEW.$key;
+ $this->set_userdata($flashdata_key, $val);
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Keeps existing flashdata available to next request.
+ *
+ * @param string Item key
+ * @return void
+ */
+ public function keep_flashdata($key)
+ {
+ // 'old' flashdata gets removed. Here we mark all flashdata as 'new' to preserve it from _flashdata_sweep()
+ // Note the function will return NULL if the $key provided cannot be found
+ $old_flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key;
+ $value = $this->userdata($old_flashdata_key);
+
+ $new_flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_NEW.$key;
+ $this->set_userdata($new_flashdata_key, $value);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch a specific flashdata item from the session array
+ *
+ * @param string Item key
+ * @return string
+ */
+ public function flashdata($key)
+ {
+ // Prepend key and retrieve value
+ $flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key;
+ return $this->userdata($flashdata_key);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Add or change tempdata, only available until expiration
+ *
+ * @param mixed Item name or array of items
+ * @param string Item value or empty string
+ * @param int Item lifetime in seconds or 0 for default
+ * @return void
+ */
+ public function set_tempdata($newdata = array(), $newval = '', $expire = 0)
+ {
+ // Set expiration time
+ $expire = time() + ($expire ? $expire : self::TEMP_EXP_DEF);
+
+ // Wrap item as array if singular
+ if (is_string($newdata))
+ {
+ $newdata = array($newdata => $newval);
+ }
+
+ // Get or create expiration list
+ $expirations = $this->userdata(self::EXPIRATION_KEY);
+ if ( ! $expirations)
+ {
+ $expirations = array();
+ }
+
+ // Prepend each key name and set value
+ if (count($newdata) > 0)
+ {
+ foreach ($newdata as $key => $val)
+ {
+ $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key;
+ $expirations[$tempdata_key] = $expire;
+ $this->set_userdata($tempdata_key, $val);
+ }
+ }
+
+ // Update expiration list
+ $this->set_userdata(self::EXPIRATION_KEY, $expirations);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Delete a temporary session variable from the "userdata" array
+ *
+ * @param mixed Item name or array of item names
+ * @return void
+ */
+ public function unset_tempdata($newdata = array())
+ {
+ // Get expirations list
+ $expirations = $this->userdata(self::EXPIRATION_KEY);
+ if (empty($expirations))
+ {
+ // Nothing to do
+ return;
+ }
+
+ // Wrap single name as array
+ if (is_string($newdata))
+ {
+ $newdata = array($newdata => '');
+ }
+
+ // Prepend each item name and unset
+ if (count($newdata) > 0)
+ {
+ foreach (array_keys($newdata) as $key)
+ {
+ $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key;
+ unset($expirations[$tempdata_key]);
+ $this->unset_userdata($tempdata_key);
+ }
+ }
+
+ // Update expiration list
+ $this->set_userdata(self::EXPIRATION_KEY, $expirations);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch a specific tempdata item from the session array
+ *
+ * @param string Item key
+ * @return string
+ */
+ public function tempdata($key)
+ {
+ // Prepend key and return value
+ $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key;
+ return $this->userdata($tempdata_key);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Identifies flashdata as 'old' for removal
+ * when _flashdata_sweep() runs.
+ *
+ * @return void
+ */
+ protected function _flashdata_mark()
+ {
+ foreach ($this->all_userdata() as $name => $value)
+ {
+ $parts = explode(self::FLASHDATA_NEW, $name);
+ if (is_array($parts) && count($parts) === 2)
+ {
+ $new_name = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$parts[1];
+ $this->set_userdata($new_name, $value);
+ $this->unset_userdata($name);
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Removes all flashdata marked as 'old'
+ *
+ * @return void
+ */
+ protected function _flashdata_sweep()
+ {
+ $userdata = $this->all_userdata();
+ foreach (array_keys($userdata) as $key)
+ {
+ if (strpos($key, self::FLASHDATA_OLD))
+ {
+ $this->unset_userdata($key);
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Removes all expired tempdata
+ *
+ * @return void
+ */
+ protected function _tempdata_sweep()
+ {
+ // Get expirations list
+ $expirations = $this->userdata(self::EXPIRATION_KEY);
+ if (empty($expirations))
+ {
+ // Nothing to do
+ return;
+ }
+
+ // Unset expired elements
+ $now = time();
+ $userdata = $this->all_userdata();
+ foreach (array_keys($userdata) as $key)
+ {
+ if (strpos($key, self::FLASHDATA_EXP) && $expirations[$key] < $now)
+ {
+ unset($expirations[$key]);
+ $this->unset_userdata($key);
+ }
+ }
+
+ // Update expiration list
+ $this->set_userdata(self::EXPIRATION_KEY, $expirations);
+ }
+
+}
+
+// ------------------------------------------------------------------------
+
+/**
+ * CI_Session_driver Class
+ *
+ * Extend this class to make a new CI_Session driver.
+ * A CI_Session driver basically manages an array of name/value pairs with some sort of storage mechanism.
+ * To make a new driver, derive from (extend) CI_Session_driver. Overload the initialize method and read or create
+ * session data. Then implement a save handler to write changed data to storage (sess_save), a destroy handler
+ * to remove deleted data (sess_destroy), and an access handler to expose the data (get_userdata).
+ * Put your driver in the libraries/Session/drivers folder anywhere in the loader paths. This includes the
+ * application directory, the system directory, or any path you add with $CI->load->add_package_path().
+ * Your driver must be named CI_Session_<name>, and your filename must be Session_<name>.php,
+ * preferably also capitalized. (e.g.: CI_Session_foo in libraries/Session/drivers/Session_foo.php)
+ * Then specify the driver by setting 'sess_driver' in your config file or as a parameter when loading the CI_Session
+ * object. (e.g.: $config['sess_driver'] = 'foo'; OR $CI->load->driver('session', array('sess_driver' => 'foo')); )
+ * Already provided are the Native driver, which manages the native PHP $_SESSION array, and
+ * the Cookie driver, which manages the data in a browser cookie, with optional extra storage in a database table.
+ *
+ * @package CodeIgniter
+ * @subpackage Libraries
+ * @category Sessions
+ * @author EllisLab Dev Team
+ */
+abstract class CI_Session_driver extends CI_Driver {
+
+ protected $CI;
+
+ /**
+ * Constructor
+ *
+ * Gets the CI singleton, so that individual drivers
+ * don't have to do it separately.
+ *
+ * @return void
+ */
+ public function __construct()
+ {
+ $this->CI =& get_instance();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Decorate
+ *
+ * Decorates the child with the parent driver lib's methods and properties
+ *
+ * @param object Parent library object
+ * @return void
+ */
+ public function decorate($parent)
+ {
+ // Call base class decorate first
+ parent::decorate($parent);
+
+ // Call initialize method now that driver has access to $this->_parent
+ $this->initialize();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * __call magic method
+ *
+ * Handles access to the parent driver library's methods
+ *
+ * @param string Library method name
+ * @param array Method arguments (default: none)
+ * @return mixed
+ */
+ public function __call($method, $args = array())
+ {
+ // Make sure the parent library uses this driver
+ $this->_parent->select_driver(get_class($this));
+ return parent::__call($method, $args);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Initialize driver
+ *
+ * @return void
+ */
+ protected function initialize()
+ {
+ // Overload this method to implement initialization
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Save the session data
+ *
+ * Data in the array has changed - perform any storage synchronization
+ * necessary. The child class MUST implement this abstract method!
+ *
+ * @return void
+ */
+ abstract public function sess_save();
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Destroy the current session
+ *
+ * Clean up storage for this session - it has been terminated.
+ * The child class MUST implement this abstract method!
+ *
+ * @return void
+ */
+ abstract public function sess_destroy();
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Regenerate the current session
+ *
+ * Regenerate the session ID.
+ * The child class MUST implement this abstract method!
+ *
+ * @param bool Destroy session data flag (default: false)
+ * @return void
+ */
+ abstract public function sess_regenerate($destroy = FALSE);
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Get a reference to user data array
+ *
+ * Give array access to the main CI_Session object.
+ * The child class MUST implement this abstract method!
+ *
+ * @return array Reference to userdata
+ */
+ abstract public function &get_userdata();
+
+}
+
+/* End of file Session.php */
+/* Location: ./system/libraries/Session/Session.php */ \ No newline at end of file
diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php
new file mode 100755
index 000000000..8617aec2d
--- /dev/null
+++ b/system/libraries/Session/drivers/Session_cookie.php
@@ -0,0 +1,821 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst. It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 1.0
+ * @filesource
+ */
+
+/**
+ * Cookie-based session management driver
+ *
+ * This is the classic CI_Session functionality, as written by EllisLab, abstracted out to a driver.
+ *
+ * @package CodeIgniter
+ * @subpackage Libraries
+ * @category Sessions
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/libraries/sessions.html
+ */
+class CI_Session_cookie extends CI_Session_driver {
+
+ /**
+ * Whether to encrypt the session cookie
+ *
+ * @var bool
+ */
+ public $sess_encrypt_cookie = FALSE;
+
+ /**
+ * Whether to use to the database for session storage
+ *
+ * @var bool
+ */
+ public $sess_use_database = FALSE;
+
+ /**
+ * Name of the database table in which to store sessions
+ *
+ * @var string
+ */
+ public $sess_table_name = '';
+
+ /**
+ * Length of time (in seconds) for sessions to expire
+ *
+ * @var int
+ */
+ public $sess_expiration = 7200;
+
+ /**
+ * Whether to kill session on close of browser window
+ *
+ * @var bool
+ */
+ public $sess_expire_on_close = FALSE;
+
+ /**
+ * Whether to match session on ip address
+ *
+ * @var bool
+ */
+ public $sess_match_ip = FALSE;
+
+ /**
+ * Whether to match session on user-agent
+ *
+ * @var bool
+ */
+ public $sess_match_useragent = TRUE;
+
+ /**
+ * Name of session cookie
+ *
+ * @var string
+ */
+ public $sess_cookie_name = 'ci_session';
+
+ /**
+ * Session cookie prefix
+ *
+ * @var string
+ */
+ public $cookie_prefix = '';
+
+ /**
+ * Session cookie path
+ *
+ * @var string
+ */
+ public $cookie_path = '';
+
+ /**
+ * Session cookie domain
+ *
+ * @var string
+ */
+ public $cookie_domain = '';
+
+ /**
+ * Whether to set the cookie only on HTTPS connections
+ *
+ * @var bool
+ */
+ public $cookie_secure = FALSE;
+
+ /**
+ * Whether cookie should be allowed only to be sent by the server
+ *
+ * @var bool
+ */
+ public $cookie_httponly = FALSE;
+
+ /**
+ * Interval at which to update session
+ *
+ * @var int
+ */
+ public $sess_time_to_update = 300;
+
+ /**
+ * Key with which to encrypt the session cookie
+ *
+ * @var string
+ */
+ public $encryption_key = '';
+
+ /**
+ * Timezone to use for the current time
+ *
+ * @var string
+ */
+ public $time_reference = 'local';
+
+ /**
+ * Session data
+ *
+ * @var array
+ */
+ public $userdata = array();
+
+ /**
+ * Current time
+ *
+ * @var int
+ */
+ public $now;
+
+ /**
+ * Default userdata keys
+ *
+ * @var array
+ */
+ protected $defaults = array(
+ 'session_id' => NULL,
+ 'ip_address' => NULL,
+ 'user_agent' => NULL,
+ 'last_activity' => NULL
+ );
+
+ /**
+ * Data needs DB update flag
+ *
+ * @var bool
+ */
+ protected $data_dirty = FALSE;
+
+ /**
+ * Initialize session driver object
+ *
+ * @return void
+ */
+ protected function initialize()
+ {
+ // Set all the session preferences, which can either be set
+ // manually via the $params array or via the config file
+ $prefs = array(
+ 'sess_encrypt_cookie',
+ 'sess_use_database',
+ 'sess_table_name',
+ 'sess_expiration',
+ 'sess_expire_on_close',
+ 'sess_match_ip',
+ 'sess_match_useragent',
+ 'sess_cookie_name',
+ 'cookie_path',
+ 'cookie_domain',
+ 'cookie_secure',
+ 'cookie_httponly',
+ 'sess_time_to_update',
+ 'time_reference',
+ 'cookie_prefix',
+ 'encryption_key'
+ );
+
+ foreach ($prefs as $key)
+ {
+ $this->$key = isset($this->_parent->params[$key])
+ ? $this->_parent->params[$key]
+ : $this->CI->config->item($key);
+ }
+
+ if ($this->encryption_key === '')
+ {
+ show_error('In order to use the Cookie Session driver you are required to set an encryption key in your config file.');
+ }
+
+ // Load the string helper so we can use the strip_slashes() function
+ $this->CI->load->helper('string');
+
+ // Do we need encryption? If so, load the encryption class
+ if ($this->sess_encrypt_cookie === TRUE)
+ {
+ $this->CI->load->library('encrypt');
+ }
+
+ // Check for database
+ if ($this->sess_use_database === TRUE && $this->sess_table_name !== '')
+ {
+ // Load database driver
+ $this->CI->load->database();
+
+ // Register shutdown function
+ register_shutdown_function(array($this, '_update_db'));
+ }
+
+ // Set the "now" time. Can either be GMT or server time, based on the config prefs.
+ // We use this to set the "last activity" time
+ $this->now = $this->_get_time();
+
+ // Set the session length. If the session expiration is
+ // set to zero we'll set the expiration two years from now.
+ if ($this->sess_expiration === 0)
+ {
+ $this->sess_expiration = (60*60*24*365*2);
+ }
+
+ // Set the cookie name
+ $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
+
+ // Run the Session routine. If a session doesn't exist we'll
+ // create a new one. If it does, we'll update it.
+ if ( ! $this->_sess_read())
+ {
+ $this->_sess_create();
+ }
+ else
+ {
+ $this->_sess_update();
+ }
+
+ // Delete expired sessions if necessary
+ $this->_sess_gc();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Write the session data
+ *
+ * @return void
+ */
+ public function sess_save()
+ {
+ // Check for database
+ if ($this->sess_use_database === TRUE)
+ {
+ // Mark custom data as dirty so we know to update the DB
+ $this->data_dirty = TRUE;
+ }
+
+ // Write the cookie
+ $this->_set_cookie();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Destroy the current session
+ *
+ * @return void
+ */
+ public function sess_destroy()
+ {
+ // Kill the session DB row
+ if ($this->sess_use_database === TRUE && isset($this->userdata['session_id']))
+ {
+ $this->CI->db->delete($this->sess_table_name, array('session_id' => $this->userdata['session_id']));
+ $this->data_dirty = FALSE;
+ }
+
+ // Kill the cookie
+ $this->_setcookie($this->sess_cookie_name, '', ($this->now - 31500000),
+ $this->cookie_path, $this->cookie_domain, 0);
+
+ // Kill session data
+ $this->userdata = array();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Regenerate the current session
+ *
+ * Regenerate the session id
+ *
+ * @param bool Destroy session data flag (default: false)
+ * @return void
+ */
+ public function sess_regenerate($destroy = FALSE)
+ {
+ // Check destroy flag
+ if ($destroy)
+ {
+ // Destroy old session and create new one
+ $this->sess_destroy();
+ $this->_sess_create();
+ }
+ else
+ {
+ // Just force an update to recreate the id
+ $this->_sess_update(TRUE);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Get a reference to user data array
+ *
+ * @return array Reference to userdata
+ */
+ public function &get_userdata()
+ {
+ return $this->userdata;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch the current session data if it exists
+ *
+ * @return bool
+ */
+ protected function _sess_read()
+ {
+ // Fetch the cookie
+ $session = $this->CI->input->cookie($this->sess_cookie_name);
+
+ // No cookie? Goodbye cruel world!...
+ if ($session === NULL)
+ {
+ log_message('debug', 'A session cookie was not found.');
+ return FALSE;
+ }
+
+ $len = strlen($session) - 40;
+
+ if ($len < 0)
+ {
+ log_message('debug', 'The session cookie was not signed.');
+ return FALSE;
+ }
+
+ // Check cookie authentication
+ $hmac = substr($session, $len);
+ $session = substr($session, 0, $len);
+
+ if ($hmac !== hash_hmac('sha1', $session, $this->encryption_key))
+ {
+ log_message('error', 'The session cookie data did not match what was expected.');
+ $this->sess_destroy();
+ return FALSE;
+ }
+
+ // Check for encryption
+ if ($this->sess_encrypt_cookie === TRUE)
+ {
+ // Decrypt the cookie data
+ $session = $this->CI->encrypt->decode($session);
+ }
+
+ // Unserialize the session array
+ $session = $this->_unserialize($session);
+
+ // Is the session data we unserialized an array with the correct format?
+ if ( ! is_array($session) OR ! isset($session['session_id'], $session['ip_address'], $session['user_agent'], $session['last_activity']))
+ {
+ $this->sess_destroy();
+ return FALSE;
+ }
+
+ // Is the session current?
+ if (($session['last_activity'] + $this->sess_expiration) < $this->now OR $session['last_activity'] > $this->now)
+ {
+ $this->sess_destroy();
+ return FALSE;
+ }
+
+ // Does the IP match?
+ if ($this->sess_match_ip === TRUE && $session['ip_address'] !== $this->CI->input->ip_address())
+ {
+ $this->sess_destroy();
+ return FALSE;
+ }
+
+ // Does the User Agent Match?
+ if ($this->sess_match_useragent === TRUE &&
+ trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
+ {
+ $this->sess_destroy();
+ return FALSE;
+ }
+
+ // Is there a corresponding session in the DB?
+ if ($this->sess_use_database === TRUE)
+ {
+ $this->CI->db->where('session_id', $session['session_id']);
+
+ if ($this->sess_match_ip === TRUE)
+ {
+ $this->CI->db->where('ip_address', $session['ip_address']);
+ }
+
+ if ($this->sess_match_useragent === TRUE)
+ {
+ $this->CI->db->where('user_agent', $session['user_agent']);
+ }
+
+ // Is caching in effect? Turn it off
+ $db_cache = $this->CI->db->cache_on;
+ $this->CI->db->cache_off();
+
+ $query = $this->CI->db->limit(1)->get($this->sess_table_name);
+
+ // Was caching in effect?
+ if ($db_cache)
+ {
+ // Turn it back on
+ $this->CI->db->cache_on();
+ }
+
+ // No result? Kill it!
+ if ($query->num_rows() === 0)
+ {
+ $this->sess_destroy();
+ return FALSE;
+ }
+
+ // Is there custom data? If so, add it to the main session array
+ $row = $query->row();
+ if ( ! empty($row->user_data))
+ {
+ $custom_data = $this->_unserialize($row->user_data);
+
+ if (is_array($custom_data))
+ {
+ $session = $session + $custom_data;
+ }
+ }
+ }
+
+ // Session is valid!
+ $this->userdata = $session;
+ return TRUE;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Create a new session
+ *
+ * @return void
+ */
+ protected function _sess_create()
+ {
+ // Initialize userdata
+ $this->userdata = array(
+ 'session_id' => $this->_make_sess_id(),
+ 'ip_address' => $this->CI->input->ip_address(),
+ 'user_agent' => substr($this->CI->input->user_agent(), 0, 120),
+ 'last_activity' => $this->now,
+ );
+
+ // Check for database
+ if ($this->sess_use_database === TRUE)
+ {
+ // Add empty user_data field and save the data to the DB
+ $this->CI->db->set('user_data', '')->insert($this->sess_table_name, $this->userdata);
+ }
+
+ // Write the cookie
+ $this->_set_cookie();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Update an existing session
+ *
+ * @param bool Force update flag (default: false)
+ * @return void
+ */
+ protected function _sess_update($force = FALSE)
+ {
+ // We only update the session every five minutes by default (unless forced)
+ if ( ! $force && ($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
+ {
+ return;
+ }
+
+ // Update last activity to now
+ $this->userdata['last_activity'] = $this->now;
+
+ // Save the old session id so we know which DB record to update
+ $old_sessid = $this->userdata['session_id'];
+
+ // Changing the session ID during an AJAX call causes problems
+ if ( ! $this->CI->input->is_ajax_request())
+ {
+ // Get new id
+ $this->userdata['session_id'] = $this->_make_sess_id();
+ }
+
+ // Check for database
+ if ($this->sess_use_database === TRUE)
+ {
+ // Update the session ID and last_activity field in the DB
+ $this->CI->db->update($this->sess_table_name, array(
+ 'last_activity' => $this->now,
+ 'session_id' => $this->userdata['session_id']
+ ), array('session_id' => $old_sessid));
+ }
+
+ // Write the cookie
+ $this->_set_cookie();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Update database with current data
+ *
+ * This gets called from the shutdown function and also
+ * registered with PHP to run at the end of the request
+ * so it's guaranteed to update even when a fatal error
+ * occurs. The first call makes the update and clears the
+ * dirty flag so it won't happen twice.
+ *
+ * @return void
+ */
+ public function _update_db()
+ {
+ // Check for database and dirty flag and unsaved
+ if ($this->sess_use_database === TRUE && $this->data_dirty === TRUE)
+ {
+ // Set up activity and data fields to be set
+ // If we don't find custom data, user_data will remain an empty string
+ $set = array(
+ 'last_activity' => $this->userdata['last_activity'],
+ 'user_data' => ''
+ );
+
+ // Get the custom userdata, leaving out the defaults
+ // (which get stored in the cookie)
+ $userdata = array_diff_key($this->userdata, $this->defaults);
+
+ // Did we find any custom data?
+ if ( ! empty($userdata))
+ {
+ // Serialize the custom data array so we can store it
+ $set['user_data'] = $this->_serialize($userdata);
+ }
+
+ // Run the update query
+ // Any time we change the session id, it gets updated immediately,
+ // so our where clause below is always safe
+ $this->CI->db->update($this->sess_table_name, $set, array('session_id' => $this->userdata['session_id']));
+
+ // Clear dirty flag to prevent double updates
+ $this->data_dirty = FALSE;
+
+ log_message('debug', 'CI_Session Data Saved To DB');
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Generate a new session id
+ *
+ * @return string Hashed session id
+ */
+ protected function _make_sess_id()
+ {
+ $new_sessid = '';
+ do
+ {
+ $new_sessid .= mt_rand(0, mt_getrandmax());
+ }
+ while (strlen($new_sessid) < 32);
+
+ // To make the session ID even more secure we'll combine it with the user's IP
+ $new_sessid .= $this->CI->input->ip_address();
+
+ // Turn it into a hash and return
+ return md5(uniqid($new_sessid, TRUE));
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Get the "now" time
+ *
+ * @return int Time
+ */
+ protected function _get_time()
+ {
+ if ($this->time_reference === 'local' OR $this->time_reference === date_default_timezone_get())
+ {
+ return time();
+ }
+
+ $datetime = new DateTime('now', new DateTimeZone($this->time_reference));
+ sscanf($datetime->format('j-n-Y G:i:s'), '%d-%d-%d %d:%d:%d', $day, $month, $year, $hour, $minute, $second);
+
+ return mktime($hour, $minute, $second, $month, $day, $year);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Write the session cookie
+ *
+ * @return void
+ */
+ protected function _set_cookie()
+ {
+ // Get userdata (only defaults if database)
+ $cookie_data = ($this->sess_use_database === TRUE)
+ ? array_intersect_key($this->userdata, $this->defaults)
+ : $this->userdata;
+
+ // Serialize the userdata for the cookie
+ $cookie_data = $this->_serialize($cookie_data);
+
+ if ($this->sess_encrypt_cookie === TRUE)
+ {
+ $cookie_data = $this->CI->encrypt->encode($cookie_data);
+ }
+
+ // Require message authentication
+ $cookie_data .= hash_hmac('sha1', $cookie_data, $this->encryption_key);
+
+ $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();
+
+ // Set the cookie
+ $this->_setcookie($this->sess_cookie_name, $cookie_data, $expire, $this->cookie_path, $this->cookie_domain,
+ $this->cookie_secure, $this->cookie_httponly);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Set a cookie with the system
+ *
+ * This abstraction of the setcookie call allows overriding for unit testing
+ *
+ * @param string Cookie name
+ * @param string Cookie value
+ * @param int Expiration time
+ * @param string Cookie path
+ * @param string Cookie domain
+ * @param bool Secure connection flag
+ * @param bool HTTP protocol only flag
+ * @return void
+ */
+ protected function _setcookie($name, $value = '', $expire = 0, $path = '', $domain = '', $secure = FALSE, $httponly = FALSE)
+ {
+ setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Serialize an array
+ *
+ * This function first converts any slashes found in the array to a temporary
+ * marker, so when it gets unserialized the slashes will be preserved
+ *
+ * @param mixed Data to serialize
+ * @return string Serialized data
+ */
+ protected function _serialize($data)
+ {
+ if (is_array($data))
+ {
+ array_walk_recursive($data, array(&$this, '_escape_slashes'));
+ }
+ elseif (is_string($data))
+ {
+ $data = str_replace('\\', '{{slash}}', $data);
+ }
+
+ return serialize($data);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Escape slashes
+ *
+ * This function converts any slashes found into a temporary marker
+ *
+ * @param string Value
+ * @param string Key
+ * @return void
+ */
+ protected function _escape_slashes(&$val, $key)
+ {
+ if (is_string($val))
+ {
+ $val = str_replace('\\', '{{slash}}', $val);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Unserialize
+ *
+ * This function unserializes a data string, then converts any
+ * temporary slash markers back to actual slashes
+ *
+ * @param mixed Data to unserialize
+ * @return mixed Unserialized data
+ */
+ protected function _unserialize($data)
+ {
+ $data = @unserialize(strip_slashes(trim($data)));
+
+ if (is_array($data))
+ {
+ array_walk_recursive($data, array(&$this, '_unescape_slashes'));
+ return $data;
+ }
+
+ return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Unescape slashes
+ *
+ * This function converts any slash markers back into actual slashes
+ *
+ * @param string Value
+ * @param string Key
+ * @return void
+ */
+ protected function _unescape_slashes(&$val, $key)
+ {
+ if (is_string($val))
+ {
+ $val= str_replace('{{slash}}', '\\', $val);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Garbage collection
+ *
+ * This deletes expired session rows from database
+ * if the probability percentage is met
+ *
+ * @return void
+ */
+ protected function _sess_gc()
+ {
+ if ($this->sess_use_database !== TRUE)
+ {
+ return;
+ }
+
+ $probability = ini_get('session.gc_probability');
+ $divisor = ini_get('session.gc_divisor');
+
+ srand(time());
+ if ((mt_rand(0, $divisor) / $divisor) < $probability)
+ {
+ $expire = $this->now - $this->sess_expiration;
+ $this->CI->db->delete($this->sess_table_name, 'last_activity < '.$expire);
+
+ log_message('debug', 'Session garbage collection performed.');
+ }
+ }
+
+}
+
+/* End of file Session_cookie.php */
+/* Location: ./system/libraries/Session/drivers/Session_cookie.php */ \ No newline at end of file
diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php
new file mode 100755
index 000000000..da744f39b
--- /dev/null
+++ b/system/libraries/Session/drivers/Session_native.php
@@ -0,0 +1,241 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst. It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 1.0
+ * @filesource
+ */
+
+/**
+ * Native PHP session management driver
+ *
+ * This is the driver that uses the native PHP $_SESSION array through the Session driver library.
+ *
+ * @package CodeIgniter
+ * @subpackage Libraries
+ * @category Sessions
+ * @author EllisLab Dev Team
+ */
+class CI_Session_native extends CI_Session_driver {
+
+ /**
+ * Initialize session driver object
+ *
+ * @return void
+ */
+ protected function initialize()
+ {
+ // Get config parameters
+ $config = array();
+ $prefs = array(
+ 'sess_cookie_name',
+ 'sess_expire_on_close',
+ 'sess_expiration',
+ 'sess_match_ip',
+ 'sess_match_useragent',
+ 'sess_time_to_update',
+ 'cookie_prefix',
+ 'cookie_path',
+ 'cookie_domain',
+ 'cookie_secure',
+ 'cookie_httponly'
+ );
+
+ foreach ($prefs as $key)
+ {
+ $config[$key] = isset($this->_parent->params[$key])
+ ? $this->_parent->params[$key]
+ : $this->CI->config->item($key);
+ }
+
+ // Set session name, if specified
+ if ($config['sess_cookie_name'])
+ {
+ // Differentiate name from cookie driver with '_id' suffix
+ $name = $config['sess_cookie_name'].'_id';
+ if ($config['cookie_prefix'])
+ {
+ // Prepend cookie prefix
+ $name = $config['cookie_prefix'].$name;
+ }
+ session_name($name);
+ }
+
+ // Set expiration, path, and domain
+ $expire = 7200;
+ $path = '/';
+ $domain = '';
+ $secure = (bool) $config['cookie_secure'];
+ $http_only = (bool) $config['cookie_httponly'];
+
+ if ($config['sess_expiration'] !== FALSE)
+ {
+ // Default to 2 years if expiration is "0"
+ $expire = ($config['sess_expiration'] == 0) ? (60*60*24*365*2) : $config['sess_expiration'];
+ }
+
+ if ($config['cookie_path'])
+ {
+ // Use specified path
+ $path = $config['cookie_path'];
+ }
+
+ if ($config['cookie_domain'])
+ {
+ // Use specified domain
+ $domain = $config['cookie_domain'];
+ }
+
+ session_set_cookie_params($config['sess_expire_on_close'] ? 0 : $expire, $path, $domain, $secure, $http_only);
+
+ // Start session
+ session_start();
+
+ // Check session expiration, ip, and agent
+ $now = time();
+ $destroy = FALSE;
+ if (isset($_SESSION['last_activity']) && (($_SESSION['last_activity'] + $expire) < $now OR $_SESSION['last_activity'] > $now))
+ {
+ // Expired - destroy
+ $destroy = TRUE;
+ }
+ elseif ($config['sess_match_ip'] === TRUE && isset($_SESSION['ip_address'])
+ && $_SESSION['ip_address'] !== $this->CI->input->ip_address())
+ {
+ // IP doesn't match - destroy
+ $destroy = TRUE;
+ }
+ elseif ($config['sess_match_useragent'] === TRUE && isset($_SESSION['user_agent'])
+ && $_SESSION['user_agent'] !== trim(substr($this->CI->input->user_agent(), 0, 50)))
+ {
+ // Agent doesn't match - destroy
+ $destroy = TRUE;
+ }
+
+ // Destroy expired or invalid session
+ if ($destroy)
+ {
+ // Clear old session and start new
+ $this->sess_destroy();
+ session_start();
+ }
+
+ // Check for update time
+ if ($config['sess_time_to_update'] && isset($_SESSION['last_activity'])
+ && ($_SESSION['last_activity'] + $config['sess_time_to_update']) < $now)
+ {
+ // Changing the session ID amidst a series of AJAX calls causes problems
+ if( ! $this->CI->input->is_ajax_request())
+ {
+ // Regenerate ID, but don't destroy session
+ $this->sess_regenerate(FALSE);
+ }
+ }
+
+ // Set activity time
+ $_SESSION['last_activity'] = $now;
+
+ // Set matching values as required
+ if ($config['sess_match_ip'] === TRUE && ! isset($_SESSION['ip_address']))
+ {
+ // Store user IP address
+ $_SESSION['ip_address'] = $this->CI->input->ip_address();
+ }
+
+ if ($config['sess_match_useragent'] === TRUE && ! isset($_SESSION['user_agent']))
+ {
+ // Store user agent string
+ $_SESSION['user_agent'] = trim(substr($this->CI->input->user_agent(), 0, 50));
+ }
+
+ // Make session ID available
+ $_SESSION['session_id'] = session_id();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Save the session data
+ *
+ * @return void
+ */
+ public function sess_save()
+ {
+ // Nothing to do - changes to $_SESSION are automatically saved
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Destroy the current session
+ *
+ * @return void
+ */
+ public function sess_destroy()
+ {
+ // Cleanup session
+ $_SESSION = array();
+ $name = session_name();
+ if (isset($_COOKIE[$name]))
+ {
+ // Clear session cookie
+ $params = session_get_cookie_params();
+ setcookie($name, '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
+ unset($_COOKIE[$name]);
+ }
+ session_destroy();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Regenerate the current session
+ *
+ * Regenerate the session id
+ *
+ * @param bool Destroy session data flag (default: FALSE)
+ * @return void
+ */
+ public function sess_regenerate($destroy = FALSE)
+ {
+ // Just regenerate id, passing destroy flag
+ session_regenerate_id($destroy);
+ $_SESSION['session_id'] = session_id();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Get a reference to user data array
+ *
+ * @return array Reference to userdata
+ */
+ public function &get_userdata()
+ {
+ // Just return reference to $_SESSION
+ return $_SESSION;
+ }
+
+}
+
+/* End of file Session_native.php */
+/* Location: ./system/libraries/Session/drivers/Session_native.php */ \ No newline at end of file
diff --git a/system/libraries/Trackback.php b/system/libraries/Trackback.php
index 9a680dc2a..7bd7cba04 100644
--- a/system/libraries/Trackback.php
+++ b/system/libraries/Trackback.php
@@ -45,6 +45,11 @@ class CI_Trackback {
public $response = '';
public $error_msg = array();
+ /**
+ * Constructor
+ *
+ * @return void
+ */
public function __construct()
{
log_message('debug', 'Trackback Class Initialized');
diff --git a/system/libraries/Unit_test.php b/system/libraries/Unit_test.php
index 70ad8dc41..7b99dee0d 100644
--- a/system/libraries/Unit_test.php
+++ b/system/libraries/Unit_test.php
@@ -38,13 +38,18 @@
*/
class CI_Unit_test {
- public $active = TRUE;
- public $results = array();
- public $strict = FALSE;
- protected $_template = NULL;
- protected $_template_rows = NULL;
+ public $active = TRUE;
+ public $results = array();
+ public $strict = FALSE;
+ protected $_template = NULL;
+ protected $_template_rows = NULL;
protected $_test_items_visible = array();
+ /**
+ * Constructor
+ *
+ * @return void
+ */
public function __construct()
{
// These are the default items visible when a test is run.
@@ -86,9 +91,10 @@ class CI_Unit_test {
*
* Runs the supplied tests
*
- * @param mixed
- * @param mixed
- * @param string
+ * @param mixed $test
+ * @param mixed $expected = TRUE
+ * @param string $test_name = 'undefined'
+ * @param string $notes = ''
* @return string
*/
public function run($test, $expected = TRUE, $test_name = 'undefined', $notes = '')
@@ -134,6 +140,7 @@ class CI_Unit_test {
*
* Displays a table with the test data
*
+ * @param array $result = array()
* @return string
*/
public function report($result = array())
@@ -213,6 +220,7 @@ class CI_Unit_test {
*
* Returns the raw result data
*
+ * @param array $results = array()
* @return array
*/
public function result($results = array())
@@ -240,6 +248,11 @@ class CI_Unit_test {
{
foreach ($val as $k => $v)
{
+ if ( ! in_array($k, $this->_test_items_visible))
+ {
+ continue;
+ }
+
if (FALSE !== ($line = $CI->lang->line(strtolower('ut_'.$v))))
{
$v = $line;
@@ -340,14 +353,22 @@ class CI_Unit_test {
}
/**
- * Helper functions to test boolean true/false
+ * Helper function to test boolean TRUE
*
+ * @param mixed $test
* @return bool
*/
function is_true($test)
{
return ($test === TRUE);
}
+
+/**
+ * Helper function to test boolean FALSE
+ *
+ * @param mixed $test
+ * @return bool
+ */
function is_false($test)
{
return ($test === FALSE);
diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php
index d381440cd..76bbc244e 100644
--- a/system/libraries/Upload.php
+++ b/system/libraries/Upload.php
@@ -154,6 +154,7 @@ class CI_Upload {
/**
* Perform the file upload
*
+ * @param string $field = 'userfile'
* @return bool
*/
public function do_upload($field = 'userfile')
@@ -790,7 +791,8 @@ class CI_Upload {
/**
* Limit the File Name Length
*
- * @param string
+ * @param string $filename
+ * @param int $length
* @return string
*/
public function limit_filename_length($filename, $length)
diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php
index cbb91c40a..3ed050a2e 100644..100755
--- a/system/libraries/Xmlrpc.php
+++ b/system/libraries/Xmlrpc.php
@@ -170,8 +170,10 @@ class CI_Xmlrpc {
/**
* Parse server URL
*
- * @param string url
- * @param int port
+ * @param string $url
+ * @param int $port = 80
+ * @param string $proxy = FALSE
+ * @param int $proxy_port = 8080
* @return void
*/
public function server($url, $port = 80, $proxy = FALSE, $proxy_port = 8080)
@@ -395,9 +397,11 @@ class XML_RPC_Client extends CI_Xmlrpc
/**
* Constructor
*
- * @param string
- * @param object
- * @param int
+ * @param string $path
+ * @param object $server
+ * @param int $port = 80
+ * @param string $proxy = FALSE
+ * @param int $proxy_port = 8080
* @return void
*/
public function __construct($path, $server, $port = 80, $proxy = FALSE, $proxy_port = 8080)
@@ -1317,15 +1321,15 @@ class XML_RPC_Values extends CI_Xmlrpc
{
$type = $type === '' ? 'string' : $type;
- if ($this->xmlrpcTypes[$type] === 1)
+ if ($this->xmlrpcTypes[$type] == 1)
{
$this->addScalar($val,$type);
}
- elseif ($this->xmlrpcTypes[$type] === 2)
+ elseif ($this->xmlrpcTypes[$type] == 2)
{
$this->addArray($val);
}
- elseif ($this->xmlrpcTypes[$type] === 3)
+ elseif ($this->xmlrpcTypes[$type] == 3)
{
$this->addStruct($val);
}
@@ -1351,7 +1355,7 @@ class XML_RPC_Values extends CI_Xmlrpc
return 0;
}
- if ($typeof !== 1)
+ if ($typeof != 1)
{
echo '<strong>XML_RPC_Values</strong>: not a scalar type (${typeof})<br />';
return 0;
@@ -1359,7 +1363,7 @@ class XML_RPC_Values extends CI_Xmlrpc
if ($type === $this->xmlrpcBoolean)
{
- $val = (int) (strcasecmp($val,'true') === 0 OR $val === 1 OR ($val === TRUE && strcasecmp($val, 'false')));
+ $val = (int) (strcasecmp($val, 'true') === 0 OR $val === 1 OR ($val === TRUE && strcasecmp($val, 'false')));
}
if ($this->mytype === 2)
diff --git a/system/libraries/javascript/Jquery.php b/system/libraries/javascript/Jquery.php
index 44c16b578..8739d141f 100644
--- a/system/libraries/javascript/Jquery.php
+++ b/system/libraries/javascript/Jquery.php
@@ -34,7 +34,6 @@
* @author EllisLab Dev Team
* @link http://codeigniter.com/user_guide/libraries/javascript.html
*/
-
class CI_Jquery extends CI_Javascript {
protected $_javascript_folder = 'js';
@@ -45,6 +44,12 @@ class CI_Jquery extends CI_Javascript {
public $jquery_table_sorter_pager_active = FALSE;
public $jquery_ajax_img = '';
+ /**
+ * Constructor
+ *
+ * @param array $params
+ * @return void
+ */
public function __construct($params)
{
$this->CI =& get_instance();
@@ -101,15 +106,12 @@ class CI_Jquery extends CI_Javascript {
*
* @param string The element to attach the event to
* @param string The code to execute
- * @param boolean whether or not to return false
+ * @param bool whether or not to return false
* @return string
*/
protected function _click($element = 'this', $js = '', $ret_false = TRUE)
{
- if ( ! is_array($js))
- {
- $js = array($js);
- }
+ is_array($js) OR $js = array($js);
if ($ret_false)
{
@@ -307,11 +309,10 @@ class CI_Jquery extends CI_Javascript {
*
* Outputs script directly
*
- * @param string The element to attach the event to
- * @param string The code to execute
- * @return string
+ * @param array $array_js = array()
+ * @return void
*/
- protected function _output($array_js = '')
+ protected function _output($array_js = array())
{
if ( ! is_array($array_js))
{
@@ -381,10 +382,11 @@ class CI_Jquery extends CI_Javascript {
*
* Outputs a jQuery addClass event
*
- * @param string - element
+ * @param string $element = 'this'
+ * @param string $class = ''
* @return string
*/
- protected function _addClass($element = 'this', $class='')
+ protected function _addClass($element = 'this', $class = '')
{
$element = $this->_prep_element($element);
return '$('.$element.').addClass("'.$class.'");';
@@ -397,9 +399,10 @@ class CI_Jquery extends CI_Javascript {
*
* Outputs a jQuery animate event
*
- * @param string - element
- * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
- * @param string - Javascript callback function
+ * @param string $element = 'this'
+ * @param array $params = array()
+ * @param string $speed = '' 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string $extra = ''
* @return string
*/
protected function _animate($element = 'this', $params = array(), $speed = '', $extra = '')
@@ -511,10 +514,11 @@ class CI_Jquery extends CI_Javascript {
*
* Outputs a jQuery remove class event
*
- * @param string - element
+ * @param string $element = 'this'
+ * @param string $class = ''
* @return string
*/
- protected function _removeClass($element = 'this', $class='')
+ protected function _removeClass($element = 'this', $class = '')
{
$element = $this->_prep_element($element);
return '$('.$element.').removeClass("'.$class.'");';
@@ -618,10 +622,11 @@ class CI_Jquery extends CI_Javascript {
*
* Outputs a jQuery toggle class event
*
- * @param string - element
+ * @param string $element = 'this'
+ * @param string $class = ''
* @return string
*/
- protected function _toggleClass($element = 'this', $class='')
+ protected function _toggleClass($element = 'this', $class = '')
{
$element = $this->_prep_element($element);
return '$('.$element.').toggleClass("'.$class.'");';
@@ -703,8 +708,9 @@ class CI_Jquery extends CI_Javascript {
/**
* Zebra tables
*
- * @param string table name
- * @param string plugin location
+ * @param string $class = ''
+ * @param string $odd = 'odd'
+ * @param string $hover = ''
* @return string
*/
protected function _zebraTables($class = '', $odd = 'odd', $hover = '')
@@ -731,7 +737,8 @@ class CI_Jquery extends CI_Javascript {
*
* http://www.malsup.com/jquery/corner/
*
- * @param string target
+ * @param string $element = ''
+ * @param string $corner_style = ''
* @return string
*/
public function corner($element = '', $corner_style = '')
@@ -750,10 +757,12 @@ class CI_Jquery extends CI_Javascript {
// --------------------------------------------------------------------
/**
- * modal window
+ * Modal window
*
* Load a thickbox modal window
*
+ * @param string $src
+ * @param bool $relative = FALSE
* @return void
*/
public function modal($src, $relative = FALSE)
@@ -768,6 +777,8 @@ class CI_Jquery extends CI_Javascript {
*
* Load an Effect library
*
+ * @param string $src
+ * @param bool $relative = FALSE
* @return void
*/
public function effect($src, $relative = FALSE)
@@ -782,6 +793,8 @@ class CI_Jquery extends CI_Javascript {
*
* Load a plugin library
*
+ * @param string $src
+ * @param bool $relative = FALSE
* @return void
*/
public function plugin($src, $relative = FALSE)
@@ -796,12 +809,15 @@ class CI_Jquery extends CI_Javascript {
*
* Load a user interface library
*
+ * @param string $src
+ * @param bool $relative = FALSE
* @return void
*/
public function ui($src, $relative = FALSE)
{
$this->jquery_code_for_load[] = $this->external($src, $relative);
}
+
// --------------------------------------------------------------------
/**
@@ -809,11 +825,12 @@ class CI_Jquery extends CI_Javascript {
*
* Creates a jQuery sortable
*
- * @return void
+ * @param string $element
+ * @param array $options = array()
+ * @return string
*/
public function sortable($element, $options = array())
{
-
if (count($options) > 0)
{
$sort_options = array();
@@ -880,7 +897,9 @@ class CI_Jquery extends CI_Javascript {
* As events are specified, they are stored in an array
* This funciton compiles them all for output on a page
*
- * @return string
+ * @param string $view_var = 'script_foot'
+ * @param bool $script_tags = TRUE
+ * @return void
*/
protected function _compile($view_var = 'script_foot', $script_tags = TRUE)
{
@@ -902,7 +921,6 @@ class CI_Jquery extends CI_Javascript {
$output = ($script_tags === FALSE) ? $script : $this->inline($script);
$this->CI->load->vars(array($view_var => $output));
-
}
// --------------------------------------------------------------------
@@ -926,14 +944,12 @@ class CI_Jquery extends CI_Javascript {
*
* A wrapper for writing document.ready()
*
- * @return string
+ * @param array $js
+ * @return void
*/
protected function _document_ready($js)
{
- if ( ! is_array($js))
- {
- $js = array($js);
- }
+ is_array($js) OR $js = array($js);
foreach ($js as $script)
{
@@ -948,7 +964,8 @@ class CI_Jquery extends CI_Javascript {
*
* Outputs the script tag that loads the jquery.js file into an HTML document
*
- * @param string
+ * @param string $library_src = ''
+ * @param bool $relative = FALSE
* @return string
*/
public function script($library_src = '', $relative = FALSE)