mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-05-24 16:28:40 -04:00
Update to Code Igniter 3.1.0 (#782)
This commit is contained in:
@@ -72,6 +72,12 @@ $autoload['libraries'] = array('database', 'form_validation', 'session', 'user_a
|
||||
| Prototype:
|
||||
|
|
||||
| $autoload['drivers'] = array('cache');
|
||||
|
|
||||
| You can also supply an alternative property name to be assigned in
|
||||
| the controller:
|
||||
|
|
||||
| $autoload['drivers'] = array('cache' => 'cch');
|
||||
|
|
||||
*/
|
||||
$autoload['drivers'] = array();
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ defined('DIR_WRITE_MODE') OR define('DIR_WRITE_MODE', 0755);
|
||||
defined('FOPEN_READ') OR define('FOPEN_READ', 'rb');
|
||||
defined('FOPEN_READ_WRITE') OR define('FOPEN_READ_WRITE', 'r+b');
|
||||
defined('FOPEN_WRITE_CREATE_DESTRUCTIVE') OR define('FOPEN_WRITE_CREATE_DESTRUCTIVE', 'wb'); // truncates existing file data, use with care
|
||||
defined('FOPEN_READ_WRITE_CREATE_DESCTRUCTIVE') OR define('FOPEN_READ_WRITE_CREATE_DESTRUCTIVE', 'w+b'); // truncates existing file data, use with care
|
||||
defined('FOPEN_READ_WRITE_CREATE_DESTRUCTIVE') OR define('FOPEN_READ_WRITE_CREATE_DESTRUCTIVE', 'w+b'); // truncates existing file data, use with care
|
||||
defined('FOPEN_WRITE_CREATE') OR define('FOPEN_WRITE_CREATE', 'ab');
|
||||
defined('FOPEN_READ_WRITE_CREATE') OR define('FOPEN_READ_WRITE_CREATE', 'a+b');
|
||||
defined('FOPEN_WRITE_CREATE_STRICT') OR define('FOPEN_WRITE_CREATE_STRICT', 'xb');
|
||||
|
||||
@@ -207,5 +207,8 @@ $robots = array(
|
||||
'CRAZYWEBCRAWLER' => 'Crazy Webcrawler',
|
||||
'adsbot-google' => 'AdsBot Google',
|
||||
'feedfetcher-google' => 'Feedfetcher Google',
|
||||
'curious george' => 'Curious George'
|
||||
'curious george' => 'Curious George',
|
||||
'ia_archiver' => 'Alexa Crawler',
|
||||
'MJ12bot' => 'Majestic-12',
|
||||
'Uptimebot' => 'Uptimebot'
|
||||
);
|
||||
|
||||
@@ -1 +1 @@
|
||||
Code Igniter 3.0.6
|
||||
Code Igniter 3.1.0
|
||||
@@ -55,7 +55,7 @@ defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
* @var string
|
||||
*
|
||||
*/
|
||||
define('CI_VERSION', '3.0.6');
|
||||
define('CI_VERSION', '3.1.0');
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------
|
||||
|
||||
@@ -355,7 +355,7 @@ if ( ! function_exists('is_https'))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
|
||||
elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https')
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
@@ -716,8 +716,8 @@ if ( ! function_exists('remove_invisible_characters'))
|
||||
// carriage return (dec 13) and horizontal tab (dec 09)
|
||||
if ($url_encoded)
|
||||
{
|
||||
$non_displayables[] = '/%0[0-8bcef]/'; // url encoded 00-08, 11, 12, 14, 15
|
||||
$non_displayables[] = '/%1[0-9a-f]/'; // url encoded 16-31
|
||||
$non_displayables[] = '/%0[0-8bcef]/i'; // url encoded 00-08, 11, 12, 14, 15
|
||||
$non_displayables[] = '/%1[0-9a-f]/i'; // url encoded 16-31
|
||||
}
|
||||
|
||||
$non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127
|
||||
|
||||
@@ -319,7 +319,7 @@ class CI_Config {
|
||||
}
|
||||
}
|
||||
|
||||
return $base_url.ltrim($this->_uri_string($uri), '/');
|
||||
return $base_url.$this->_uri_string($uri);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
@@ -337,11 +337,8 @@ class CI_Config {
|
||||
{
|
||||
if ($this->item('enable_query_strings') === FALSE)
|
||||
{
|
||||
if (is_array($uri))
|
||||
{
|
||||
$uri = implode('/', $uri);
|
||||
}
|
||||
return trim($uri, '/');
|
||||
is_array($uri) && $uri = implode('/', $uri);
|
||||
return ltrim($uri, '/');
|
||||
}
|
||||
elseif (is_array($uri))
|
||||
{
|
||||
|
||||
@@ -519,9 +519,9 @@ class CI_Input {
|
||||
if ($separator === ':')
|
||||
{
|
||||
$netaddr = explode(':', str_replace('::', str_repeat(':', 9 - substr_count($netaddr, ':')), $netaddr));
|
||||
for ($i = 0; $i < 8; $i++)
|
||||
for ($j = 0; $j < 8; $j++)
|
||||
{
|
||||
$netaddr[$i] = intval($netaddr[$i], 16);
|
||||
$netaddr[$i] = intval($netaddr[$j], 16);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -760,30 +760,32 @@ class CI_Input {
|
||||
// If header is already defined, return it immediately
|
||||
if ( ! empty($this->headers))
|
||||
{
|
||||
return $this->headers;
|
||||
return $this->_fetch_from_array($this->headers, NULL, $xss_clean);
|
||||
}
|
||||
|
||||
// In Apache, you can simply call apache_request_headers()
|
||||
if (function_exists('apache_request_headers'))
|
||||
{
|
||||
return $this->headers = apache_request_headers();
|
||||
$this->headers = apache_request_headers();
|
||||
}
|
||||
|
||||
$this->headers['Content-Type'] = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE');
|
||||
|
||||
foreach ($_SERVER as $key => $val)
|
||||
else
|
||||
{
|
||||
if (sscanf($key, 'HTTP_%s', $header) === 1)
|
||||
{
|
||||
// take SOME_HEADER and turn it into Some-Header
|
||||
$header = str_replace('_', ' ', strtolower($header));
|
||||
$header = str_replace(' ', '-', ucwords($header));
|
||||
isset($_SERVER['CONTENT_TYPE']) && $this->headers['Content-Type'] = $_SERVER['CONTENT_TYPE'];
|
||||
|
||||
$this->headers[$header] = $this->_fetch_from_array($_SERVER, $key, $xss_clean);
|
||||
foreach ($_SERVER as $key => $val)
|
||||
{
|
||||
if (sscanf($key, 'HTTP_%s', $header) === 1)
|
||||
{
|
||||
// take SOME_HEADER and turn it into Some-Header
|
||||
$header = str_replace('_', ' ', strtolower($header));
|
||||
$header = str_replace(' ', '-', ucwords($header));
|
||||
|
||||
$this->headers[$header] = $_SERVER[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->headers;
|
||||
return $this->_fetch_from_array($this->headers, NULL, $xss_clean);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -1106,7 +1106,7 @@ class CI_Loader {
|
||||
* @used-by CI_Loader::_ci_load_library()
|
||||
* @uses CI_Loader::_ci_init_library()
|
||||
*
|
||||
* @param string $library Library name to load
|
||||
* @param string $library_name Library name to load
|
||||
* @param string $file_path Path to the library filename, relative to libraries/
|
||||
* @param mixed $params Optional parameters to pass to the class constructor
|
||||
* @param string $object_name Optional object name to assign to
|
||||
|
||||
@@ -237,7 +237,7 @@ class CI_Log {
|
||||
*
|
||||
* @param string $level The error level
|
||||
* @param string $date Formatted date string
|
||||
* @param string $msg The log message
|
||||
* @param string $message The log message
|
||||
* @return string Formatted log line with a new line character '\n' at the end
|
||||
*/
|
||||
protected function _format_line($level, $date, $message)
|
||||
|
||||
@@ -285,7 +285,7 @@ class CI_Output {
|
||||
/**
|
||||
* Get Header
|
||||
*
|
||||
* @param string $header_name
|
||||
* @param string $header
|
||||
* @return string
|
||||
*/
|
||||
public function get_header($header)
|
||||
|
||||
@@ -116,14 +116,22 @@ if ( ! function_exists('password_hash'))
|
||||
}
|
||||
elseif ( ! isset($options['salt']))
|
||||
{
|
||||
if (defined('MCRYPT_DEV_URANDOM'))
|
||||
if (function_exists('random_bytes'))
|
||||
{
|
||||
try
|
||||
{
|
||||
$options['salt'] = random_bytes(16);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
log_message('error', 'compat/password: Error while trying to use random_bytes(): '.$e->getMessage());
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
elseif (defined('MCRYPT_DEV_URANDOM'))
|
||||
{
|
||||
$options['salt'] = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
|
||||
}
|
||||
elseif (function_exists('openssl_random_pseudo_bytes'))
|
||||
{
|
||||
$options['salt'] = openssl_random_pseudo_bytes(16);
|
||||
}
|
||||
elseif (DIRECTORY_SEPARATOR === '/' && (is_readable($dev = '/dev/arandom') OR is_readable($dev = '/dev/urandom')))
|
||||
{
|
||||
if (($fp = fopen($dev, 'rb')) === FALSE)
|
||||
@@ -148,6 +156,16 @@ if ( ! function_exists('password_hash'))
|
||||
|
||||
fclose($fp);
|
||||
}
|
||||
elseif (function_exists('openssl_random_pseudo_bytes'))
|
||||
{
|
||||
$is_secure = NULL;
|
||||
$options['salt'] = openssl_random_pseudo_bytes(16, $is_secure);
|
||||
if ($is_secure !== TRUE)
|
||||
{
|
||||
log_message('error', 'compat/password: openssl_random_pseudo_bytes() set the $cryto_strong flag to FALSE');
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_message('error', 'compat/password: No CSPRNG available.');
|
||||
|
||||
@@ -62,7 +62,7 @@ if ( ! function_exists('array_column'))
|
||||
* array_column()
|
||||
*
|
||||
* @link http://php.net/array_column
|
||||
* @param string $array
|
||||
* @param array $array
|
||||
* @param mixed $column_key
|
||||
* @param mixed $index_key
|
||||
* @return array
|
||||
|
||||
@@ -1395,7 +1395,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
|
||||
$this->qb_orderby = NULL;
|
||||
}
|
||||
|
||||
$result = ($this->qb_distinct === TRUE)
|
||||
$result = ($this->qb_distinct === TRUE OR ! empty($this->qb_groupby))
|
||||
? $this->query($this->_count_string.$this->protect_identifiers('numrows')."\nFROM (\n".$this->_compile_select()."\n) CI_count_all_results")
|
||||
: $this->query($this->_compile_select($this->_count_string.$this->protect_identifiers('numrows')));
|
||||
|
||||
@@ -1498,8 +1498,10 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
|
||||
$affected_rows = 0;
|
||||
for ($i = 0, $total = count($this->qb_set); $i < $total; $i += $batch_size)
|
||||
{
|
||||
$this->query($this->_insert_batch($this->protect_identifiers($table, TRUE, $escape, FALSE), $this->qb_keys, array_slice($this->qb_set, $i, $batch_size)));
|
||||
$affected_rows += $this->affected_rows();
|
||||
if ($this->query($this->_insert_batch($this->protect_identifiers($table, TRUE, $escape, FALSE), $this->qb_keys, array_slice($this->qb_set, $i, $batch_size))))
|
||||
{
|
||||
$affected_rows += $this->affected_rows();
|
||||
}
|
||||
}
|
||||
|
||||
$this->_reset_write();
|
||||
@@ -1913,8 +1915,11 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
|
||||
$affected_rows = 0;
|
||||
for ($i = 0, $total = count($this->qb_set); $i < $total; $i += $batch_size)
|
||||
{
|
||||
$this->query($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->qb_set, $i, $batch_size), $this->protect_identifiers($index)));
|
||||
$affected_rows += $this->affected_rows();
|
||||
if ($this->query($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->qb_set, $i, $batch_size), $this->protect_identifiers($index))))
|
||||
{
|
||||
$affected_rows += $this->affected_rows();
|
||||
}
|
||||
|
||||
$this->qb_where = array();
|
||||
}
|
||||
|
||||
|
||||
@@ -178,6 +178,9 @@ class CI_DB_cubrid_forge extends CI_DB_forge {
|
||||
$attributes['TYPE'] = 'INTEGER';
|
||||
$attributes['UNSIGNED'] = FALSE;
|
||||
return;
|
||||
case 'LONGTEXT':
|
||||
$attributes['TYPE'] = 'STRING';
|
||||
return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +158,7 @@ class CI_DB_mssql_driver extends CI_DB {
|
||||
if (mssql_select_db('['.$database.']', $this->conn_id))
|
||||
{
|
||||
$this->database = $database;
|
||||
$this->data_cache = array();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +113,11 @@ class CI_DB_mssql_forge extends CI_DB_forge {
|
||||
*/
|
||||
protected function _attr_type(&$attributes)
|
||||
{
|
||||
if (isset($attributes['CONSTRAINT']) && strpos($attributes['TYPE'], 'INT') !== FALSE)
|
||||
{
|
||||
unset($attributes['CONSTRAINT']);
|
||||
}
|
||||
|
||||
switch (strtoupper($attributes['TYPE']))
|
||||
{
|
||||
case 'MEDIUMINT':
|
||||
|
||||
@@ -208,6 +208,7 @@ class CI_DB_mysql_driver extends CI_DB {
|
||||
if (mysql_select_db($database, $this->conn_id))
|
||||
{
|
||||
$this->database = $database;
|
||||
$this->data_cache = array();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -256,6 +256,7 @@ class CI_DB_mysqli_driver extends CI_DB {
|
||||
if ($this->conn_id->select_db($database))
|
||||
{
|
||||
$this->database = $database;
|
||||
$this->data_cache = array();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -559,23 +559,29 @@ class CI_DB_oci8_driver extends CI_DB {
|
||||
*/
|
||||
public function error()
|
||||
{
|
||||
/* oci_error() returns an array that already contains the
|
||||
* 'code' and 'message' keys, so we can just return it.
|
||||
*/
|
||||
// oci_error() returns an array that already contains
|
||||
// 'code' and 'message' keys, but it can return false
|
||||
// if there was no error ....
|
||||
if (is_resource($this->curs_id))
|
||||
{
|
||||
return oci_error($this->curs_id);
|
||||
$error = oci_error($this->curs_id);
|
||||
}
|
||||
elseif (is_resource($this->stmt_id))
|
||||
{
|
||||
return oci_error($this->stmt_id);
|
||||
$error = oci_error($this->stmt_id);
|
||||
}
|
||||
elseif (is_resource($this->conn_id))
|
||||
{
|
||||
return oci_error($this->conn_id);
|
||||
$error = oci_error($this->conn_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
$error = oci_error();
|
||||
}
|
||||
|
||||
return oci_error();
|
||||
return is_array($error)
|
||||
? $error
|
||||
: array('code' => '', 'message' => '');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -53,6 +53,13 @@ class CI_DB_oci8_forge extends CI_DB_forge {
|
||||
*/
|
||||
protected $_create_database = FALSE;
|
||||
|
||||
/**
|
||||
* CREATE TABLE IF statement
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_create_table_if = FALSE;
|
||||
|
||||
/**
|
||||
* DROP DATABASE statement
|
||||
*
|
||||
@@ -146,4 +153,33 @@ class CI_DB_oci8_forge extends CI_DB_forge {
|
||||
// Not supported - sequences and triggers must be used instead
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Field attribute TYPE
|
||||
*
|
||||
* Performs a data type mapping between different databases.
|
||||
*
|
||||
* @param array &$attributes
|
||||
* @return void
|
||||
*/
|
||||
protected function _attr_type(&$attributes)
|
||||
{
|
||||
switch (strtoupper($attributes['TYPE']))
|
||||
{
|
||||
case 'TINYINT':
|
||||
$attributes['TYPE'] = 'NUMBER';
|
||||
return;
|
||||
case 'MEDIUMINT':
|
||||
$attributes['TYPE'] = 'NUMBER';
|
||||
return;
|
||||
case 'INT':
|
||||
$attributes['TYPE'] = 'NUMBER';
|
||||
return;
|
||||
case 'BIGINT':
|
||||
$attributes['TYPE'] = 'NUMBER';
|
||||
return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/user_guide/database/
|
||||
*/
|
||||
class CI_DB_odbc_driver extends CI_DB {
|
||||
class CI_DB_odbc_driver extends CI_DB_driver {
|
||||
|
||||
/**
|
||||
* Database driver
|
||||
@@ -93,6 +93,22 @@ class CI_DB_odbc_driver extends CI_DB {
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* ODBC result ID resource returned from odbc_prepare()
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
private $odbc_result;
|
||||
|
||||
/**
|
||||
* Values to use with odbc_execute() for prepared statements
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $binds = array();
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
@@ -127,6 +143,74 @@ class CI_DB_odbc_driver extends CI_DB {
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compile Bindings
|
||||
*
|
||||
* @param string $sql SQL statement
|
||||
* @param array $binds An array of values to bind
|
||||
* @return string
|
||||
*/
|
||||
public function compile_binds($sql, $binds)
|
||||
{
|
||||
if (empty($binds) OR empty($this->bind_marker) OR strpos($sql, $this->bind_marker) === FALSE)
|
||||
{
|
||||
return $sql;
|
||||
}
|
||||
elseif ( ! is_array($binds))
|
||||
{
|
||||
$binds = array($binds);
|
||||
$bind_count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure we're using numeric keys
|
||||
$binds = array_values($binds);
|
||||
$bind_count = count($binds);
|
||||
}
|
||||
|
||||
// We'll need the marker length later
|
||||
$ml = strlen($this->bind_marker);
|
||||
|
||||
// Make sure not to replace a chunk inside a string that happens to match the bind marker
|
||||
if ($c = preg_match_all("/'[^']*'/i", $sql, $matches))
|
||||
{
|
||||
$c = preg_match_all('/'.preg_quote($this->bind_marker, '/').'/i',
|
||||
str_replace($matches[0],
|
||||
str_replace($this->bind_marker, str_repeat(' ', $ml), $matches[0]),
|
||||
$sql, $c),
|
||||
$matches, PREG_OFFSET_CAPTURE);
|
||||
|
||||
// Bind values' count must match the count of markers in the query
|
||||
if ($bind_count !== $c)
|
||||
{
|
||||
return $sql;
|
||||
}
|
||||
}
|
||||
elseif (($c = preg_match_all('/'.preg_quote($this->bind_marker, '/').'/i', $sql, $matches, PREG_OFFSET_CAPTURE)) !== $bind_count)
|
||||
{
|
||||
return $sql;
|
||||
}
|
||||
|
||||
if ($this->bind_marker !== '?')
|
||||
{
|
||||
do
|
||||
{
|
||||
$c--;
|
||||
$sql = substr_replace($sql, '?', $matches[0][$c][1], $ml);
|
||||
}
|
||||
while ($c !== 0);
|
||||
}
|
||||
|
||||
if (FALSE !== ($this->odbc_result = odbc_prepare($this->conn_id, $sql)))
|
||||
{
|
||||
$this->binds = array_values($binds);
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Execute the query
|
||||
*
|
||||
@@ -135,7 +219,25 @@ class CI_DB_odbc_driver extends CI_DB {
|
||||
*/
|
||||
protected function _execute($sql)
|
||||
{
|
||||
return odbc_exec($this->conn_id, $sql);
|
||||
if ( ! isset($this->odbc_result))
|
||||
{
|
||||
return odbc_exec($this->conn_id, $sql);
|
||||
}
|
||||
elseif ($this->odbc_result === FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (TRUE === ($success = odbc_execute($this->odbc_result, $this->binds)))
|
||||
{
|
||||
// For queries that return result sets, return the result_id resource on success
|
||||
$this->is_write_type($sql) OR $success = $this->odbc_result;
|
||||
}
|
||||
|
||||
$this->odbc_result = NULL;
|
||||
$this->binds = array();
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -214,7 +316,7 @@ class CI_DB_odbc_driver extends CI_DB {
|
||||
*/
|
||||
protected function _escape_str($str)
|
||||
{
|
||||
return remove_invisible_characters($str);
|
||||
$this->db->display_error('db_unsupported_feature');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -311,58 +413,6 @@ class CI_DB_odbc_driver extends CI_DB {
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Update statement
|
||||
*
|
||||
* Generates a platform-specific update string from the supplied data
|
||||
*
|
||||
* @param string $table
|
||||
* @param array $values
|
||||
* @return string
|
||||
*/
|
||||
protected function _update($table, $values)
|
||||
{
|
||||
$this->qb_limit = FALSE;
|
||||
$this->qb_orderby = array();
|
||||
return parent::_update($table, $values);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Truncate statement
|
||||
*
|
||||
* Generates a platform-specific truncate string from the supplied data
|
||||
*
|
||||
* If the database does not support the TRUNCATE statement,
|
||||
* then this method maps to 'DELETE FROM table'
|
||||
*
|
||||
* @param string $table
|
||||
* @return string
|
||||
*/
|
||||
protected function _truncate($table)
|
||||
{
|
||||
return 'DELETE FROM '.$table;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Delete statement
|
||||
*
|
||||
* Generates a platform-specific delete string from the supplied data
|
||||
*
|
||||
* @param string $table
|
||||
* @return string
|
||||
*/
|
||||
protected function _delete($table)
|
||||
{
|
||||
$this->qb_limit = FALSE;
|
||||
return parent::_delete($table);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Close DB Connection
|
||||
*
|
||||
@@ -372,5 +422,4 @@ class CI_DB_odbc_driver extends CI_DB {
|
||||
{
|
||||
odbc_close($this->conn_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -126,7 +126,10 @@ class CI_DB_pdo_driver extends CI_DB {
|
||||
*/
|
||||
public function db_connect($persistent = FALSE)
|
||||
{
|
||||
$this->options[PDO::ATTR_PERSISTENT] = $persistent;
|
||||
if ($persistent === TRUE)
|
||||
{
|
||||
$this->options[PDO::ATTR_PERSISTENT] = TRUE;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -178,6 +178,9 @@ class CI_DB_pdo_cubrid_forge extends CI_DB_pdo_forge {
|
||||
$attributes['TYPE'] = 'INTEGER';
|
||||
$attributes['UNSIGNED'] = FALSE;
|
||||
return;
|
||||
case 'LONGTEXT':
|
||||
$attributes['TYPE'] = 'STRING';
|
||||
return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,12 @@ class CI_DB_pdo_dblib_driver extends CI_DB_pdo_driver {
|
||||
*/
|
||||
public function db_connect($persistent = FALSE)
|
||||
{
|
||||
$this->conn_id = parent::db_connect($persistent);
|
||||
if ($persistent === TRUE)
|
||||
{
|
||||
log_message('debug', "dblib driver doesn't support persistent connections");
|
||||
}
|
||||
|
||||
$this->conn_id = parent::db_connect(FALSE);
|
||||
|
||||
if ( ! is_object($this->conn_id))
|
||||
{
|
||||
|
||||
@@ -111,6 +111,11 @@ class CI_DB_pdo_dblib_forge extends CI_DB_pdo_forge {
|
||||
*/
|
||||
protected function _attr_type(&$attributes)
|
||||
{
|
||||
if (isset($attributes['CONSTRAINT']) && strpos($attributes['TYPE'], 'INT') !== FALSE)
|
||||
{
|
||||
unset($attributes['CONSTRAINT']);
|
||||
}
|
||||
|
||||
switch (strtoupper($attributes['TYPE']))
|
||||
{
|
||||
case 'MEDIUMINT':
|
||||
|
||||
@@ -218,6 +218,7 @@ class CI_DB_pdo_mysql_driver extends CI_DB_pdo_driver {
|
||||
if (FALSE !== $this->simple_query('USE '.$this->escape_identifiers($database)))
|
||||
{
|
||||
$this->database = $database;
|
||||
$this->data_cache = array();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,13 @@ class CI_DB_pdo_oci_forge extends CI_DB_pdo_forge {
|
||||
*/
|
||||
protected $_create_database = FALSE;
|
||||
|
||||
/**
|
||||
* CREATE TABLE IF statement
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_create_table_if = FALSE;
|
||||
|
||||
/**
|
||||
* DROP DATABASE statement
|
||||
*
|
||||
@@ -60,13 +67,6 @@ class CI_DB_pdo_oci_forge extends CI_DB_pdo_forge {
|
||||
*/
|
||||
protected $_drop_database = FALSE;
|
||||
|
||||
/**
|
||||
* CREATE TABLE IF statement
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_create_table_if = 'CREATE TABLE IF NOT EXISTS';
|
||||
|
||||
/**
|
||||
* UNSIGNED support
|
||||
*
|
||||
@@ -146,4 +146,31 @@ class CI_DB_pdo_oci_forge extends CI_DB_pdo_forge {
|
||||
// Not supported - sequences and triggers must be used instead
|
||||
}
|
||||
|
||||
/**
|
||||
* Field attribute TYPE
|
||||
*
|
||||
* Performs a data type mapping between different databases.
|
||||
*
|
||||
* @param array &$attributes
|
||||
* @return void
|
||||
*/
|
||||
protected function _attr_type(&$attributes)
|
||||
{
|
||||
switch (strtoupper($attributes['TYPE']))
|
||||
{
|
||||
case 'TINYINT':
|
||||
$attributes['TYPE'] = 'NUMBER';
|
||||
return;
|
||||
case 'MEDIUMINT':
|
||||
$attributes['TYPE'] = 'NUMBER';
|
||||
return;
|
||||
case 'INT':
|
||||
$attributes['TYPE'] = 'NUMBER';
|
||||
return;
|
||||
case 'BIGINT':
|
||||
$attributes['TYPE'] = 'NUMBER';
|
||||
return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,6 +160,19 @@ class CI_DB_pdo_odbc_driver extends CI_DB_pdo_driver {
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Platform-dependant string escape
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
protected function _escape_str($str)
|
||||
{
|
||||
$this->db->display_error('db_unsupported_feature');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Determines if a query is a "write" type.
|
||||
*
|
||||
@@ -213,72 +226,4 @@ class CI_DB_pdo_odbc_driver extends CI_DB_pdo_driver {
|
||||
{
|
||||
return 'SELECT column_name FROM information_schema.columns WHERE table_name = '.$this->escape($table);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Update statement
|
||||
*
|
||||
* Generates a platform-specific update string from the supplied data
|
||||
*
|
||||
* @param string $table
|
||||
* @param array $values
|
||||
* @return string
|
||||
*/
|
||||
protected function _update($table, $values)
|
||||
{
|
||||
$this->qb_limit = FALSE;
|
||||
$this->qb_orderby = array();
|
||||
return parent::_update($table, $values);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Truncate statement
|
||||
*
|
||||
* Generates a platform-specific truncate string from the supplied data
|
||||
*
|
||||
* If the database does not support the TRUNCATE statement,
|
||||
* then this method maps to 'DELETE FROM table'
|
||||
*
|
||||
* @param string $table
|
||||
* @return string
|
||||
*/
|
||||
protected function _truncate($table)
|
||||
{
|
||||
return 'DELETE FROM '.$table;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* LIMIT
|
||||
*
|
||||
* Generates a platform-specific LIMIT clause
|
||||
*
|
||||
* @param string $sql SQL Query
|
||||
* @return string
|
||||
*/
|
||||
protected function _limit($sql)
|
||||
{
|
||||
return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$this->qb_limit.' ', $sql);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -111,6 +111,11 @@ class CI_DB_pdo_sqlsrv_forge extends CI_DB_pdo_forge {
|
||||
*/
|
||||
protected function _attr_type(&$attributes)
|
||||
{
|
||||
if (isset($attributes['CONSTRAINT']) && strpos($attributes['TYPE'], 'INT') !== FALSE)
|
||||
{
|
||||
unset($attributes['CONSTRAINT']);
|
||||
}
|
||||
|
||||
switch (strtoupper($attributes['TYPE']))
|
||||
{
|
||||
case 'MEDIUMINT':
|
||||
|
||||
@@ -171,6 +171,7 @@ class CI_DB_sqlsrv_driver extends CI_DB {
|
||||
if ($this->_execute('USE '.$this->escape_identifiers($database)))
|
||||
{
|
||||
$this->database = $database;
|
||||
$this->data_cache = array();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -111,6 +111,11 @@ class CI_DB_sqlsrv_forge extends CI_DB_forge {
|
||||
*/
|
||||
protected function _attr_type(&$attributes)
|
||||
{
|
||||
if (isset($attributes['CONSTRAINT']) && strpos($attributes['TYPE'], 'INT') !== FALSE)
|
||||
{
|
||||
unset($attributes['CONSTRAINT']);
|
||||
}
|
||||
|
||||
switch (strtoupper($attributes['TYPE']))
|
||||
{
|
||||
case 'MEDIUMINT':
|
||||
|
||||
@@ -138,13 +138,15 @@ if ( ! function_exists('delete_files'))
|
||||
{
|
||||
if ($filename !== '.' && $filename !== '..')
|
||||
{
|
||||
if (is_dir($path.DIRECTORY_SEPARATOR.$filename) && $filename[0] !== '.')
|
||||
$filepath = $path.DIRECTORY_SEPARATOR.$filename;
|
||||
|
||||
if (is_dir($filepath) && $filename[0] !== '.' && ! is_link($filepath))
|
||||
{
|
||||
delete_files($path.DIRECTORY_SEPARATOR.$filename, $del_dir, $htdocs, $_level + 1);
|
||||
delete_files($filepath, $del_dir, $htdocs, $_level + 1);
|
||||
}
|
||||
elseif ($htdocs !== TRUE OR ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename))
|
||||
{
|
||||
@unlink($path.DIRECTORY_SEPARATOR.$filename);
|
||||
@unlink($filepath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,7 +568,7 @@ if ( ! function_exists('form_label'))
|
||||
*
|
||||
* @param string The text to appear onscreen
|
||||
* @param string The id the label applies to
|
||||
* @param string Additional attributes
|
||||
* @param array Additional attributes
|
||||
* @return string
|
||||
*/
|
||||
function form_label($label_text = '', $id = '', $attributes = array())
|
||||
|
||||
@@ -61,7 +61,7 @@ if ( ! function_exists('set_realpath'))
|
||||
function set_realpath($path, $check_existance = FALSE)
|
||||
{
|
||||
// Security check to make sure the path is NOT a URL. No remote file inclusion!
|
||||
if (preg_match('#^(http:\/\/|https:\/\/|www\.|ftp)#i', $path) OR filter_var($path, FILTER_VALIDATE_IP) === $path )
|
||||
if (preg_match('#^(http:\/\/|https:\/\/|www\.|ftp|php:\/\/)#i', $path) OR filter_var($path, FILTER_VALIDATE_IP) === $path)
|
||||
{
|
||||
show_error('The path you submitted must be a local server path, not a URL');
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ class CI_Cache_apc extends CI_Driver {
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param mixed $data Data to store
|
||||
* @param int $ttol Length of time (in seconds) to cache the data
|
||||
* @param int $ttl Length of time (in seconds) to cache the data
|
||||
* @param bool $raw Whether to store the raw value
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
|
||||
@@ -295,7 +295,7 @@ class CI_Cache_memcached extends CI_Driver {
|
||||
{
|
||||
$this->_memcached->close();
|
||||
}
|
||||
elseif ($this->_memcached instanceof Memcached)
|
||||
elseif ($this->_memcached instanceof Memcached && method_exists($this->_memcached, 'quit'))
|
||||
{
|
||||
$this->_memcached->quit();
|
||||
}
|
||||
|
||||
@@ -147,14 +147,7 @@ class CI_Email {
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $charset = 'utf-8';
|
||||
|
||||
/**
|
||||
* Multipart message
|
||||
*
|
||||
* @var string 'mixed' (in the body) or 'related' (separate)
|
||||
*/
|
||||
public $multipart = 'mixed'; // "mixed" (in the body) or "related" (separate)
|
||||
public $charset = 'UTF-8';
|
||||
|
||||
/**
|
||||
* Alternative message (for HTML messages only)
|
||||
@@ -260,20 +253,6 @@ class CI_Email {
|
||||
*/
|
||||
protected $_finalbody = '';
|
||||
|
||||
/**
|
||||
* multipart/alternative boundary
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_alt_boundary = '';
|
||||
|
||||
/**
|
||||
* Attachment boundary
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_atc_boundary = '';
|
||||
|
||||
/**
|
||||
* Final headers to send
|
||||
*
|
||||
@@ -408,47 +387,24 @@ class CI_Email {
|
||||
public function __construct(array $config = array())
|
||||
{
|
||||
$this->charset = config_item('charset');
|
||||
|
||||
if (count($config) > 0)
|
||||
{
|
||||
$this->initialize($config);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_smtp_auth = ! ($this->smtp_user === '' && $this->smtp_pass === '');
|
||||
}
|
||||
|
||||
$this->initialize($config);
|
||||
$this->_safe_mode = ( ! is_php('5.4') && ini_get('safe_mode'));
|
||||
$this->charset = strtoupper($this->charset);
|
||||
|
||||
log_message('info', 'Email Class Initialized');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Destructor - Releases Resources
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if (is_resource($this->_smtp_connect))
|
||||
{
|
||||
$this->_send_command('quit');
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Initialize preferences
|
||||
*
|
||||
* @param array
|
||||
* @param array $config
|
||||
* @return CI_Email
|
||||
*/
|
||||
public function initialize($config = array())
|
||||
public function initialize(array $config = array())
|
||||
{
|
||||
$this->clear();
|
||||
|
||||
foreach ($config as $key => $val)
|
||||
{
|
||||
if (isset($this->$key))
|
||||
@@ -465,9 +421,9 @@ class CI_Email {
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->clear();
|
||||
|
||||
$this->_smtp_auth = ! ($this->smtp_user === '' && $this->smtp_pass === '');
|
||||
$this->charset = strtoupper($this->charset);
|
||||
$this->_smtp_auth = isset($this->smtp_user[0], $this->smtp_pass[0]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -766,7 +722,8 @@ class CI_Email {
|
||||
'name' => array($file, $newname),
|
||||
'disposition' => empty($disposition) ? 'attachment' : $disposition, // Can also be 'inline' Not sure if it matters
|
||||
'type' => $mime,
|
||||
'content' => chunk_split(base64_encode($file_content))
|
||||
'content' => chunk_split(base64_encode($file_content)),
|
||||
'multipart' => 'mixed'
|
||||
);
|
||||
|
||||
return $this;
|
||||
@@ -784,15 +741,11 @@ class CI_Email {
|
||||
*/
|
||||
public function attachment_cid($filename)
|
||||
{
|
||||
if ($this->multipart !== 'related')
|
||||
{
|
||||
$this->multipart = 'related'; // Thunderbird need this for inline images
|
||||
}
|
||||
|
||||
for ($i = 0, $c = count($this->_attachments); $i < $c; $i++)
|
||||
{
|
||||
if ($this->_attachments[$i]['name'][0] === $filename)
|
||||
{
|
||||
$this->_attachments[$i]['multipart'] = 'related';
|
||||
$this->_attachments[$i]['cid'] = uniqid(basename($this->_attachments[$i]['name'][0]).'@');
|
||||
return $this->_attachments[$i]['cid'];
|
||||
}
|
||||
@@ -936,19 +889,6 @@ class CI_Email {
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set Message Boundary
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _set_boundaries()
|
||||
{
|
||||
$this->_alt_boundary = 'B_ALT_'.uniqid(''); // multipart/alternative
|
||||
$this->_atc_boundary = 'B_ATC_'.uniqid(''); // attachment boundary
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the Message ID
|
||||
*
|
||||
@@ -1016,9 +956,9 @@ class CI_Email {
|
||||
{
|
||||
if ($this->mailtype === 'html')
|
||||
{
|
||||
return (count($this->_attachments) === 0) ? 'html' : 'html-attach';
|
||||
return empty($this->_attachments) ? 'html' : 'html-attach';
|
||||
}
|
||||
elseif ($this->mailtype === 'text' && count($this->_attachments) > 0)
|
||||
elseif ($this->mailtype === 'text' && ! empty($this->_attachments))
|
||||
{
|
||||
return 'plain-attach';
|
||||
}
|
||||
@@ -1324,7 +1264,6 @@ class CI_Email {
|
||||
$this->_body = $this->word_wrap($this->_body);
|
||||
}
|
||||
|
||||
$this->_set_boundaries();
|
||||
$this->_write_headers();
|
||||
|
||||
$hdr = ($this->_get_protocol() === 'mail') ? $this->newline : '';
|
||||
@@ -1332,7 +1271,7 @@ class CI_Email {
|
||||
|
||||
switch ($this->_get_content_type())
|
||||
{
|
||||
case 'plain' :
|
||||
case 'plain':
|
||||
|
||||
$hdr .= 'Content-Type: text/plain; charset='.$this->charset.$this->newline
|
||||
.'Content-Transfer-Encoding: '.$this->_get_encoding();
|
||||
@@ -1349,7 +1288,7 @@ class CI_Email {
|
||||
|
||||
return;
|
||||
|
||||
case 'html' :
|
||||
case 'html':
|
||||
|
||||
if ($this->send_multipart === FALSE)
|
||||
{
|
||||
@@ -1358,14 +1297,16 @@ class CI_Email {
|
||||
}
|
||||
else
|
||||
{
|
||||
$hdr .= 'Content-Type: multipart/alternative; boundary="'.$this->_alt_boundary.'"';
|
||||
$boundary = uniqid('B_ALT_');
|
||||
$hdr .= 'Content-Type: multipart/alternative; boundary="'.$boundary.'"';
|
||||
|
||||
$body .= $this->_get_mime_message().$this->newline.$this->newline
|
||||
.'--'.$this->_alt_boundary.$this->newline
|
||||
.'--'.$boundary.$this->newline
|
||||
|
||||
.'Content-Type: text/plain; charset='.$this->charset.$this->newline
|
||||
.'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline.$this->newline
|
||||
.$this->_get_alt_message().$this->newline.$this->newline.'--'.$this->_alt_boundary.$this->newline
|
||||
.$this->_get_alt_message().$this->newline.$this->newline
|
||||
.'--'.$boundary.$this->newline
|
||||
|
||||
.'Content-Type: text/html; charset='.$this->charset.$this->newline
|
||||
.'Content-Transfer-Encoding: quoted-printable'.$this->newline.$this->newline;
|
||||
@@ -1384,14 +1325,15 @@ class CI_Email {
|
||||
|
||||
if ($this->send_multipart !== FALSE)
|
||||
{
|
||||
$this->_finalbody .= '--'.$this->_alt_boundary.'--';
|
||||
$this->_finalbody .= '--'.$boundary.'--';
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
case 'plain-attach' :
|
||||
case 'plain-attach':
|
||||
|
||||
$hdr .= 'Content-Type: multipart/'.$this->multipart.'; boundary="'.$this->_atc_boundary.'"';
|
||||
$boundary = uniqid('B_ATC_');
|
||||
$hdr .= 'Content-Type: multipart/mixed; boundary="'.$boundary.'"';
|
||||
|
||||
if ($this->_get_protocol() === 'mail')
|
||||
{
|
||||
@@ -1400,59 +1342,83 @@ class CI_Email {
|
||||
|
||||
$body .= $this->_get_mime_message().$this->newline
|
||||
.$this->newline
|
||||
.'--'.$this->_atc_boundary.$this->newline
|
||||
.'--'.$boundary.$this->newline
|
||||
.'Content-Type: text/plain; charset='.$this->charset.$this->newline
|
||||
.'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline
|
||||
.$this->newline
|
||||
.$this->_body.$this->newline.$this->newline;
|
||||
|
||||
break;
|
||||
case 'html-attach' :
|
||||
$this->_append_attachments($body, $boundary);
|
||||
|
||||
$hdr .= 'Content-Type: multipart/'.$this->multipart.'; boundary="'.$this->_atc_boundary.'"';
|
||||
break;
|
||||
case 'html-attach':
|
||||
|
||||
$alt_boundary = uniqid('B_ALT_');
|
||||
$last_boundary = NULL;
|
||||
|
||||
if ($this->_attachments_have_multipart('mixed'))
|
||||
{
|
||||
$atc_boundary = uniqid('B_ATC_');
|
||||
$hdr .= 'Content-Type: multipart/mixed; boundary="'.$atc_boundary.'"';
|
||||
$last_boundary = $atc_boundary;
|
||||
}
|
||||
|
||||
if ($this->_attachments_have_multipart('related'))
|
||||
{
|
||||
$rel_boundary = uniqid('B_REL_');
|
||||
$rel_boundary_header = 'Content-Type: multipart/related; boundary="'.$rel_boundary.'"';
|
||||
|
||||
if (isset($last_boundary))
|
||||
{
|
||||
$body .= '--'.$last_boundary.$this->newline.$rel_boundary_header;
|
||||
}
|
||||
else
|
||||
{
|
||||
$hdr .= $rel_boundary_header;
|
||||
}
|
||||
|
||||
$last_boundary = $rel_boundary;
|
||||
}
|
||||
|
||||
if ($this->_get_protocol() === 'mail')
|
||||
{
|
||||
$this->_header_str .= $hdr;
|
||||
}
|
||||
|
||||
strlen($body) && $body .= $this->newline.$this->newline;
|
||||
$body .= $this->_get_mime_message().$this->newline.$this->newline
|
||||
.'--'.$this->_atc_boundary.$this->newline
|
||||
.'--'.$last_boundary.$this->newline
|
||||
|
||||
.'Content-Type: multipart/alternative; boundary="'.$this->_alt_boundary.'"'.$this->newline.$this->newline
|
||||
.'--'.$this->_alt_boundary.$this->newline
|
||||
.'Content-Type: multipart/alternative; boundary="'.$alt_boundary.'"'.$this->newline.$this->newline
|
||||
.'--'.$alt_boundary.$this->newline
|
||||
|
||||
.'Content-Type: text/plain; charset='.$this->charset.$this->newline
|
||||
.'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline.$this->newline
|
||||
.$this->_get_alt_message().$this->newline.$this->newline.'--'.$this->_alt_boundary.$this->newline
|
||||
.$this->_get_alt_message().$this->newline.$this->newline
|
||||
.'--'.$alt_boundary.$this->newline
|
||||
|
||||
.'Content-Type: text/html; charset='.$this->charset.$this->newline
|
||||
.'Content-Transfer-Encoding: quoted-printable'.$this->newline.$this->newline
|
||||
|
||||
.$this->_prep_quoted_printable($this->_body).$this->newline.$this->newline
|
||||
.'--'.$this->_alt_boundary.'--'.$this->newline.$this->newline;
|
||||
.'--'.$alt_boundary.'--'.$this->newline.$this->newline;
|
||||
|
||||
break;
|
||||
if ( ! empty($rel_boundary))
|
||||
{
|
||||
$body .= $this->newline.$this->newline;
|
||||
$this->_append_attachments($body, $rel_boundary, 'related');
|
||||
}
|
||||
|
||||
// multipart/mixed attachments
|
||||
if ( ! empty($atc_boundary))
|
||||
{
|
||||
$body .= $this->newline.$this->newline;
|
||||
$this->_append_attachments($body, $atc_boundary, 'mixed');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$attachment = array();
|
||||
for ($i = 0, $c = count($this->_attachments), $z = 0; $i < $c; $i++)
|
||||
{
|
||||
$filename = $this->_attachments[$i]['name'][0];
|
||||
$basename = ($this->_attachments[$i]['name'][1] === NULL)
|
||||
? basename($filename) : $this->_attachments[$i]['name'][1];
|
||||
|
||||
$attachment[$z++] = '--'.$this->_atc_boundary.$this->newline
|
||||
.'Content-type: '.$this->_attachments[$i]['type'].'; '
|
||||
.'name="'.$basename.'"'.$this->newline
|
||||
.'Content-Disposition: '.$this->_attachments[$i]['disposition'].';'.$this->newline
|
||||
.'Content-Transfer-Encoding: base64'.$this->newline
|
||||
.(empty($this->_attachments[$i]['cid']) ? '' : 'Content-ID: <'.$this->_attachments[$i]['cid'].'>'.$this->newline);
|
||||
|
||||
$attachment[$z++] = $this->_attachments[$i]['content'];
|
||||
}
|
||||
|
||||
$body .= implode($this->newline, $attachment).$this->newline.'--'.$this->_atc_boundary.'--';
|
||||
$this->_finalbody = ($this->_get_protocol() === 'mail')
|
||||
? $body
|
||||
: $hdr.$this->newline.$this->newline.$body;
|
||||
@@ -1462,6 +1428,57 @@ class CI_Email {
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
protected function _attachments_have_multipart($type)
|
||||
{
|
||||
foreach ($this->_attachments as &$attachment)
|
||||
{
|
||||
if ($attachment['multipart'] === $type)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Prepares attachment string
|
||||
*
|
||||
* @param string $body Message body to append to
|
||||
* @param string $boundary Multipart boundary
|
||||
* @param string $multipart When provided, only attachments of this type will be processed
|
||||
* @return string
|
||||
*/
|
||||
protected function _append_attachments(&$body, $boundary, $multipart = null)
|
||||
{
|
||||
for ($i = 0, $c = count($this->_attachments); $i < $c; $i++)
|
||||
{
|
||||
if (isset($multipart) && $this->_attachments[$i]['multipart'] !== $multipart)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = isset($this->_attachments[$i]['name'][1])
|
||||
? $this->_attachments[$i]['name'][1]
|
||||
: basename($this->_attachments[$i]['name'][0]);
|
||||
|
||||
$body .= '--'.$boundary.$this->newline
|
||||
.'Content-Type: '.$this->_attachments[$i]['type'].'; name="'.$name.'"'.$this->newline
|
||||
.'Content-Disposition: '.$this->_attachments[$i]['disposition'].';'.$this->newline
|
||||
.'Content-Transfer-Encoding: base64'.$this->newline
|
||||
.(empty($this->_attachments[$i]['cid']) ? '' : 'Content-ID: <'.$this->_attachments[$i]['cid'].'>'.$this->newline.$this->newline)
|
||||
.$this->_attachments[$i]['content'].$this->newline;
|
||||
}
|
||||
|
||||
// $name won't be set if no attachments were appended,
|
||||
// and therefore a boundary wouldn't be necessary
|
||||
empty($name) OR $body .= '--'.$boundary.'--';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Prep Quoted Printable
|
||||
*
|
||||
@@ -1902,6 +1919,7 @@ class CI_Email {
|
||||
|
||||
if ( ! $this->_send_command('from', $this->clean_email($this->_headers['From'])))
|
||||
{
|
||||
$this->_smtp_end();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -1909,6 +1927,7 @@ class CI_Email {
|
||||
{
|
||||
if ( ! $this->_send_command('to', $val))
|
||||
{
|
||||
$this->_smtp_end();
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@@ -1919,6 +1938,7 @@ class CI_Email {
|
||||
{
|
||||
if ($val !== '' && ! $this->_send_command('to', $val))
|
||||
{
|
||||
$this->_smtp_end();
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@@ -1930,6 +1950,7 @@ class CI_Email {
|
||||
{
|
||||
if ($val !== '' && ! $this->_send_command('to', $val))
|
||||
{
|
||||
$this->_smtp_end();
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@@ -1937,6 +1958,7 @@ class CI_Email {
|
||||
|
||||
if ( ! $this->_send_command('data'))
|
||||
{
|
||||
$this->_smtp_end();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -1946,29 +1968,37 @@ class CI_Email {
|
||||
$this->_send_data('.');
|
||||
|
||||
$reply = $this->_get_smtp_data();
|
||||
|
||||
$this->_set_error_message($reply);
|
||||
|
||||
$this->_smtp_end();
|
||||
|
||||
if (strpos($reply, '250') !== 0)
|
||||
{
|
||||
$this->_set_error_message('lang:email_smtp_error', $reply);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ($this->smtp_keepalive)
|
||||
{
|
||||
$this->_send_command('reset');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_send_command('quit');
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* SMTP End
|
||||
*
|
||||
* Shortcut to send RSET or QUIT depending on keep-alive
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _smtp_end()
|
||||
{
|
||||
($this->smtp_keepalive)
|
||||
? $this->_send_command('reset')
|
||||
: $this->_send_command('quit');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* SMTP Connect
|
||||
*
|
||||
@@ -2153,6 +2183,11 @@ class CI_Email {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ($this->smtp_keepalive)
|
||||
{
|
||||
$this->_smtp_auth = FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -2342,4 +2377,15 @@ class CI_Email {
|
||||
return 'application/x-unknown-content-type';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
is_resource($this->_smtp_connect) && $this->_send_command('quit');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,12 +339,26 @@ class CI_Encryption {
|
||||
{
|
||||
if (function_exists('random_bytes'))
|
||||
{
|
||||
return random_bytes((int) $length);
|
||||
try
|
||||
{
|
||||
return random_bytes((int) $length);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
log_message('error', $e->getMessage());
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
elseif (defined('MCRYPT_DEV_URANDOM'))
|
||||
{
|
||||
return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
|
||||
}
|
||||
|
||||
return ($this->_driver === 'mcrypt')
|
||||
? mcrypt_create_iv($length, MCRYPT_DEV_URANDOM)
|
||||
: openssl_random_pseudo_bytes($length);
|
||||
$is_secure = NULL;
|
||||
$key = openssl_random_pseudo_bytes($length, $is_secure);
|
||||
return ($is_secure === TRUE)
|
||||
? $key
|
||||
: FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -400,7 +414,7 @@ class CI_Encryption {
|
||||
// The greater-than-1 comparison is mostly a work-around for a bug,
|
||||
// where 1 is returned for ARCFour instead of 0.
|
||||
$iv = (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1)
|
||||
? mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM)
|
||||
? $this->create_key($iv_size)
|
||||
: NULL;
|
||||
|
||||
if (mcrypt_generic_init($params['handle'], $params['key'], $iv) < 0)
|
||||
@@ -463,7 +477,7 @@ class CI_Encryption {
|
||||
}
|
||||
|
||||
$iv = ($iv_size = openssl_cipher_iv_length($params['handle']))
|
||||
? openssl_random_pseudo_bytes($iv_size)
|
||||
? $this->create_key($iv_size)
|
||||
: NULL;
|
||||
|
||||
$data = openssl_encrypt(
|
||||
|
||||
@@ -493,6 +493,63 @@ class CI_Form_validation {
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Prepare rules
|
||||
*
|
||||
* Re-orders the provided rules in order of importance, so that
|
||||
* they can easily be executed later without weird checks ...
|
||||
*
|
||||
* "Callbacks" are given the highest priority (always called),
|
||||
* followed by 'required' (called if callbacks didn't fail),
|
||||
* and then every next rule depends on the previous one passing.
|
||||
*
|
||||
* @param array $rules
|
||||
* @return array
|
||||
*/
|
||||
protected function _prepare_rules($rules)
|
||||
{
|
||||
$new_rules = array();
|
||||
$callbacks = array();
|
||||
|
||||
foreach ($rules as &$rule)
|
||||
{
|
||||
// Let 'required' always be the first (non-callback) rule
|
||||
if ($rule === 'required')
|
||||
{
|
||||
array_unshift($new_rules, 'required');
|
||||
}
|
||||
// 'isset' is a kind of a weird alias for 'required' ...
|
||||
elseif ($rule === 'isset' && (empty($new_rules) OR $new_rules[0] !== 'required'))
|
||||
{
|
||||
array_unshift($new_rules, 'isset');
|
||||
}
|
||||
// The old/classic 'callback_'-prefixed rules
|
||||
elseif (is_string($rule) && strncmp('callback_', $rule, 9) === 0)
|
||||
{
|
||||
$callbacks[] = $rule;
|
||||
}
|
||||
// Proper callables
|
||||
elseif (is_callable($rule))
|
||||
{
|
||||
$callbacks[] = $rule;
|
||||
}
|
||||
// "Named" callables; i.e. array('name' => $callable)
|
||||
elseif (is_array($rule) && isset($rule[0], $rule[1]) && is_callable($rule[1]))
|
||||
{
|
||||
$callbacks[] = $rule;
|
||||
}
|
||||
// Everything else goes at the end of the queue
|
||||
else
|
||||
{
|
||||
$new_rules[] = $rule;
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge($callbacks, $new_rules);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Traverse a multidimensional $_POST array index until the data is found
|
||||
*
|
||||
@@ -580,70 +637,7 @@ class CI_Form_validation {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the field is blank, but NOT required, no further tests are necessary
|
||||
$callback = FALSE;
|
||||
if ( ! in_array('required', $rules) && ($postdata === NULL OR $postdata === ''))
|
||||
{
|
||||
// Before we bail out, does the rule contain a callback?
|
||||
foreach ($rules as &$rule)
|
||||
{
|
||||
if (is_string($rule))
|
||||
{
|
||||
if (strncmp($rule, 'callback_', 9) === 0)
|
||||
{
|
||||
$callback = TRUE;
|
||||
$rules = array(1 => $rule);
|
||||
break;
|
||||
}
|
||||
}
|
||||
elseif (is_callable($rule))
|
||||
{
|
||||
$callback = TRUE;
|
||||
$rules = array(1 => $rule);
|
||||
break;
|
||||
}
|
||||
elseif (is_array($rule) && isset($rule[0], $rule[1]) && is_callable($rule[1]))
|
||||
{
|
||||
$callback = TRUE;
|
||||
$rules = array(array($rule[0], $rule[1]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $callback)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Isset Test. Typically this rule will only apply to checkboxes.
|
||||
if (($postdata === NULL OR $postdata === '') && ! $callback)
|
||||
{
|
||||
if (in_array('isset', $rules, TRUE) OR in_array('required', $rules))
|
||||
{
|
||||
// Set the message type
|
||||
$type = in_array('required', $rules) ? 'required' : 'isset';
|
||||
|
||||
$line = $this->_get_error_message($type, $row['field']);
|
||||
|
||||
// Build the error message
|
||||
$message = $this->_build_error_msg($line, $this->_translate_fieldname($row['label']));
|
||||
|
||||
// Save the error message
|
||||
$this->_field_data[$row['field']]['error'] = $message;
|
||||
|
||||
if ( ! isset($this->_error_array[$row['field']]))
|
||||
{
|
||||
$this->_error_array[$row['field']] = $message;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// Cycle through each rule and run it
|
||||
$rules = $this->_prepare_rules($rules);
|
||||
foreach ($rules as $rule)
|
||||
{
|
||||
$_in_array = FALSE;
|
||||
@@ -702,6 +696,17 @@ class CI_Form_validation {
|
||||
$param = $match[2];
|
||||
}
|
||||
|
||||
// Ignore empty, non-required inputs with a few exceptions ...
|
||||
if (
|
||||
($postdata === NULL OR $postdata === '')
|
||||
&& $callback === FALSE
|
||||
&& $callable === FALSE
|
||||
&& ! in_array($rule, array('required', 'isset', 'matches'), TRUE)
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Call the function that corresponds to the rule
|
||||
if ($callback OR $callable !== FALSE)
|
||||
{
|
||||
@@ -740,12 +745,6 @@ class CI_Form_validation {
|
||||
{
|
||||
$this->_field_data[$row['field']]['postdata'] = is_bool($result) ? $postdata : $result;
|
||||
}
|
||||
|
||||
// If the field isn't required and we just processed a callback we'll move on...
|
||||
if ( ! in_array('required', $rules, TRUE) && $result !== FALSE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
elseif ( ! method_exists($this, $rule))
|
||||
{
|
||||
@@ -1055,7 +1054,9 @@ class CI_Form_validation {
|
||||
*/
|
||||
public function required($str)
|
||||
{
|
||||
return is_array($str) ? (bool) count($str) : (trim($str) !== '');
|
||||
return is_array($str)
|
||||
? (empty($str) === FALSE)
|
||||
: (trim($str) !== '');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -456,7 +456,7 @@ class CI_Image_lib {
|
||||
{
|
||||
if (property_exists($this, $key))
|
||||
{
|
||||
if (in_array($key, array('wm_font_color', 'wm_shadow_color')))
|
||||
if (in_array($key, array('wm_font_color', 'wm_shadow_color'), TRUE))
|
||||
{
|
||||
if (preg_match('/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i', $val, $matches))
|
||||
{
|
||||
@@ -478,6 +478,10 @@ class CI_Image_lib {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
elseif (in_array($key, array('width', 'height'), TRUE) && ! ctype_digit((string) $val))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->$key = $val;
|
||||
}
|
||||
@@ -862,27 +866,28 @@ class CI_Image_lib {
|
||||
|
||||
if ($action === 'crop')
|
||||
{
|
||||
$cmd .= ' -crop '.$this->width.'x'.$this->height.'+'.$this->x_axis.'+'.$this->y_axis.' "'.$this->full_src_path.'" "'.$this->full_dst_path .'" 2>&1';
|
||||
$cmd .= ' -crop '.$this->width.'x'.$this->height.'+'.$this->x_axis.'+'.$this->y_axis;
|
||||
}
|
||||
elseif ($action === 'rotate')
|
||||
{
|
||||
$angle = ($this->rotation_angle === 'hor' OR $this->rotation_angle === 'vrt')
|
||||
? '-flop' : '-rotate '.$this->rotation_angle;
|
||||
|
||||
$cmd .= ' '.$angle.' "'.$this->full_src_path.'" "'.$this->full_dst_path.'" 2>&1';
|
||||
$cmd .= ($this->rotation_angle === 'hor' OR $this->rotation_angle === 'vrt')
|
||||
? ' -flop'
|
||||
: ' -rotate '.$this->rotation_angle;
|
||||
}
|
||||
else // Resize
|
||||
{
|
||||
if($this->maintain_ratio === TRUE)
|
||||
{
|
||||
$cmd .= ' -resize '.$this->width.'x'.$this->height.' "'.$this->full_src_path.'" "'.$this->full_dst_path.'" 2>&1';
|
||||
$cmd .= ' -resize '.$this->width.'x'.$this->height;
|
||||
}
|
||||
else
|
||||
{
|
||||
$cmd .= ' -resize '.$this->width.'x'.$this->height.'\! "'.$this->full_src_path.'" "'.$this->full_dst_path.'" 2>&1';
|
||||
$cmd .= ' -resize '.$this->width.'x'.$this->height.'\!';
|
||||
}
|
||||
}
|
||||
|
||||
$cmd .= ' "'.escapeshellarg($this->full_src_path).'" "'.escapeshellarg($this->full_dst_path).'" 2>&1';
|
||||
|
||||
$retval = 1;
|
||||
// exec() might be disabled
|
||||
if (function_usable('exec'))
|
||||
|
||||
@@ -91,6 +91,7 @@ class CI_Session {
|
||||
// Note: BC workaround
|
||||
elseif (config_item('sess_use_database'))
|
||||
{
|
||||
log_message('debug', 'Session: "sess_driver" is empty; using BC fallback to "sess_use_database".');
|
||||
$this->_driver = 'database';
|
||||
}
|
||||
|
||||
@@ -729,7 +730,7 @@ class CI_Session {
|
||||
*
|
||||
* Legacy CI_Session compatibility method
|
||||
*
|
||||
* @param mixed $data Session data key(s)
|
||||
* @param mixed $key Session data key(s)
|
||||
* @return void
|
||||
*/
|
||||
public function unset_userdata($key)
|
||||
|
||||
@@ -109,7 +109,10 @@ class CI_Session_database_driver extends CI_Session_driver implements SessionHan
|
||||
}
|
||||
|
||||
// Note: BC work-around for the old 'sess_table_name' setting, should be removed in the future.
|
||||
isset($this->_config['save_path']) OR $this->_config['save_path'] = config_item('sess_table_name');
|
||||
if ( ! isset($this->_config['save_path']) && ($this->_config['save_path'] = config_item('sess_table_name')))
|
||||
{
|
||||
log_message('debug', 'Session: "sess_save_path" is empty; using BC fallback to "sess_table_name".');
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@@ -95,6 +95,7 @@ class CI_Session_files_driver extends CI_Session_driver implements SessionHandle
|
||||
}
|
||||
else
|
||||
{
|
||||
log_message('debug', 'Session: "sess_save_path" is empty; using "session.save_path" value from php.ini.');
|
||||
$this->_config['save_path'] = rtrim(ini_get('session.save_path'), '/\\');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,7 +255,7 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle
|
||||
if ($this->_redis->ping() === '+PONG')
|
||||
{
|
||||
$this->_release_lock();
|
||||
if ($this->_redis->close() === $this->_failure)
|
||||
if ($this->_redis->close() === FALSE)
|
||||
{
|
||||
return $this->_fail();
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ class CI_Upload {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $props
|
||||
* @param array $config
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($config = array())
|
||||
@@ -601,7 +601,7 @@ class CI_Upload {
|
||||
'file_type' => $this->file_type,
|
||||
'file_path' => $this->upload_path,
|
||||
'full_path' => $this->upload_path.$this->file_name,
|
||||
'raw_name' => str_replace($this->file_ext, '', $this->file_name),
|
||||
'raw_name' => substr($this->file_name, 0, -strlen($this->file_ext)),
|
||||
'orig_name' => $this->orig_name,
|
||||
'client_name' => $this->client_name,
|
||||
'file_ext' => $this->file_ext,
|
||||
|
||||
@@ -173,13 +173,11 @@ class CI_User_agent {
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->_load_agent_file();
|
||||
|
||||
if (isset($_SERVER['HTTP_USER_AGENT']))
|
||||
{
|
||||
$this->agent = trim($_SERVER['HTTP_USER_AGENT']);
|
||||
}
|
||||
|
||||
if ($this->agent !== NULL && $this->_load_agent_file())
|
||||
{
|
||||
$this->_compile_data();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user