diff options
-rw-r--r-- | application/config/database.php | 2 | ||||
-rw-r--r-- | index.php | 2 | ||||
-rw-r--r-- | readme.rst | 4 | ||||
-rw-r--r-- | system/core/Common.php | 3 | ||||
-rwxr-xr-x | system/core/Input.php | 67 | ||||
-rwxr-xr-x | system/database/DB.php | 1 | ||||
-rw-r--r-- | system/database/DB_driver.php | 27 | ||||
-rw-r--r-- | system/database/drivers/pdo/pdo_driver.php | 272 | ||||
-rw-r--r-- | system/database/drivers/pdo/pdo_forge.php | 12 | ||||
-rw-r--r-- | system/database/drivers/pdo/pdo_result.php | 67 | ||||
-rw-r--r-- | system/libraries/Session.php | 133 | ||||
-rw-r--r-- | user_guide_src/source/changelog.rst | 4 | ||||
-rw-r--r-- | user_guide_src/source/database/configuration.rst | 4 |
13 files changed, 410 insertions, 188 deletions
diff --git a/application/config/database.php b/application/config/database.php index 7eac59b23..bd68db1d8 100644 --- a/application/config/database.php +++ b/application/config/database.php @@ -37,6 +37,7 @@ | EXPLANATION OF VARIABLES | ------------------------------------------------------------------- | +| ['dsn'] The full DSN string describe a connection to the database. | ['hostname'] The hostname of your database server. | ['username'] The username used to connect to the database | ['password'] The password used to connect to the database @@ -74,6 +75,7 @@ $active_group = 'default'; $active_record = TRUE; +$db['default']['dsn'] = ''; $db['default']['hostname'] = 'localhost'; $db['default']['username'] = ''; $db['default']['password'] = ''; @@ -218,6 +218,7 @@ if (defined('ENVIRONMENT')) { if ( ! is_dir(BASEPATH.$application_folder.'/')) { + header('HTTP/1.1 503 Service Unavailable.', TRUE, '503'); exit('Your application folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF); } @@ -233,6 +234,7 @@ if (defined('ENVIRONMENT')) { if ( ! is_dir(APPPATH.'views/')) { + header('HTTP/1.1 503 Service Unavailable.', TRUE, '503'); exit('Your view folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF); } diff --git a/readme.rst b/readme.rst index 26e04ceac..2369a8ddb 100644 --- a/readme.rst +++ b/readme.rst @@ -23,7 +23,7 @@ Changelog and New Features ************************** You can find a list of all changes for each release in the `user -guide change log <https://github.com/EllisLab/CodeIgniter/blob/develop/user_guide/changelog.html>`_. +guide change log <https://github.com/EllisLab/CodeIgniter/blob/develop/user_guide_src/source/changelog.rst>`_. ******************* Server Requirements @@ -193,4 +193,4 @@ Acknowledgement *************** The EllisLab team and The Reactor Engineers would like to thank all the -contributors to the CodeIgniter project and you, the CodeIgniter user.
\ No newline at end of file +contributors to the CodeIgniter project and you, the CodeIgniter user. diff --git a/system/core/Common.php b/system/core/Common.php index 2f9c4ff43..225227d17 100644 --- a/system/core/Common.php +++ b/system/core/Common.php @@ -177,6 +177,7 @@ if ( ! function_exists('load_class')) { // Note: We use exit() rather then show_error() in order to avoid a // self-referencing loop with the Excptions class + set_status_header(503); exit('Unable to locate the specified class: '.$class.'.php'); } @@ -243,6 +244,7 @@ if ( ! function_exists('get_config')) // Fetch the config file if ( ! file_exists($file_path)) { + set_status_header(503); exit('The configuration file does not exist.'); } @@ -251,6 +253,7 @@ if ( ! function_exists('get_config')) // Does the $config array exist in the file? if ( ! isset($config) OR ! is_array($config)) { + set_status_header(503); exit('Your config file does not appear to be formatted correctly.'); } diff --git a/system/core/Input.php b/system/core/Input.php index 7a16e51ab..ee15f4013 100755 --- a/system/core/Input.php +++ b/system/core/Input.php @@ -25,8 +25,6 @@ * @filesource */ -// ------------------------------------------------------------------------ - /** * Input Class * @@ -152,7 +150,7 @@ class CI_Input { public function get($index = NULL, $xss_clean = FALSE) { // Check if a field has been provided - if ($index === NULL AND ! empty($_GET)) + if ($index === NULL && ! empty($_GET)) { $get = array(); @@ -179,7 +177,7 @@ class CI_Input { public function post($index = NULL, $xss_clean = FALSE) { // Check if a field has been provided - if ($index === NULL AND ! empty($_POST)) + if ($index === NULL && ! empty($_POST)) { $post = array(); @@ -206,9 +204,9 @@ class CI_Input { */ public function get_post($index = '', $xss_clean = FALSE) { - return ( ! isset($_POST[$index])) - ? $this->get($index, $xss_clean) - : $this->post($index, $xss_clean); + return isset($_POST[$index]) + ? $this->post($index, $xss_clean) + : $this->get($index, $xss_clean); } // -------------------------------------------------------------------- @@ -256,19 +254,19 @@ class CI_Input { } } - if ($prefix == '' AND config_item('cookie_prefix') != '') + if ($prefix == '' && config_item('cookie_prefix') != '') { $prefix = config_item('cookie_prefix'); } - if ($domain == '' AND config_item('cookie_domain') != '') + if ($domain == '' && config_item('cookie_domain') != '') { $domain = config_item('cookie_domain'); } - if ($path == '/' AND config_item('cookie_path') != '/') + if ($path == '/' && config_item('cookie_path') !== '/') { $path = config_item('cookie_path'); } - if ($secure == FALSE AND config_item('cookie_secure') != FALSE) + if ($secure == FALSE && config_item('cookie_secure') != FALSE) { $secure = config_item('cookie_secure'); } @@ -320,11 +318,11 @@ class CI_Input { $this->ip_address = in_array($_SERVER['REMOTE_ADDR'], $proxies) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR']; } - elseif ( ! $this->server('HTTP_CLIENT_IP') AND $this->server('REMOTE_ADDR')) + elseif ( ! $this->server('HTTP_CLIENT_IP') && $this->server('REMOTE_ADDR')) { $this->ip_address = $_SERVER['REMOTE_ADDR']; } - elseif ($this->server('REMOTE_ADDR') AND $this->server('HTTP_CLIENT_IP')) + elseif ($this->server('REMOTE_ADDR') && $this->server('HTTP_CLIENT_IP')) { $this->ip_address = $_SERVER['HTTP_CLIENT_IP']; } @@ -414,7 +412,7 @@ class CI_Input { return $this->user_agent; } - return $this->user_agent = ( ! isset($_SERVER['HTTP_USER_AGENT'])) ? FALSE : $_SERVER['HTTP_USER_AGENT']; + return $this->user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : FALSE; } // -------------------------------------------------------------------- @@ -469,19 +467,16 @@ class CI_Input { { $_GET = array(); } - else + elseif (is_array($_GET) && count($_GET) > 0) { - if (is_array($_GET) AND count($_GET) > 0) + foreach ($_GET as $key => $val) { - foreach ($_GET as $key => $val) - { - $_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); - } + $_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); } } // Clean $_POST Data - if (is_array($_POST) AND count($_POST) > 0) + if (is_array($_POST) && count($_POST) > 0) { foreach ($_POST as $key => $val) { @@ -490,7 +485,7 @@ class CI_Input { } // Clean $_COOKIE Data - if (is_array($_COOKIE) AND count($_COOKIE) > 0) + if (is_array($_COOKIE) && count($_COOKIE) > 0) { // Also get rid of specially treated cookies that might be set by a server // or silly application, that are of no use to a CI application anyway @@ -568,7 +563,7 @@ class CI_Input { } // Standardize newlines if needed - if ($this->_standardize_newlines == TRUE AND strpos($str, "\r") !== FALSE) + if ($this->_standardize_newlines == TRUE && strpos($str, "\r") !== FALSE) { return str_replace(array("\r\n", "\r", "\r\n\n"), PHP_EOL, $str); } @@ -592,6 +587,7 @@ class CI_Input { { if ( ! preg_match('/^[a-z0-9:_\/-]+$/i', $str)) { + set_status_header(503); exit('Disallowed Key Characters.'); } @@ -624,7 +620,7 @@ class CI_Input { } else { - $headers['Content-Type'] = (isset($_SERVER['CONTENT_TYPE'])) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE'); + $headers['Content-Type'] = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE'); foreach ($_SERVER as $key => $val) { @@ -654,9 +650,9 @@ class CI_Input { * * Returns the value of a single member of the headers class member * - * @param string array key for $this->headers - * @param boolean XSS Clean or not - * @return mixed FALSE on failure, string on success + * @param string array key for $this->headers + * @param bool XSS Clean or not + * @return mixed FALSE on failure, string on success */ public function get_request_header($index, $xss_clean = FALSE) { @@ -670,12 +666,9 @@ class CI_Input { return FALSE; } - if ($xss_clean === TRUE) - { - return $this->security->xss_clean($this->headers[$index]); - } - - return $this->headers[$index]; + return ($xss_clean === TRUE) + ? $this->security->xss_clean($this->headers[$index]) + : $this->headers[$index]; } // -------------------------------------------------------------------- @@ -685,11 +678,11 @@ class CI_Input { * * Test to see if a request contains the HTTP_X_REQUESTED_WITH header * - * @return boolean + * @return bool */ public function is_ajax_request() { - return ($this->server('HTTP_X_REQUESTED_WITH') === 'XMLHttpRequest'); + return ( ! empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest'); } // -------------------------------------------------------------------- @@ -699,11 +692,11 @@ class CI_Input { * * Test to see if a request was made from the command line * - * @return boolean + * @return bool */ public function is_cli_request() { - return (php_sapi_name() === 'cli') or defined('STDIN'); + return (php_sapi_name() === 'cli' OR defined('STDIN')); } } diff --git a/system/database/DB.php b/system/database/DB.php index ed6afd7ed..d06ffb40e 100755 --- a/system/database/DB.php +++ b/system/database/DB.php @@ -82,6 +82,7 @@ function &DB($params = '', $active_record_override = NULL) $params = array( 'dbdriver' => $dns['scheme'], 'hostname' => (isset($dns['host'])) ? rawurldecode($dns['host']) : '', + 'port' => (isset($dns['port'])) ? rawurldecode($dns['port']) : '', 'username' => (isset($dns['user'])) ? rawurldecode($dns['user']) : '', 'password' => (isset($dns['pass'])) ? rawurldecode($dns['pass']) : '', 'database' => (isset($dns['path'])) ? rawurldecode(substr($dns['path'], 1)) : '' diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php index 566779d0e..9c9fdac85 100644 --- a/system/database/DB_driver.php +++ b/system/database/DB_driver.php @@ -81,8 +81,7 @@ class CI_DB_driver { var $stmt_id; var $curs_id; var $limit_used; - - + /** * Constructor. Accepts one parameter containing the database @@ -814,20 +813,23 @@ class CI_DB_driver { if ($query->num_rows() > 0) { - foreach ($query->result_array() as $row) + $table = FALSE; + $rows = $query->result_array(); + $key = (($row = current($rows)) && in_array('table_name', array_map('strtolower', array_keys($row)))); + + if ($key) { - if (isset($row['TABLE_NAME'])) - { - $retval[] = $row['TABLE_NAME']; - } - else - { - $retval[] = array_shift($row); - } + $table = array_key_exists('TABLE_NAME', $row) ? 'TABLE_NAME' : 'table_name'; + } + + foreach ($rows as $row) + { + $retval[] = ( ! $table) ? current($row) : $row[$table]; } } $this->data_cache['table_names'] = $retval; + return $this->data_cache['table_names']; } @@ -1436,10 +1438,7 @@ class CI_DB_driver { return $item.$alias; } - - } - /* End of file DB_driver.php */ /* Location: ./system/database/DB_driver.php */ diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php index 4f4f44ba7..fc378daeb 100644 --- a/system/database/drivers/pdo/pdo_driver.php +++ b/system/database/drivers/pdo/pdo_driver.php @@ -46,9 +46,10 @@ class CI_DB_pdo_driver extends CI_DB { // the character used to excape - not necessary for PDO var $_escape_char = ''; + + // clause and character used for LIKE escape sequences var $_like_escape_str; var $_like_escape_chr; - /** * The syntax to count rows is slightly different across different @@ -57,29 +58,36 @@ class CI_DB_pdo_driver extends CI_DB { */ var $_count_string = "SELECT COUNT(*) AS "; var $_random_keyword; - + + // need to track the pdo DSN, driver and options + var $dsn; + var $pdodriver; var $options = array(); function __construct($params) { parent::__construct($params); - + + if (preg_match('/([^;]+):/', $this->dsn, $match) && count($match) == 2) + { + // If there is a minimum valid dsn string pattern found, we're done + // This is for general PDO users, who tend to have a full DSN string. + $this->pdodriver = end($match); + } + else + { + // Try to build a complete DSN string from params + $this->_connect_string($params); + } + // clause and character used for LIKE escape sequences - if (strpos($this->hostname, 'mysql') !== FALSE) + // this one depends on the driver being used + if ($this->pdodriver == 'mysql') { $this->_like_escape_str = ''; $this->_like_escape_chr = ''; - - //Prior to this version, the charset can't be set in the dsn - if(is_php('5.3.6')) - { - $this->hostname .= ";charset={$this->char_set}"; - } - - //Set the charset with the connection options - $this->options['PDO::MYSQL_ATTR_INIT_COMMAND'] = "SET NAMES {$this->char_set}"; } - else if (strpos($this->hostname, 'odbc') !== FALSE) + elseif ($this->pdodriver == 'odbc') { $this->_like_escape_str = " {escape '%s'} "; $this->_like_escape_chr = '!'; @@ -90,14 +98,85 @@ class CI_DB_pdo_driver extends CI_DB { $this->_like_escape_chr = '!'; } - if (strpos($this->hostname, 'sqlite') === FALSE) + $this->trans_enabled = FALSE; + $this->_random_keyword = ' RND('.time().')'; // database specific random keyword + } + + /** + * Connection String + * + * @access private + * @param array + * @return void + */ + function _connect_string($params) + { + if (strpos($this->hostname, ':')) { - $this->hostname .= ";dbname=".$this->database; + // hostname generally would have this prototype + // $db['hostname'] = 'pdodriver:host(/Server(/DSN))=hostname(/DSN);'; + // We need to get the prefix (pdodriver used by PDO). + $this->dsn = $this->hostname; + $this->pdodriver = substr($this->hostname, 0, strpos($this->hostname, ':')); } - - $this->trans_enabled = FALSE; + else + { + // Invalid DSN, display an error + if ( ! array_key_exists('pdodriver', $params)) + { + show_error('Invalid DB Connection String for PDO'); + } - $this->_random_keyword = ' RND('.time().')'; // database specific random keyword + // Assuming that the following DSN string format is used: + // $dsn = 'pdo://username:password@hostname:port/database?pdodriver=pgsql'; + $this->dsn = $this->pdodriver.':'; + + // Add hostname to the DSN for databases that need it + if ( ! empty($this->hostname) && in_array($this->pdodriver, array('informix', 'mysql', 'pgsql', 'sybase', 'mssql', 'dblib', 'cubrid'))) + { + $this->dsn .= 'host='.$this->hostname.';'; + } + + // Add a port to the DSN for databases that can use it + if ( ! empty($this->port) && in_array($this->pdodriver, array('informix', 'mysql', 'pgsql', 'ibm', 'cubrid'))) + { + $this->dsn .= 'port='.$this->port.';'; + } + } + + // Add the database name to the DSN, if needed + if (stripos($this->dsn, 'dbname') === FALSE + && in_array($this->pdodriver, array('4D', 'pgsql', 'mysql', 'firebird', 'sybase', 'mssql', 'dblib', 'cubrid'))) + { + $this->dsn .= 'dbname='.$this->database.';'; + } + elseif (stripos($this->dsn, 'database') === FALSE && in_array($this->pdodriver, array('ibm', 'sqlsrv'))) + { + if (stripos($this->dsn, 'dsn') === FALSE) + { + $this->dsn .= 'database='.$this->database.';'; + } + } + elseif ($this->pdodriver === 'sqlite' && $this->dsn === 'sqlite:') + { + if ($this->database !== ':memory') + { + if ( ! file_exists($this->database)) + { + show_error('Invalid DB Connection string for PDO SQLite'); + } + + $this->dsn .= (strpos($this->database, DIRECTORY_SEPARATOR) !== 0) ? DIRECTORY_SEPARATOR : ''; + } + + $this->dsn .= $this->database; + } + + // Add charset to the DSN, if needed + if ( ! empty($this->char_set) && in_array($this->pdodriver, array('4D', 'mysql', 'sybase', 'mssql', 'dblib', 'oci'))) + { + $this->dsn .= 'charset='.$this->char_set.';'; + } } /** @@ -108,9 +187,9 @@ class CI_DB_pdo_driver extends CI_DB { */ function db_connect() { - $this->options['PDO::ATTR_ERRMODE'] = PDO::ERRMODE_SILENT; - - return new PDO($this->hostname, $this->username, $this->password, $this->options); + $this->options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_SILENT; + + return $this->pdo_connect(); } // -------------------------------------------------------------------- @@ -123,10 +202,44 @@ class CI_DB_pdo_driver extends CI_DB { */ function db_pconnect() { - $this->options['PDO::ATTR_ERRMODE'] = PDO::ERRMODE_SILENT; - $this->options['PDO::ATTR_PERSISTENT'] = TRUE; + $this->options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_SILENT; + $this->options[PDO::ATTR_PERSISTENT] = TRUE; - return new PDO($this->hostname, $this->username, $this->password, $this->options); + return $this->pdo_connect(); + } + + // -------------------------------------------------------------------- + + /** + * PDO connection + * + * @access private called by the PDO driver class + * @return resource + */ + function pdo_connect() + { + // Refer : http://php.net/manual/en/ref.pdo-mysql.connection.php + if ($this->pdodriver == 'mysql' && is_php('5.3.6')) + { + $this->options[PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES $this->char_set COLLATE '$this->dbcollat'"; + } + + // Connecting... + try + { + $db = new PDO($this->dsn, $this->username, $this->password, $this->options); + } + catch (PDOException $e) + { + if ($this->db_debug && empty($this->failover)) + { + $this->display_error($e->getMessage(), '', TRUE); + } + + return FALSE; + } + + return $db; } // -------------------------------------------------------------------- @@ -146,6 +259,7 @@ class CI_DB_pdo_driver extends CI_DB { { return $this->db->display_error('db_unsuported_feature'); } + return FALSE; } @@ -175,7 +289,6 @@ class CI_DB_pdo_driver extends CI_DB { */ function db_set_charset($charset, $collation) { - // @todo - add support if needed return TRUE; } @@ -204,6 +317,7 @@ class CI_DB_pdo_driver extends CI_DB { function _execute($sql) { $sql = $this->_prep_query($sql); + $result_id = $this->conn_id->query($sql); if (is_object($result_id)) @@ -231,6 +345,17 @@ class CI_DB_pdo_driver extends CI_DB { */ function _prep_query($sql) { + if ($this->pdodriver === 'pgsql') + { + // Change the backtick(s) for Postgre + $sql = str_replace('`', '"', $sql); + } + elseif ($this->pdodriver === 'sqlite') + { + // Change the backtick(s) for SQLite + $sql = str_replace('`', '', $sql); + } + return $sql; } @@ -285,6 +410,7 @@ class CI_DB_pdo_driver extends CI_DB { } $ret = $this->conn->commit(); + return $ret; } @@ -310,6 +436,7 @@ class CI_DB_pdo_driver extends CI_DB { } $ret = $this->conn_id->rollBack(); + return $ret; } @@ -348,7 +475,9 @@ class CI_DB_pdo_driver extends CI_DB { if ($like === TRUE) { $str = str_replace( array('%', '_', $this->_like_escape_chr), - array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr), + array($this->_like_escape_chr.'%', + $this->_like_escape_chr.'_', + $this->_like_escape_chr.$this->_like_escape_chr), $str); } @@ -378,9 +507,9 @@ class CI_DB_pdo_driver extends CI_DB { */ function insert_id($name=NULL) { - //Convenience method for postgres insertid - if (strpos($this->hostname, 'pgsql') !== FALSE) + if ($this->pdodriver == 'pgsql') { + //Convenience method for postgres insertid $v = $this->_version(); $table = func_num_args() > 0 ? func_get_arg(0) : NULL; @@ -389,8 +518,10 @@ class CI_DB_pdo_driver extends CI_DB { { $sql='SELECT LASTVAL() as ins_id'; } + $query = $this->query($sql); - $row = $query->row(); + $row = $query->row(); + return $row->ins_id; } else @@ -418,7 +549,9 @@ class CI_DB_pdo_driver extends CI_DB { return 0; } - $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); + $sql = $this->_count_string.$this->_protect_identifiers('numrows').' FROM '; + $sql .= $this->_protect_identifiers($table, TRUE, NULL, FALSE); + $query = $this->query($sql); if ($query->num_rows() == 0) { @@ -427,6 +560,7 @@ class CI_DB_pdo_driver extends CI_DB { $row = $query->row(); $this->_reset_select(); + return (int) $row->numrows; } @@ -443,12 +577,19 @@ class CI_DB_pdo_driver extends CI_DB { */ function _list_tables($prefix_limit = FALSE) { - $sql = "SHOW TABLES FROM `".$this->database."`"; + if ($this->pdodriver == 'pgsql') + { + // Analog function to show all tables in postgre + $sql = "SELECT * FROM information_schema.tables WHERE table_schema = 'public'"; + } + else + { + $sql = "SHOW TABLES FROM `".$this->database."`"; + } if ($prefix_limit !== FALSE AND $this->dbprefix != '') { - //$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); - return FALSE; // not currently supported + return FALSE; } return $sql; @@ -467,7 +608,7 @@ class CI_DB_pdo_driver extends CI_DB { */ function _list_columns($table = '') { - return "SHOW COLUMNS FROM ".$table; + return 'SHOW COLUMNS FROM '.$this->_from_tables($table); } // -------------------------------------------------------------------- @@ -483,7 +624,7 @@ class CI_DB_pdo_driver extends CI_DB { */ function _field_data($table) { - return "SELECT TOP 1 FROM ".$table; + return 'SELECT TOP 1 FROM '.$this->_from_tables($table); } // -------------------------------------------------------------------- @@ -497,6 +638,7 @@ class CI_DB_pdo_driver extends CI_DB { function _error_message() { $error_array = $this->conn_id->errorInfo(); + return $error_array[2]; } @@ -544,8 +686,8 @@ class CI_DB_pdo_driver extends CI_DB { if (strpos($item, '.') !== FALSE) { - $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; - + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item); + $str .= $this->_escape_char; } else { @@ -575,7 +717,7 @@ class CI_DB_pdo_driver extends CI_DB { $tables = array($tables); } - return (count($tables) == 1) ? $tables[0] : '('.implode(', ', $tables).')'; + return (count($tables) == 1) ? '`'.$tables[0].'`' : '('.implode(', ', $tables).')'; } // -------------------------------------------------------------------- @@ -593,7 +735,7 @@ class CI_DB_pdo_driver extends CI_DB { */ function _insert($table, $keys, $values) { - return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + return 'INSERT INTO '.$this->_from_tables($table).' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')'; } // -------------------------------------------------------------------- @@ -611,7 +753,7 @@ class CI_DB_pdo_driver extends CI_DB { */ function _insert_batch($table, $keys, $values) { - return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values); + return 'INSERT INTO '.$this->_from_tables($table).' ('.implode(', ', $keys).') VALUES '.implode(', ', $values); } // -------------------------------------------------------------------- @@ -636,14 +778,11 @@ class CI_DB_pdo_driver extends CI_DB { $valstr[] = $key." = ".$val; } - $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - - $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; - - $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); - - $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + $orderby = (count($orderby) >= 1) ? ' ORDER BY '.implode(', ', $orderby) : ''; + $sql = 'UPDATE '.$this->_from_tables($table).' SET '.implode(', ', $valstr); + $sql .= ($where != '' && count($where) >= 1) ? ' WHERE '.implode(' ', $where) : ''; $sql .= $orderby.$limit; return $sql; @@ -664,8 +803,8 @@ class CI_DB_pdo_driver extends CI_DB { */ function _update_batch($table, $values, $index, $where = NULL) { - $ids = array(); - $where = ($where != '' AND count($where) >=1) ? implode(" ", $where).' AND ' : ''; + $ids = array(); + $where = ($where != '' && count($where) >=1) ? implode(" ", $where).' AND ' : ''; foreach ($values as $key => $val) { @@ -680,12 +819,13 @@ class CI_DB_pdo_driver extends CI_DB { } } - $sql = "UPDATE ".$table." SET "; + $sql = 'UPDATE '.$this->_from_tables($table).' SET '; $cases = ''; foreach ($final as $k => $v) { $cases .= $k.' = CASE '."\n"; + foreach ($v as $row) { $cases .= $row."\n"; @@ -695,7 +835,6 @@ class CI_DB_pdo_driver extends CI_DB { } $sql .= substr($cases, 0, -2); - $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')'; return $sql; @@ -739,19 +878,20 @@ class CI_DB_pdo_driver extends CI_DB { if (count($where) > 0 OR count($like) > 0) { - $conditions = "\nWHERE "; + $conditions = "\nWHERE "; $conditions .= implode("\n", $this->ar_where); if (count($where) > 0 && count($like) > 0) { $conditions .= " AND "; } + $conditions .= implode("\n", $like); } $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - return "DELETE FROM ".$table.$conditions.$limit; + return 'DELETE FROM '.$this->_from_tables($table).$conditions.$limit; } // -------------------------------------------------------------------- @@ -769,27 +909,16 @@ class CI_DB_pdo_driver extends CI_DB { */ function _limit($sql, $limit, $offset) { - if (strpos($this->hostname, 'cubrid') !== FALSE || strpos($this->hostname, 'sqlite') !== FALSE) + if ($this->pdodriver == 'cubrid' OR $this->pdodriver == 'sqlite') { - if ($offset == 0) - { - $offset = ''; - } - else - { - $offset .= ", "; - } + $offset = ($offset == 0) ? '' : $offset.', '; - return $sql."LIMIT ".$offset.$limit; + return $sql.'LIMIT '.$offset.$limit; } else { - $sql .= "LIMIT ".$limit; - - if ($offset > 0) - { - $sql .= " OFFSET ".$offset; - } + $sql .= 'LIMIT '.$limit; + $sql .= ($offset > 0) ? ' OFFSET '.$offset : ''; return $sql; } @@ -809,10 +938,7 @@ class CI_DB_pdo_driver extends CI_DB { $this->conn_id = null; } - } - - /* End of file pdo_driver.php */ /* Location: ./system/database/drivers/pdo/pdo_driver.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/pdo_forge.php b/system/database/drivers/pdo/pdo_forge.php index 076415928..478b2dbfb 100644 --- a/system/database/drivers/pdo/pdo_forge.php +++ b/system/database/drivers/pdo/pdo_forge.php @@ -96,7 +96,7 @@ class CI_DB_pdo_forge extends CI_DB_forge { $sql .= 'IF NOT EXISTS '; } - $sql .= $this->db->_escape_identifiers($table)." ("; + $sql .= '`'.$this->db->_escape_identifiers($table).'` ('; $current_field_count = 0; foreach ($fields as $field=>$attributes) @@ -111,6 +111,7 @@ class CI_DB_pdo_forge extends CI_DB_forge { else { $attributes = array_change_key_case($attributes, CASE_UPPER); + $numeric = array('SERIAL', 'INTEGER'); $sql .= "\n\t".$this->db->_protect_identifiers($field); @@ -118,7 +119,11 @@ class CI_DB_pdo_forge extends CI_DB_forge { if (array_key_exists('CONSTRAINT', $attributes)) { - $sql .= '('.$attributes['CONSTRAINT'].')'; + // Exception for Postgre numeric which not too happy with constraint within those type + if ( ! ($this->db->pdodriver == 'pgsql' && in_array($attributes['TYPE'], $numeric))) + { + $sql .= '('.$attributes['CONSTRAINT'].')'; + } } if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) @@ -219,7 +224,7 @@ class CI_DB_pdo_forge extends CI_DB_forge { */ function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') { - $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name); + $sql = 'ALTER TABLE `'.$this->db->_protect_identifiers($table)."` $alter_type ".$this->db->_protect_identifiers($column_name); // DROP has everything it needs now. if ($alter_type == 'DROP') @@ -271,7 +276,6 @@ class CI_DB_pdo_forge extends CI_DB_forge { return $sql; } - } /* End of file pdo_forge.php */ diff --git a/system/database/drivers/pdo/pdo_result.php b/system/database/drivers/pdo/pdo_result.php index 6b523b001..c333abc40 100644 --- a/system/database/drivers/pdo/pdo_result.php +++ b/system/database/drivers/pdo/pdo_result.php @@ -39,6 +39,16 @@ class CI_DB_pdo_result extends CI_DB_result { /** + * @var bool Hold the flag whether a result handler already fetched before + */ + protected $is_fetched = FALSE; + + /** + * @var mixed Hold the fetched assoc array of a result handler + */ + protected $result_assoc; + + /** * Number of rows in the result set * * @access public @@ -46,7 +56,59 @@ class CI_DB_pdo_result extends CI_DB_result { */ function num_rows() { - return $this->result_id->rowCount(); + if (empty($this->result_id) OR ! is_object($this->result_id)) + { + // invalid result handler + return 0; + } + elseif (($num_rows = $this->result_id->rowCount()) && $num_rows > 0) + { + // If rowCount return something, we're done. + return $num_rows; + } + + // Fetch the result, instead perform another extra query + return ($this->is_fetched && is_array($this->result_assoc)) ? count($this->result_assoc) : count($this->result_assoc()); + } + + /** + * Fetch the result handler + * + * @access public + * @return mixed + */ + function result_assoc() + { + // If the result already fetched before, use that one + if (count($this->result_array) > 0 OR $this->is_fetched) + { + return $this->result_array(); + } + + // Define the output + $output = array('assoc', 'object'); + + // Fetch the result + foreach ($output as $type) + { + // Define the method and handler + $res_method = '_fetch_'.$type; + $res_handler = 'result_'.$type; + + $this->$res_handler = array(); + $this->_data_seek(0); + + while ($row = $this->$res_method()) + { + $this->{$res_handler}[] = $row; + } + } + + // Save this as buffer and marked the fetch flag + $this->result_array = $this->result_assoc; + $this->is_fetched = TRUE; + + return $this->result_assoc; } // -------------------------------------------------------------------- @@ -78,6 +140,7 @@ class CI_DB_pdo_result extends CI_DB_result { { return $this->db->display_error('db_unsuported_feature'); } + return FALSE; } @@ -110,6 +173,7 @@ class CI_DB_pdo_result extends CI_DB_result { { return $this->db->display_error('db_unsuported_feature'); } + return FALSE; } } @@ -178,6 +242,5 @@ class CI_DB_pdo_result extends CI_DB_result { } - /* End of file pdo_result.php */ /* Location: ./system/database/drivers/pdo/pdo_result.php */
\ No newline at end of file diff --git a/system/libraries/Session.php b/system/libraries/Session.php index 04103a4d9..66b39a6a2 100644 --- a/system/libraries/Session.php +++ b/system/libraries/Session.php @@ -25,8 +25,6 @@ * @filesource */ -// ------------------------------------------------------------------------ - /** * Session Class * @@ -67,7 +65,7 @@ class CI_Session { */ public function __construct($params = array()) { - log_message('debug', "Session Class Initialized"); + log_message('debug', 'Session Class Initialized'); // Set the super object to a local variable for use throughout the class $this->CI =& get_instance(); @@ -93,14 +91,14 @@ class CI_Session { $this->CI->load->library('encrypt'); } - // Are we using a database? If so, load it - if ($this->sess_use_database === TRUE AND $this->sess_table_name != '') + // 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 + // 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 @@ -114,7 +112,7 @@ class CI_Session { $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. + // create a new one. If it does, we'll update it. if ( ! $this->sess_read()) { $this->sess_create(); @@ -133,7 +131,7 @@ class CI_Session { // Delete expired sessions if necessary $this->_sess_gc(); - log_message('debug', "Session routines successfully run"); + log_message('debug', 'Session routines successfully run'); } // -------------------------------------------------------------------- @@ -166,7 +164,7 @@ class CI_Session { $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 + // 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.'); @@ -179,7 +177,7 @@ class CI_Session { $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']) OR ! isset($session['ip_address']) OR ! isset($session['user_agent']) OR ! isset($session['last_activity'])) + if ( ! is_array($session) OR ! isset($session['session_id'], $session['ip_address'], $session['user_agent'], $session['last_activity'])) { $this->sess_destroy(); return FALSE; @@ -192,15 +190,15 @@ class CI_Session { return FALSE; } - // Does the IP Match? - if ($this->sess_match_ip == TRUE AND $session['ip_address'] !== $this->CI->input->ip_address()) + // 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 AND trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120))) + if ($this->sess_match_useragent == TRUE && trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120))) { $this->sess_destroy(); return FALSE; @@ -223,7 +221,7 @@ class CI_Session { $query = $this->CI->db->get($this->sess_table_name); - // No result? Kill it! + // No result? Kill it! if ($query->num_rows() === 0) { $this->sess_destroy(); @@ -232,7 +230,7 @@ class CI_Session { // Is there custom data? If so, add it to the main session array $row = $query->row(); - if (isset($row->user_data) AND $row->user_data != '') + if (isset($row->user_data) && $row->user_data != '') { $custom_data = $this->_unserialize($row->user_data); @@ -282,7 +280,7 @@ class CI_Session { $cookie_userdata[$val] = $this->userdata[$val]; } - // Did we find any custom data? If not, we turn the empty array into a string + // 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) { @@ -298,7 +296,7 @@ class CI_Session { $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 + // 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); @@ -324,13 +322,12 @@ class CI_Session { $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' => '' - ); - + '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) @@ -357,6 +354,35 @@ class CI_Session { 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']; @@ -374,10 +400,6 @@ class CI_Session { $this->userdata['session_id'] = $new_sessid = md5(uniqid($new_sessid, TRUE)); $this->userdata['last_activity'] = $this->now; - // _set_cookie() will handle this for us if we aren't using database sessions - // by pushing all userdata to the cookie. - $cookie_data = NULL; - // Update the session ID and last_activity field in the DB if needed if ($this->sess_use_database === TRUE) { @@ -405,7 +427,7 @@ class CI_Session { public function sess_destroy() { // Kill the session DB row - if ($this->sess_use_database === TRUE AND isset($this->userdata['session_id'])) + 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); @@ -413,13 +435,13 @@ class CI_Session { // Kill the cookie setcookie( - $this->sess_cookie_name, - addslashes(serialize(array())), - ($this->now - 31500000), - $this->cookie_path, - $this->cookie_domain, - 0 - ); + $this->sess_cookie_name, + addslashes(serialize(array())), + ($this->now - 31500000), + $this->cookie_path, + $this->cookie_domain, + 0 + ); } // -------------------------------------------------------------------- @@ -535,7 +557,7 @@ class CI_Session { */ public function keep_flashdata($key) { - // 'old' flashdata gets removed. Here we mark all + // 'old' flashdata gets removed. Here we mark all // flashdata as 'new' to preserve it from _flashdata_sweep() // Note the function will return FALSE if the $key // provided cannot be found @@ -586,7 +608,6 @@ class CI_Session { * * @return void */ - protected function _flashdata_sweep() { $userdata = $this->all_userdata(); @@ -609,13 +630,9 @@ class CI_Session { */ protected function _get_time() { - if (strtolower($this->time_reference) === 'gmt') - { - $now = time(); - return mktime(gmdate('H', $now), gmdate('i', $now), gmdate('s', $now), gmdate('m', $now), gmdate('d', $now), gmdate('Y', $now)); - } - - return time(); + return (strtolower($this->time_reference) === 'gmt') + ? mktime(gmdate('H'), gmdate('i'), gmdate('s'), gmdate('m'), gmdate('d'), gmdate('Y')) + : time(); } // -------------------------------------------------------------------- @@ -649,13 +666,13 @@ class CI_Session { // Set the cookie setcookie( - $this->sess_cookie_name, - $cookie_data, - $expire, - $this->cookie_path, - $this->cookie_domain, - $this->cookie_secure - ); + $this->sess_cookie_name, + $cookie_data, + $expire, + $this->cookie_path, + $this->cookie_domain, + $this->cookie_secure + ); } // -------------------------------------------------------------------- @@ -687,8 +704,11 @@ class CI_Session { * * This function converts any slashes found into a temporary marker * + * @param string + * @param string + * @return void */ - function _escape_slashes(&$val, $key) + protected function _escape_slashes(&$val, $key) { if (is_string($val)) { @@ -725,6 +745,9 @@ class CI_Session { * * This function converts any slash markers back into actual slashes * + * @param string + * @param string + * @return void */ protected function _unescape_slashes(&$val, $key) { @@ -763,9 +786,7 @@ class CI_Session { } } - } -// END Session Class /* End of file Session.php */ /* Location: ./system/libraries/Session.php */ diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst index 10f5507eb..649616e8d 100644 --- a/user_guide_src/source/changelog.rst +++ b/user_guide_src/source/changelog.rst @@ -49,6 +49,8 @@ Release Date: Not Released - Adding $escape parameter to the order_by function, this enables ordering by custom fields. - MySQLi driver now uses mysqli_get_server_info() for server version checking. - MySQLi driver now supports persistent connections when running on PHP >= 5.3. + - Added dsn if the group connections in the config use PDO or any driver which need DSN. + - Improved PDO database support. - Libraries @@ -100,6 +102,8 @@ Bug fixes for 3.0 - Fixed a bug (#561) - Errors in :doc:`XML-RPC Library <libraries/xmlrpc>` were not properly escaped. - Fixed a bug (#904) - ``CI_Loader::initialize()`` caused a PHP Fatal error to be triggered if error level E_STRICT is used. - Fixed a hosting edge case where an empty $_SERVER['HTTPS'] variable would evaluate to 'on' +- Fixed a bug (#154) - ``CI_Session::sess_update()`` caused the session to be destroyed on pages where multiple AJAX requests were executed at once. +- Fixed a possible bug in ``CI_Input::is_ajax_request()`` where some clients might not send the X-Requested-With HTTP header value exactly as 'XmlHttpRequest'. Version 2.1.0 ============= diff --git a/user_guide_src/source/database/configuration.rst b/user_guide_src/source/database/configuration.rst index 4f88c25ab..040e7e33f 100644 --- a/user_guide_src/source/database/configuration.rst +++ b/user_guide_src/source/database/configuration.rst @@ -28,6 +28,10 @@ prototype:: $db['default']['autoinit'] = TRUE; $db['default']['stricton'] = FALSE; +If you use PDO as your dbdriver, you can specify the full DSN string describe a connection to the database like this:: + + $db['default']['dsn'] = 'pgsql:host=localhost;port=5432;dbname=database_name'; + You can also specify failovers for the situation when the main connection cannot connect for some reason. These failovers can be specified by setting the failover for a connection like this:: |