From 0c259682f65eaaf23ea4ccb56a706d6baf3007e4 Mon Sep 17 00:00:00 2001 From: alecpl Date: Fri, 13 Apr 2012 08:52:02 +0000 Subject: - Merge devel-framework branch, resolved conflicts --- program/include/rcube_mdb2.php | 345 ++++++++++++++++++++++++++--------------- 1 file changed, 220 insertions(+), 125 deletions(-) (limited to 'program/include/rcube_mdb2.php') diff --git a/program/include/rcube_mdb2.php b/program/include/rcube_mdb2.php index c103f9a61..0139bdc65 100644 --- a/program/include/rcube_mdb2.php +++ b/program/include/rcube_mdb2.php @@ -59,10 +59,11 @@ class rcube_mdb2 * @param string $db_dsnw DSN for read/write operations * @param string $db_dsnr Optional DSN for read only operations */ - function __construct($db_dsnw, $db_dsnr='', $pconn=false) + public function __construct($db_dsnw, $db_dsnr='', $pconn=false) { - if (empty($db_dsnr)) + if (empty($db_dsnr)) { $db_dsnr = $db_dsnw; + } $this->db_dsnw = $db_dsnw; $this->db_dsnr = $db_dsnr; @@ -88,7 +89,8 @@ class rcube_mdb2 'emulate_prepared' => $this->debug_mode, 'debug' => $this->debug_mode, 'debug_handler' => array($this, 'debug_handler'), - 'portability' => MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL); + 'portability' => MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL, + ); if ($this->db_provider == 'pgsql') { $db_options['disable_smart_seqname'] = true; @@ -103,17 +105,19 @@ class rcube_mdb2 $this->db_error = true; $this->db_error_msg = $dbh->getMessage(); - raise_error(array('code' => 500, 'type' => 'db', + rcube::raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, 'message' => $dbh->getUserInfo()), true, false); } else if ($this->db_provider == 'sqlite') { $dsn_array = MDB2::parseDSN($dsn); - if (!filesize($dsn_array['database']) && !empty($this->sqlite_initials)) - $this->_sqlite_create_database($dbh, $this->sqlite_initials); + if (!filesize($dsn_array['database']) && !empty($this->sqlite_initials)) { + $this->sqlite_create_database($dbh, $this->sqlite_initials); + } } - else if ($this->db_provider!='mssql' && $this->db_provider!='sqlsrv') + else if ($this->db_provider != 'mssql' && $this->db_provider != 'sqlsrv') { $dbh->setCharset('utf8'); + } return $dbh; } @@ -123,9 +127,8 @@ class rcube_mdb2 * Connect to appropiate database depending on the operation * * @param string $mode Connection mode (r|w) - * @access public */ - function db_connect($mode) + public function db_connect($mode) { // previous connection failed, don't attempt to connect again if ($this->conn_failure) { @@ -157,10 +160,12 @@ class rcube_mdb2 $this->db_connected = !PEAR::isError($this->db_handle); } - if ($this->db_connected) + if ($this->db_connected) { $this->db_mode = $mode; - else + } + else { $this->conn_failure = true; + } } @@ -168,9 +173,8 @@ class rcube_mdb2 * Activate/deactivate debug mode * * @param boolean $dbg True if SQL queries should be logged - * @access public */ - function set_debug($dbg = true) + public function set_debug($dbg = true) { $this->debug_mode = $dbg; if ($this->db_connected) { @@ -184,9 +188,8 @@ class rcube_mdb2 * Getter for error state * * @param boolean True on error - * @access public */ - function is_error() + public function is_error() { return $this->db_error ? $this->db_error_msg : false; } @@ -196,9 +199,8 @@ class rcube_mdb2 * Connection state checker * * @param boolean True if in connected state - * @access public */ - function is_connected() + public function is_connected() { return PEAR::isError($this->db_handle) ? false : $this->db_connected; } @@ -208,7 +210,7 @@ class rcube_mdb2 * Is database replication configured? * This returns true if dsnw != dsnr */ - function is_replicated() + public function is_replicated() { return !empty($this->db_dsnr) && $this->db_dsnw != $this->db_dsnr; } @@ -219,17 +221,18 @@ class rcube_mdb2 * * @param string SQL query to execute * @param mixed Values to be inserted in query + * * @return number Query handle identifier - * @access public */ - function query() + public function query() { $params = func_get_args(); $query = array_shift($params); // Support one argument of type array, instead of n arguments - if (count($params) == 1 && is_array($params[0])) + if (count($params) == 1 && is_array($params[0])) { $params = $params[0]; + } return $this->_query($query, 0, 0, $params); } @@ -242,10 +245,10 @@ class rcube_mdb2 * @param number Offset for LIMIT statement * @param number Number of rows for LIMIT statement * @param mixed Values to be inserted in query + * * @return number Query handle identifier - * @access public */ - function limitquery() + public function limitquery() { $params = func_get_args(); $query = array_shift($params); @@ -274,17 +277,21 @@ class rcube_mdb2 $this->db_connect($mode); // check connection before proceeding - if (!$this->is_connected()) + if (!$this->is_connected()) { return null; + } - if ($this->db_provider == 'sqlite') - $this->_sqlite_prepare(); + if ($this->db_provider == 'sqlite') { + $this->sqlite_prepare(); + } - if ($numrows || $offset) + if ($numrows || $offset) { $result = $this->db_handle->setLimit($numrows,$offset); + } - if (empty($params)) + if (empty($params)) { $result = $mode == 'r' ? $this->db_handle->query($query) : $this->db_handle->exec($query); + } else { $params = (array)$params; $q = $this->db_handle->prepare($query, null, $mode=='w' ? MDB2_PREPARE_MANIP : null); @@ -292,7 +299,7 @@ class rcube_mdb2 $this->db_error = true; $this->db_error_msg = $q->userinfo; - raise_error(array('code' => 500, 'type' => 'db', + rcube::raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, 'message' => $this->db_error_msg), true, false); @@ -315,17 +322,18 @@ class rcube_mdb2 * * @param number $res_id Optional query handle identifier * @return mixed Number of rows or false on failure - * @access public */ - function num_rows($res_id=null) + public function num_rows($res_id=null) { - if (!$this->db_connected) + if (!$this->db_connected) { return false; + } - if ($result = $this->_get_result($res_id)) + if ($result = $this->_get_result($res_id)) { return $result->numRows(); - else - return false; + } + + return false; } @@ -334,12 +342,12 @@ class rcube_mdb2 * * @param number $res_id Optional query handle identifier * @return mixed Number of rows or false on failure - * @access public */ - function affected_rows($res_id = null) + public function affected_rows($res_id = null) { - if (!$this->db_connected) + if (!$this->db_connected) { return false; + } return $this->_get_result($res_id); } @@ -350,21 +358,24 @@ class rcube_mdb2 * For Postgres databases, a sequence name is required * * @param string $table Table name (to find the incremented sequence) + * * @return mixed ID or false on failure - * @access public */ - function insert_id($table = '') + public function insert_id($table = '') { - if (!$this->db_connected || $this->db_mode == 'r') + if (!$this->db_connected || $this->db_mode == 'r') { return false; + } if ($table) { - if ($this->db_provider == 'pgsql') + if ($this->db_provider == 'pgsql') { // find sequence name - $table = get_sequence_name($table); - else + $table = $this->sequence_name($table); + } + else { // resolve table name - $table = get_table_name($table); + $table = $this->table_name($table); + } } $id = $this->db_handle->lastInsertID($table); @@ -378,10 +389,10 @@ class rcube_mdb2 * If no query handle is specified, the last query will be taken as reference * * @param number $res_id Optional query handle identifier + * * @return mixed Array with col values or false on failure - * @access public */ - function fetch_assoc($res_id=null) + public function fetch_assoc($res_id = null) { $result = $this->_get_result($res_id); return $this->_fetch_row($result, MDB2_FETCHMODE_ASSOC); @@ -393,10 +404,10 @@ class rcube_mdb2 * If no query handle is specified, the last query will be taken as reference * * @param number $res_id Optional query handle identifier + * * @return mixed Array with col values or false on failure - * @access public */ - function fetch_array($res_id=null) + public function fetch_array($res_id = null) { $result = $this->_get_result($res_id); return $this->_fetch_row($result, MDB2_FETCHMODE_ORDERED); @@ -408,13 +419,14 @@ class rcube_mdb2 * * @param MDB2_Result_Common Query $result result handle * @param number $mode Fetch mode identifier - * @return mixed Array with col values or false on failure - * @access private + * + * @return mixed Array with col values or false on failure */ private function _fetch_row($result, $mode) { - if ($result === false || PEAR::isError($result) || !$this->is_connected()) + if ($result === false || PEAR::isError($result) || !$this->is_connected()) { return false; + } return $result->fetchRow($mode); } @@ -424,18 +436,19 @@ class rcube_mdb2 * Wrapper for the SHOW TABLES command * * @return array List of all tables of the current database - * @access public * @since 0.4-beta */ - function list_tables() + public function list_tables() { // get tables if not cached if (!$this->tables) { $this->db_handle->loadModule('Manager'); - if (!PEAR::isError($result = $this->db_handle->listTables())) + if (!PEAR::isError($result = $this->db_handle->listTables())) { $this->tables = $result; - else + } + else { $this->tables = array(); + } } return $this->tables; @@ -446,9 +459,10 @@ class rcube_mdb2 * Wrapper for SHOW COLUMNS command * * @param string Table name + * * @return array List of table cols */ - function list_cols($table) + public function list_cols($table) { $this->db_handle->loadModule('Manager'); if (!PEAR::isError($result = $this->db_handle->listTableFields($table))) { @@ -464,18 +478,20 @@ class rcube_mdb2 * * @param mixed $input Value to quote * @param string $type Type of data + * * @return string Quoted/converted string for use in query - * @access public */ - function quote($input, $type = null) + public function quote($input, $type = null) { // handle int directly for better performance - if ($type == 'integer') + if ($type == 'integer') { return intval($input); + } // create DB handle if not available - if (!$this->db_handle) + if (!$this->db_handle) { $this->db_connect('r'); + } return $this->db_connected ? $this->db_handle->quote($input, $type) : addslashes($input); } @@ -485,12 +501,12 @@ class rcube_mdb2 * Quotes a string so it can be safely used as a table or column name * * @param string $str Value to quote + * * @return string Quoted string for use in query * @deprecated Replaced by rcube_MDB2::quote_identifier * @see rcube_mdb2::quote_identifier - * @access public */ - function quoteIdentifier($str) + public function quoteIdentifier($str) { return $this->quote_identifier($str); } @@ -500,13 +516,14 @@ class rcube_mdb2 * Quotes a string so it can be safely used as a table or column name * * @param string $str Value to quote + * * @return string Quoted string for use in query - * @access public */ - function quote_identifier($str) + public function quote_identifier($str) { - if (!$this->db_handle) + if (!$this->db_handle) { $this->db_connect('r'); + } return $this->db_connected ? $this->db_handle->quoteIdentifier($str) : $str; } @@ -516,14 +533,15 @@ class rcube_mdb2 * Escapes a string * * @param string $str The string to be escaped + * * @return string The escaped string - * @access public * @since 0.1.1 */ - function escapeSimple($str) + public function escapeSimple($str) { - if (!$this->db_handle) + if (!$this->db_handle) { $this->db_connect('r'); + } return $this->db_handle->escape($str); } @@ -533,9 +551,8 @@ class rcube_mdb2 * Return SQL function for current time and date * * @return string SQL function to use in query - * @access public */ - function now() + public function now() { switch ($this->db_provider) { case 'mssql': @@ -553,16 +570,18 @@ class rcube_mdb2 * * @param array $arr Input array * @param string $type Type of data + * * @return string Comma-separated list of quoted values for use in query - * @access public */ - function array2list($arr, $type = null) + public function array2list($arr, $type = null) { - if (!is_array($arr)) + if (!is_array($arr)) { return $this->quote($arr, $type); + } - foreach ($arr as $idx => $item) + foreach ($arr as $idx => $item) { $arr[$idx] = $this->quote($item, $type); + } return implode(',', $arr); } @@ -575,10 +594,11 @@ class rcube_mdb2 * of timestamp functions in Mysql (year 2038 problem) * * @param string $field Field name + * * @return string SQL statement to use in query * @deprecated */ - function unixtimestamp($field) + public function unixtimestamp($field) { switch($this->db_provider) { case 'pgsql': @@ -598,10 +618,10 @@ class rcube_mdb2 * Return SQL statement to convert from a unix timestamp * * @param string $timestamp Field name + * * @return string SQL statement to use in query - * @access public */ - function fromunixtime($timestamp) + public function fromunixtime($timestamp) { return date("'Y-m-d H:i:s'", $timestamp); } @@ -612,13 +632,13 @@ class rcube_mdb2 * * @param string $column Field name * @param string $value Search value + * * @return string SQL statement to use in query - * @access public */ - function ilike($column, $value) + public function ilike($column, $value) { // TODO: use MDB2's matchPattern() function - switch($this->db_provider) { + switch ($this->db_provider) { case 'pgsql': return $this->quote_identifier($column).' ILIKE '.$this->quote($value); default: @@ -626,20 +646,20 @@ class rcube_mdb2 } } + /** * Abstract SQL statement for value concatenation * * @return string SQL statement to be used in query - * @access public */ - function concat(/* col1, col2, ... */) + public function concat(/* col1, col2, ... */) { $func = ''; $args = func_get_args(); if (is_array($args[0])) $args = $args[0]; - switch($this->db_provider) { + switch ($this->db_provider) { case 'mysql': case 'mysqli': $func = 'CONCAT'; @@ -661,20 +681,22 @@ class rcube_mdb2 * Encodes non-UTF-8 characters in string/array/object (recursive) * * @param mixed $input Data to fix + * * @return mixed Properly UTF-8 encoded data - * @access public */ - function encode($input) + public static function encode($input) { if (is_object($input)) { - foreach (get_object_vars($input) as $idx => $value) - $input->$idx = $this->encode($value); + foreach (get_object_vars($input) as $idx => $value) { + $input->$idx = self::encode($value); + } return $input; } else if (is_array($input)) { - foreach ($input as $idx => $value) - $input[$idx] = $this->encode($value); - return $input; + foreach ($input as $idx => $value) { + $input[$idx] = self::encode($value); + } + return $input; } return utf8_encode($input); @@ -685,20 +707,22 @@ class rcube_mdb2 * Decodes encoded UTF-8 string/object/array (recursive) * * @param mixed $input Input data + * * @return mixed Decoded data - * @access public */ - function decode($input) + public static function decode($input) { if (is_object($input)) { - foreach (get_object_vars($input) as $idx => $value) - $input->$idx = $this->decode($value); + foreach (get_object_vars($input) as $idx => $value) { + $input->$idx = self::decode($value); + } return $input; } else if (is_array($input)) { - foreach ($input as $idx => $value) - $input[$idx] = $this->decode($value); - return $input; + foreach ($input as $idx => $value) { + $input[$idx] = self::decode($value); + } + return $input; } return utf8_decode($input); @@ -709,8 +733,8 @@ class rcube_mdb2 * Adds a query result and returns a handle ID * * @param object $res Query handle + * * @return mixed Handle ID - * @access private */ private function _add_result($res) { @@ -718,7 +742,7 @@ class rcube_mdb2 if (PEAR::isError($res)) { $this->db_error = true; $this->db_error_msg = $res->getMessage(); - raise_error(array('code' => 500, 'type' => 'db', + rcube::raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, 'message' => $res->getMessage() . " Query: " . substr(preg_replace('/[\r\n]+\s*/', ' ', $res->userinfo), 0, 512)), @@ -737,17 +761,20 @@ class rcube_mdb2 * If no ID is specified, the last resource handle will be returned * * @param number $res_id Handle ID + * * @return mixed Resource handle or false on failure - * @access private */ private function _get_result($res_id = null) { - if ($res_id == null) + if ($res_id == null) { $res_id = $this->last_res_id; + } - if (isset($this->a_query_results[$res_id])) - if (!PEAR::isError($this->a_query_results[$res_id])) + if (isset($this->a_query_results[$res_id])) { + if (!PEAR::isError($this->a_query_results[$res_id])) { return $this->a_query_results[$res_id]; + } + } return false; } @@ -758,42 +785,36 @@ class rcube_mdb2 * * @param MDB2 $dbh SQLite database handle * @param string $file_name File path to use for DB creation - * @access private */ - private function _sqlite_create_database($dbh, $file_name) + private function sqlite_create_database($dbh, $file_name) { - if (empty($file_name) || !is_string($file_name)) + if (empty($file_name) || !is_string($file_name)) { return; + } $data = file_get_contents($file_name); - if (strlen($data)) - if (!sqlite_exec($dbh->connection, $data, $error) || MDB2::isError($dbh)) - raise_error(array('code' => 500, 'type' => 'db', + if (strlen($data)) { + if (!sqlite_exec($dbh->connection, $data, $error) || MDB2::isError($dbh)) { + rcube::raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, - 'message' => $error), true, false); + 'message' => $error), true, false); + } + } } /** * Add some proprietary database functions to the current SQLite handle * in order to make it MySQL compatible - * - * @access private */ - private function _sqlite_prepare() + private function sqlite_prepare() { - include_once(INSTALL_PATH . 'program/include/rcube_sqlite.inc'); - - // we emulate via callback some missing MySQL function - sqlite_create_function($this->db_handle->connection, - 'from_unixtime', 'rcube_sqlite_from_unixtime'); + // we emulate via callback some missing MySQL functions sqlite_create_function($this->db_handle->connection, - 'unix_timestamp', 'rcube_sqlite_unix_timestamp'); + 'unix_timestamp', array('rcube_mdb2', 'sqlite_unix_timestamp')); sqlite_create_function($this->db_handle->connection, - 'now', 'rcube_sqlite_now'); - sqlite_create_function($this->db_handle->connection, - 'md5', 'rcube_sqlite_md5'); + 'now', array('rcube_mdb2', 'sqlite_now')); } @@ -805,8 +826,82 @@ class rcube_mdb2 if ($scope != 'prepare') { $debug_output = sprintf('%s(%d): %s;', $scope, $db->db_index, rtrim($message, ';')); - write_log('sql', $debug_output); + rcmail::write_log('sql', $debug_output); } } -} // end class rcube_db + + /** + * Return correct name for a specific database table + * + * @param string $table Table name + * + * @return string Translated table name + */ + public function table_name($table) + { + $rcmail = rcube::get_instance(); + + // return table name if configured + $config_key = 'db_table_'.$table; + + if ($name = $rcmail->config->get($config_key)) { + return $name; + } + + return $table; + } + + + /** + * Return correct name for a specific database sequence + * (used for Postgres only) + * + * @param string $sequence Secuence name + * + * @return string Translated sequence name + */ + public function sequence_name($sequence) + { + $rcmail = rcube::get_instance(); + + // return sequence name if configured + $config_key = 'db_sequence_'.$sequence; + + if ($name = $rcmail->config->get($config_key)) { + return $name; + } + + return $sequence; + } + + + /** + * Callback for sqlite: unix_timestamp() + */ + public static function sqlite_unix_timestamp($timestamp = '') + { + $timestamp = trim($timestamp); + if (!$timestamp) { + $ret = time(); + } + else if (!preg_match('/^[0-9]+$/s', $timestamp)) { + $ret = strtotime($timestamp); + } + else { + $ret = $timestamp; + } + + return $ret; + } + + + /** + * Callback for sqlite: now() + */ + public static function sqlite_now() + { + return date("Y-m-d H:i:s"); + } + +} -- cgit v1.2.3