Finished message sorting and fixed some skin issues
6 files added
27 files modified
| | |
| | | - Get IMAP server capabilities in array |
| | | - Check for NAMESPACE capability before sending command |
| | | - Set default user language from config 'locale_string' |
| | | - Added sorting patch (not finished yet) |
| | | - Added sorting patch for message list |
| | | - Make default sort col/order configurable |
| | | - |
| | |
| | | $rcmail_config['prettydate'] = TRUE; |
| | | $rcmail_config['smtp_port'] = 25; |
| | | $rcmail_config['default_port'] = 143; |
| | | $rcmail_config['session_lifetime'] = 20; |
| | | $rcmail_config['message_sort_col'] = 'date'; |
| | | $rcmail_config['message_sort_order'] = 'DESC'; |
| | | - replace database properties (db_type, db_host, db_user, db_pass, $d_name) |
| | | in /config/db.inc.php with the following line: |
| | | $rcmail_config['db_dsnw'] = 'mysql://roundcube:pass@localhost/roundcubemail'; |
| | |
| | | $rcmail_config['prettydate'] = TRUE; |
| | | $rcmail_config['smtp_port'] = 25; |
| | | $rcmail_config['default_port'] = 143; |
| | | $rcmail_config['session_lifetime'] = 20; |
| | | $rcmail_config['message_sort_col'] = 'date'; |
| | | $rcmail_config['message_sort_order'] = 'DESC'; |
| | | - replace database properties (db_type, db_host, db_user, db_pass, $d_name) |
| | | in /config/db.inc.php with the following line: |
| | | $rcmail_config['db_dsnw'] = 'mysql://roundcube:pass@localhost/roundcubemail'; |
| | |
| | | - replace index.php |
| | | - replace all files in folder /program/ |
| | | - replace all files in folder /skins/default/ |
| | | - add $rcmail_config['smtp_auth_type'] if you need to specify an auth method for SMTP |
| | | - $rcmail_config['session_lifetime'] to specify the session lifetime in minutes |
| | | - add these lines to /config/main.inc.php |
| | | $rcmail_config['smtp_auth_type'] = ''; // if you need to specify an auth method for SMTP |
| | | $rcmail_config['session_lifetime'] = 20; // to specify the session lifetime in minutes |
| | | $rcmail_config['message_sort_col'] = 'date'; |
| | | $rcmail_config['message_sort_order'] = 'DESC'; |
| | | |
| | | |
| | | from version 0.1-20051021 |
| | | ---------------------------------------- |
| | | - replace index.php |
| | | - replace all files in folder /program/ |
| | | - replace all files in folder /skins/default/ |
| | | - add these lines to /config/main.inc.php |
| | | $rcmail_config['message_sort_col'] = 'date'; |
| | | $rcmail_config['message_sort_order'] = 'DESC'; |
| | |
| | | // display these folders separately in the mailbox list |
| | | $rcmail_config['default_imap_folders'] = array('INBOX', 'Drafts', 'Sent', 'Junk', 'Trash'); |
| | | |
| | | // default sort col |
| | | $rcmail_config['message_sort_col'] = 'date'; |
| | | |
| | | // default sort order |
| | | $rcmail_config['message_sort_order'] = 'DESC'; |
| | | |
| | | |
| | | |
| | | /***** these settings can be overwritten by user's preferences *****/ |
| | | |
| | |
| | | |
| | | // show pretty dates as standard |
| | | $rcmail_config['prettydate'] = TRUE; |
| | | |
| | | |
| | | // end of config file |
| | | ?> |
| | |
| | | */ |
| | | |
| | | // define global vars |
| | | $INSTALL_PATH = './'; |
| | | $INSTALL_PATH = dirname($_SERVER['SCRIPT_FILENAME']); |
| | | $OUTPUT_TYPE = 'html'; |
| | | $JS_OBJECT_NAME = 'rcmail'; |
| | | $CURRENT_PATH = dirname($_SERVER['SCRIPT_FILENAME']); |
| | | |
| | | if ($CURRENT_PATH!='') |
| | | $CURRENT_PATH.='/'; |
| | | if ($INSTALL_PATH!='') |
| | | $INSTALL_PATH .= '/'; |
| | | |
| | | // set environment first |
| | | // RC include folders MUST be included FIRST to avoid other |
| | | // possible not compatible libraries (i.e PEAR) to be included |
| | | // instead the ones provided by RC |
| | | ini_set('include_path', $INSTALL_PATH.PATH_SEPARATOR.$CURRENT_PATH.'program'.PATH_SEPARATOR.$CURRENT_PATH.'program/lib'.PATH_SEPARATOR.ini_get('include_path')); |
| | | ini_set('include_path', $INSTALL_PATH.PATH_SEPARATOR.$INSTALL_PATH.'program'.PATH_SEPARATOR.$INSTALL_PATH.'program/lib'.PATH_SEPARATOR.ini_get('include_path')); |
| | | |
| | | ini_set('session.name', 'sessid'); |
| | | ini_set('session.use_cookies', 1); |
| | |
| | | } |
| | | |
| | | // check session cookie and auth string |
| | | else if ($_action!='login' && $_auth && $sess_auth) |
| | | else if ($_action!='login' && $sess_auth) |
| | | { |
| | | if ($_auth !== $sess_auth || $_auth != rcmail_auth_hash($_SESSION['client_id'], $_SESSION['auth_time']) || |
| | | ($CONFIG['session_lifetime'] && $SESS_CHANGED + $CONFIG['session_lifetime']*60 < mktime())) |
| | |
| | | |
| | | if (is_numeric($date)) |
| | | $ts = $date; |
| | | else |
| | | else if (!empty($date)) |
| | | $ts = strtotime($date); |
| | | else |
| | | return ''; |
| | | |
| | | // convert time to user's timezone |
| | | $timestamp = $ts - date('Z', $ts) + ($CONFIG['timezone'] * 3600); |
| | |
| | | } |
| | | |
| | | |
| | | // old function; replaced 2005/10/18 |
| | | // original function; replaced 2005/10/18 |
| | | // private method for listing message header |
| | | function _list_headers($mailbox='', $page=NULL, $sort_field='date', $sort_order='DESC') |
| | | { |
| | |
| | | // return complete list of messages |
| | | if (strtolower($page)=='all') |
| | | return $a_headers; |
| | | |
| | | |
| | | $start_msg = ($this->list_page-1) * $this->page_size; |
| | | return array_slice($a_headers, $start_msg, $this->page_size); |
| | | } |
| | |
| | | function dsn_connect($dsn) |
| | | { |
| | | // Use persistent connections if available |
| | | $dbh = MDB2::factory($dsn, array('persistent' => $true)); |
| | | $dbh = MDB2::factory($dsn, array('persistent' => TRUE)); |
| | | |
| | | if (PEAR::isError($dbh)) |
| | | raise_error(array('code' => 500, |
| | |
| | | // Query database |
| | | |
| | | function query() |
| | | |
| | | { |
| | | |
| | | $params = func_get_args(); |
| | | |
| | | $query = array_shift($params); |
| | | |
| | | |
| | | |
| | | return $this->_query($query, 0, 0, $params); |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | function limitquery() |
| | | |
| | | { |
| | | |
| | | $params = func_get_args(); |
| | | |
| | | $query = array_shift($params); |
| | | |
| | | $offset = array_shift($params); |
| | | |
| | | $numrows = array_shift($params); |
| | | |
| | | |
| | | |
| | | return $this->_query($query, $offset, $numrows, $params); |
| | | |
| | | } |
| | | |
| | | function _query($query, $offset, $numrows, $params) |
| | |
| | | } |
| | | |
| | | function quoteIdentifier ( $str ) |
| | | |
| | | { |
| | | |
| | | if (!$this->db_handle) |
| | | |
| | | $this->db_connect('r'); |
| | | |
| | | |
| | | |
| | | return $this->db_handle->quoteIdentifier($str); |
| | | |
| | | } |
| | | |
| | | function unixtimestamp($field) |
| | | |
| | | { |
| | | |
| | | switch($this->db_provider) |
| | | |
| | | { |
| | | |
| | | case 'pgsql': |
| | | |
| | | return "EXTRACT (EPOCH FROM $field)"; |
| | | |
| | | break; |
| | | |
| | | default: |
| | | |
| | | return "UNIX_TIMESTAMP($field)"; |
| | | |
| | | } |
| | | |
| | | } |
| | | |
| | | function _add_result($res, $query) |
| | |
| | | | Copyright (C) 2005, RoundCube Dev, - Switzerland | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | | Modified: 2005/10/21 (roundcube) | |
| | | | Modified: 2005/10/26 (roundcube) | |
| | | | | |
| | | +-----------------------------------------------------------------------+ |
| | | | Author: Thomas Bruederli <roundcube@gmail.com> | |
| | |
| | | |
| | | case 'sort': |
| | | // get the type of sorting |
| | | var a_sort = props.split('_'); |
| | | var sort_col = a_sort[0]; |
| | | var sort_order = a_sort[1].toUpperCase(); |
| | | var header; |
| | | |
| | | if (this.env.sort_col==sort_col && this.env.sort_order==sort_order) |
| | | break; |
| | | |
| | | // set table header class |
| | | if (header = document.getElementById('rcmHead'+this.env.sort_col)) |
| | | this.set_classname(header, 'sorted'+(this.env.sort_order.toUpperCase()), false); |
| | | if (header = document.getElementById('rcmHead'+sort_col)) |
| | | this.set_classname(header, 'sorted'+sort_order, true); |
| | | |
| | | // save new sort properties |
| | | this.env.sort_col = sort_col; |
| | | this.env.sort_order = sort_order; |
| | | |
| | | // reload message list |
| | | this.list_mailbox('', '', props); |
| | | break; |
| | | |
New file |
| | |
| | | <?php |
| | | // vim: set et ts=4 sw=4 fdm=marker: |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Datatype/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 MySQL driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | */ |
| | | class MDB2_Driver_Datatype_mysql extends MDB2_Driver_Datatype_Common |
| | | { |
| | | // }}} |
| | | // {{{ _getIntegerDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an integer type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param string $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. |
| | | * Currently, the types of supported field |
| | | * properties are as follows: |
| | | * |
| | | * unsigned |
| | | * Boolean flag that indicates whether the field |
| | | * should be declared as unsigned integer if |
| | | * possible. |
| | | * |
| | | * default |
| | | * Integer value to be used as default for this |
| | | * field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is |
| | | * constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getIntegerDeclaration($name, $field) |
| | | { |
| | | if (array_key_exists('autoincrement', $field) && $field['autoincrement']) { |
| | | $autoinc = ' AUTO_INCREMENT PRIMARY KEY'; |
| | | $default = ''; |
| | | } else { |
| | | $autoinc = ''; |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'integer') : ''; |
| | | } |
| | | |
| | | $unsigned = (array_key_exists('unsigned', $field) && $field['unsigned']) ? ' UNSIGNED' : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' INT'.$unsigned.$default.$notnull.$autoinc; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getCLOBDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an character |
| | | * large object type field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param string $field associative array with the name of the |
| | | * properties of the field being declared as array |
| | | * indexes. Currently, the types of supported field |
| | | * properties are as follows: |
| | | * |
| | | * length |
| | | * Integer value that determines the maximum length |
| | | * of the large object field. If this argument is |
| | | * missing the field should be declared to have the |
| | | * longest length allowed by the DBMS. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field |
| | | * is constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getCLOBDeclaration($name, $field) |
| | | { |
| | | if (array_key_exists('length', $field)) { |
| | | $length = $field['length']; |
| | | if ($length <= 255) { |
| | | $type = 'TINYTEXT'; |
| | | } else { |
| | | if ($length <= 65535) { |
| | | $type = 'TEXT'; |
| | | } else { |
| | | if ($length <= 16777215) { |
| | | $type = 'MEDIUMTEXT'; |
| | | } else { |
| | | $type = 'LONGTEXT'; |
| | | } |
| | | } |
| | | } |
| | | } else { |
| | | $type = 'LONGTEXT'; |
| | | } |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$type.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getBLOBDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an binary large |
| | | * object type field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param string $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. |
| | | * Currently, the types of supported field |
| | | * properties are as follows: |
| | | * |
| | | * length |
| | | * Integer value that determines the maximum length |
| | | * of the large object field. If this argument is |
| | | * missing the field should be declared to have the |
| | | * longest length allowed by the DBMS. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is |
| | | * constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getBLOBDeclaration($name, $field) |
| | | { |
| | | if (array_key_exists('length', $field)) { |
| | | $length = $field['length']; |
| | | if ($length <= 255) { |
| | | $type = 'TINYBLOB'; |
| | | } else { |
| | | if ($length <= 65535) { |
| | | $type = 'BLOB'; |
| | | } else { |
| | | if ($length <= 16777215) { |
| | | $type = 'MEDIUMBLOB'; |
| | | } else { |
| | | $type = 'LONGBLOB'; |
| | | } |
| | | } |
| | | } |
| | | } else { |
| | | $type = 'LONGBLOB'; |
| | | } |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$type.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getDateDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an date type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param string $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. |
| | | * Currently, the types of supported field properties |
| | | * are as follows: |
| | | * |
| | | * default |
| | | * Date value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is |
| | | * constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getDateDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'date') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' DATE'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTimestampDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an timestamp |
| | | * type field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param string $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. |
| | | * Currently, the types of supported field |
| | | * properties are as follows: |
| | | * |
| | | * default |
| | | * Time stamp value to be used as default for this |
| | | * field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is |
| | | * constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTimestampDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'timestamp') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' DATETIME'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTimeDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an time type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param string $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. |
| | | * Currently, the types of supported field |
| | | * properties are as follows: |
| | | * |
| | | * default |
| | | * Time value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is |
| | | * constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTimeDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'time') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' TIME'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getFloatDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an float type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param string $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. |
| | | * Currently, the types of supported field |
| | | * properties are as follows: |
| | | * |
| | | * default |
| | | * Integer value to be used as default for this |
| | | * field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is |
| | | * constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getFloatDeclaration($name, $field) |
| | | { |
| | | $type = 'DOUBLE'; |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'float') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$type.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getDecimalDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an decimal type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param string $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. |
| | | * Currently, the types of supported field |
| | | * properties are as follows: |
| | | * |
| | | * default |
| | | * Integer value to be used as default for this |
| | | * field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is |
| | | * constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getDecimalDeclaration($name, $field) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $type = 'DECIMAL(18,'.$db->options['decimal_places'].')'; |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'decimal') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$type.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteBLOB() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param $value |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteBLOB($value) |
| | | { |
| | | $value = $this->_readFile($value); |
| | | return "'".addslashes($value)."'"; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteFloat() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteFloat($value) |
| | | { |
| | | return (float)$value; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteDecimal() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteDecimal($value) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->escape($value); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ mapNativeDatatype() |
| | | |
| | | /** |
| | | * Maps a native array description of a field to a MDB2 datatype and length |
| | | * |
| | | * @param array $field native field description |
| | | * @return array containing the various possible types and the length |
| | | * @access public |
| | | */ |
| | | function mapNativeDatatype($field) |
| | | { |
| | | $db_type = strtolower($field['type']); |
| | | $db_type = strtok($db_type, '(), '); |
| | | if ($db_type == 'national') { |
| | | $db_type = strtok('(), '); |
| | | } |
| | | $length = strtok('(), '); |
| | | $decimal = strtok('(), '); |
| | | $type = array(); |
| | | switch ($db_type) { |
| | | case 'tinyint': |
| | | case 'smallint': |
| | | case 'mediumint': |
| | | case 'int': |
| | | case 'integer': |
| | | case 'bigint': |
| | | $type[] = 'integer'; |
| | | if ($length == '1') { |
| | | $type[] = 'boolean'; |
| | | if (preg_match('/^[is|has]/', $field['field'])) { |
| | | $type = array_reverse($type); |
| | | } |
| | | } |
| | | break; |
| | | case 'char': |
| | | case 'varchar': |
| | | $type[] = 'text'; |
| | | if ($length == '1') { |
| | | $type[] = 'boolean'; |
| | | if (preg_match('/[is|has]/', $field['field'])) { |
| | | $type = array_reverse($type); |
| | | } |
| | | } |
| | | break; |
| | | case 'enum': |
| | | preg_match_all('/\'.+\'/U', $field['type'], $matches); |
| | | $length = 0; |
| | | if (is_array($matches)) { |
| | | foreach ($matches[0] as $value) { |
| | | $length = max($length, strlen($value)-2); |
| | | } |
| | | } |
| | | case 'set': |
| | | $type[] = 'text'; |
| | | $type[] = 'integer'; |
| | | break; |
| | | case 'date': |
| | | $type[] = 'date'; |
| | | $length = null; |
| | | break; |
| | | case 'datetime': |
| | | case 'timestamp': |
| | | $type[] = 'timestamp'; |
| | | $length = null; |
| | | break; |
| | | case 'time': |
| | | $type[] = 'time'; |
| | | $length = null; |
| | | break; |
| | | case 'float': |
| | | case 'double': |
| | | case 'real': |
| | | $type[] = 'float'; |
| | | break; |
| | | case 'decimal': |
| | | case 'numeric': |
| | | $type[] = 'decimal'; |
| | | break; |
| | | case 'tinytext': |
| | | case 'mediumtext': |
| | | case 'longtext': |
| | | case 'text': |
| | | if ($decimal == 'binary') { |
| | | $type[] = 'blob'; |
| | | } |
| | | $type[] = 'clob'; |
| | | $type[] = 'text'; |
| | | break; |
| | | case 'tinyblob': |
| | | case 'mediumblob': |
| | | case 'longblob': |
| | | case 'blob': |
| | | $type[] = 'blob'; |
| | | $type[] = 'text'; |
| | | $length = null; |
| | | break; |
| | | case 'year': |
| | | $type[] = 'integer'; |
| | | $type[] = 'date'; |
| | | $length = null; |
| | | break; |
| | | default: |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'getTableFieldDefinition: unknown database attribute type'); |
| | | } |
| | | |
| | | return array($type, $length); |
| | | } |
| | | } |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Manager/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 MySQL driver for the management modules |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | */ |
| | | class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common |
| | | { |
| | | // {{{ properties |
| | | var $verified_table_types = array();# |
| | | // }}} |
| | | |
| | | // }}} |
| | | // {{{ _verifyTableType() |
| | | |
| | | /** |
| | | * verify that chosen transactional table hanlder is available in the database |
| | | * |
| | | * @param string $table_type name of the table handler |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access protected |
| | | */ |
| | | function _verifyTableType($table_type) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | switch (strtoupper($table_type)) { |
| | | case 'BERKELEYDB': |
| | | case 'BDB': |
| | | $check = array('have_bdb'); |
| | | break; |
| | | case 'INNODB': |
| | | $check = array('have_innobase', 'have_innodb'); |
| | | break; |
| | | case 'GEMINI': |
| | | $check = array('have_gemini'); |
| | | break; |
| | | case 'HEAP': |
| | | case 'ISAM': |
| | | case 'MERGE': |
| | | case 'MRG_MYISAM': |
| | | case 'MYISAM': |
| | | case '': |
| | | return MDB2_OK; |
| | | default: |
| | | return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, |
| | | $table_type.' is not a supported table type'); |
| | | } |
| | | if (isset($this->verified_table_types[$table_type]) |
| | | && $this->verified_table_types[$table_type] == $db->connection |
| | | ) { |
| | | return MDB2_OK; |
| | | } |
| | | $not_supported = false; |
| | | for ($i = 0, $j = count($check); $i < $j; ++$i) { |
| | | $query = 'SHOW VARIABLES LIKE '.$db->quote($check[$i], 'text'); |
| | | $has = $db->queryRow($query, null, MDB2_FETCHMODE_ORDERED); |
| | | if (PEAR::isError($has)) { |
| | | return $has; |
| | | } |
| | | if (is_array($has)) { |
| | | $not_supported = true; |
| | | if ($has[1] == 'YES') { |
| | | $this->verified_table_types[$table_type] = $db->connection; |
| | | return MDB2_OK; |
| | | } |
| | | } |
| | | } |
| | | if ($not_supported) { |
| | | return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, |
| | | $table_type.' is not a supported table type by this MySQL database server'); |
| | | } |
| | | return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, |
| | | 'could not tell if '.$table_type.' is a supported table type'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ createDatabase() |
| | | |
| | | /** |
| | | * create a new database |
| | | * |
| | | * @param string $name name of the database that should be created |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function createDatabase($name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $query = 'CREATE DATABASE '.$name; |
| | | $result = $db->query($query); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ dropDatabase() |
| | | |
| | | /** |
| | | * drop an existing database |
| | | * |
| | | * @param string $name name of the database that should be dropped |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function dropDatabase($name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $query = 'DROP DATABASE '.$name; |
| | | $result = $db->query($query); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ createTable() |
| | | |
| | | /** |
| | | * create a new table |
| | | * |
| | | * @param string $name Name of the database that should be created |
| | | * @param array $fields Associative array that contains the definition of each field of the new table |
| | | * The indexes of the array entries are the names of the fields of the table an |
| | | * the array entry values are associative arrays like those that are meant to be |
| | | * passed with the field definitions to get[Type]Declaration() functions. |
| | | * |
| | | * Example |
| | | * array( |
| | | * |
| | | * 'id' => array( |
| | | * 'type' => 'integer', |
| | | * 'unsigned' => 1 |
| | | * 'notnull' => 1 |
| | | * 'default' => 0 |
| | | * ), |
| | | * 'name' => array( |
| | | * 'type' => 'text', |
| | | * 'length' => 12 |
| | | * ), |
| | | * 'password' => array( |
| | | * 'type' => 'text', |
| | | * 'length' => 12 |
| | | * ) |
| | | * ); |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function createTable($name, $fields) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | if (!$name) { |
| | | return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, |
| | | 'createTable: no valid table name specified'); |
| | | } |
| | | if (empty($fields)) { |
| | | return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, |
| | | 'createTable: no fields specified for table "'.$name.'"'); |
| | | } |
| | | $verify = $this->_verifyTableType($db->options['default_table_type']); |
| | | if (PEAR::isError($verify)) { |
| | | return $verify; |
| | | } |
| | | $query_fields = $this->getFieldDeclarationList($fields); |
| | | if (PEAR::isError($query_fields)) { |
| | | return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, |
| | | 'createTable: '.$this->getUserinfo()); |
| | | } |
| | | $query = "CREATE TABLE $name ($query_fields)".(strlen($db->options['default_table_type']) |
| | | ? ' TYPE='.$db->options['default_table_type'] : ''); |
| | | |
| | | return $db->query($query); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ alterTable() |
| | | |
| | | /** |
| | | * alter an existing table |
| | | * |
| | | * @param string $name name of the table that is intended to be changed. |
| | | * @param array $changes associative array that contains the details of each type |
| | | * of change that is intended to be performed. The types of |
| | | * changes that are currently supported are defined as follows: |
| | | * |
| | | * name |
| | | * |
| | | * New name for the table. |
| | | * |
| | | * add |
| | | * |
| | | * Associative array with the names of fields to be added as |
| | | * indexes of the array. The value of each entry of the array |
| | | * should be set to another associative array with the properties |
| | | * of the fields to be added. The properties of the fields should |
| | | * be the same as defined by the Metabase parser. |
| | | * |
| | | * |
| | | * remove |
| | | * |
| | | * Associative array with the names of fields to be removed as indexes |
| | | * of the array. Currently the values assigned to each entry are ignored. |
| | | * An empty array should be used for future compatibility. |
| | | * |
| | | * rename |
| | | * |
| | | * Associative array with the names of fields to be renamed as indexes |
| | | * of the array. The value of each entry of the array should be set to |
| | | * another associative array with the entry named name with the new |
| | | * field name and the entry named Declaration that is expected to contain |
| | | * the portion of the field declaration already in DBMS specific SQL code |
| | | * as it is used in the CREATE TABLE statement. |
| | | * |
| | | * change |
| | | * |
| | | * Associative array with the names of the fields to be changed as indexes |
| | | * of the array. Keep in mind that if it is intended to change either the |
| | | * name of a field and any other properties, the change array entries |
| | | * should have the new names of the fields as array indexes. |
| | | * |
| | | * The value of each entry of the array should be set to another associative |
| | | * array with the properties of the fields to that are meant to be changed as |
| | | * array entries. These entries should be assigned to the new values of the |
| | | * respective properties. The properties of the fields should be the same |
| | | * as defined by the Metabase parser. |
| | | * |
| | | * Example |
| | | * array( |
| | | * 'name' => 'userlist', |
| | | * 'add' => array( |
| | | * 'quota' => array( |
| | | * 'type' => 'integer', |
| | | * 'unsigned' => 1 |
| | | * ) |
| | | * ), |
| | | * 'remove' => array( |
| | | * 'file_limit' => array(), |
| | | * 'time_limit' => array() |
| | | * ), |
| | | * 'change' => array( |
| | | * 'gender' => array( |
| | | * 'default' => 'M', |
| | | * ) |
| | | * ), |
| | | * 'rename' => array( |
| | | * 'sex' => array( |
| | | * 'name' => 'gender', |
| | | * ) |
| | | * ) |
| | | * ) |
| | | * |
| | | * @param boolean $check indicates whether the function should just check if the DBMS driver |
| | | * can perform the requested table alterations if the value is true or |
| | | * actually perform them otherwise. |
| | | * @access public |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | */ |
| | | function alterTable($name, $changes, $check) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | foreach ($changes as $change_name => $change) { |
| | | switch ($change_name) { |
| | | case 'add': |
| | | case 'remove': |
| | | case 'change': |
| | | case 'rename': |
| | | case 'name': |
| | | break; |
| | | default: |
| | | return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null, |
| | | 'alterTable: change type "'.$change_name.'" not yet supported'); |
| | | } |
| | | } |
| | | |
| | | if ($check) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | $query = (array_key_exists('name', $changes) ? 'RENAME AS '.$changes['name'] : ''); |
| | | |
| | | if (array_key_exists('add', $changes)) { |
| | | foreach ($changes['add'] as $field_name => $field) { |
| | | $type_declaration = $db->getDeclaration($field['type'], $field_name, $field); |
| | | if (PEAR::isError($type_declaration)) { |
| | | return $err; |
| | | } |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $query.= 'ADD ' . $type_declaration; |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('remove', $changes)) { |
| | | foreach ($changes['remove'] as $field_name => $field) { |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $query.= 'DROP ' . $field_name; |
| | | } |
| | | } |
| | | |
| | | $rename = array(); |
| | | if (array_key_exists('rename', $changes)) { |
| | | foreach ($changes['rename'] as $field_name => $field) { |
| | | $rename[$field['name']] = $field_name; |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('change', $changes)) { |
| | | foreach ($changes['change'] as $field_name => $field) { |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | if (isset($rename[$field_name])) { |
| | | $old_field_name = $rename[$field_name]; |
| | | unset($rename[$field_name]); |
| | | } else { |
| | | $old_field_name = $field_name; |
| | | } |
| | | $query.= "CHANGE $field_name " . $db->getDeclaration($field['type'], $old_field_name, $field); |
| | | } |
| | | } |
| | | |
| | | if (!empty($rename)) { |
| | | foreach ($rename as $rename_name => $renamed_field) { |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $old_field_name = $renamed_field; |
| | | $field = $changes['rename'][$old_field_name]; |
| | | $query.= 'CHANGE ' . $db->getDeclaration($field['type'], $old_field_name, $field); |
| | | } |
| | | } |
| | | |
| | | if (!$query) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | return $db->query("ALTER TABLE $name $query"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listDatabases() |
| | | |
| | | /** |
| | | * list all databases |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listDatabases() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $databases = $db->queryCol('SHOW DATABASES'); |
| | | return $databases; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listUsers() |
| | | |
| | | /** |
| | | * list all users |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listUsers() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $users = $db->queryCol('SELECT DISTINCT USER FROM USER'); |
| | | return $users; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTables() |
| | | |
| | | /** |
| | | * list all tables in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTables() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $table_names = $db->queryCol('SHOW TABLES'); |
| | | if (PEAR::isError($table_names)) { |
| | | return $table_names; |
| | | } |
| | | |
| | | $tables = array(); |
| | | for ($i = 0, $j = count($table_names); $i < $j; ++$i) { |
| | | if (!$this->_isSequenceName($table_names[$i])) |
| | | $tables[] = $table_names[$i]; |
| | | } |
| | | |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | $tables = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $tables); |
| | | } |
| | | |
| | | return $tables; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTableFields() |
| | | |
| | | /** |
| | | * list all fields in a tables in the current database |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTableFields($table) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $fields = $db->queryCol("SHOW COLUMNS FROM $table"); |
| | | if (PEAR::isError($fields)) { |
| | | return $fields; |
| | | } |
| | | |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | $fields = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $fields); |
| | | } |
| | | |
| | | return $fields; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ createIndex() |
| | | |
| | | /** |
| | | * get the stucture of a field into an array |
| | | * |
| | | * @param string $table name of the table on which the index is to be created |
| | | * @param string $name name of the index to be created |
| | | * @param array $definition associative array that defines properties of the index to be created. |
| | | * Currently, only one property named FIELDS is supported. This property |
| | | * is also an associative with the names of the index fields as array |
| | | * indexes. Each entry of this array is set to another type of associative |
| | | * array that specifies properties of the index that are specific to |
| | | * each field. |
| | | * |
| | | * Currently, only the sorting property is supported. It should be used |
| | | * to define the sorting direction of the index. It may be set to either |
| | | * ascending or descending. |
| | | * |
| | | * Not all DBMS support index sorting direction configuration. The DBMS |
| | | * drivers of those that do not support it ignore this property. Use the |
| | | * function supports() to determine whether the DBMS driver can manage indexes. |
| | | |
| | | * Example |
| | | * array( |
| | | * 'fields' => array( |
| | | * 'user_name' => array( |
| | | * 'sorting' => 'ascending' |
| | | * ), |
| | | * 'last_login' => array() |
| | | * ) |
| | | * ) |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function createIndex($table, $name, $definition) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | if (array_key_exists('primary', $definition) && $definition['primary']) { |
| | | $type = 'PRIMARY'; |
| | | $name = 'KEY'; |
| | | } elseif (array_key_exists('unique', $definition) && $definition['unique']) { |
| | | $type = 'UNIQUE'; |
| | | } else { |
| | | $type = 'INDEX'; |
| | | } |
| | | |
| | | $query = "ALTER TABLE $table ADD $type $name ("; |
| | | $query.= implode(', ', array_keys($definition['fields'])); |
| | | $query.= ')'; |
| | | |
| | | return $db->query($query); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ dropIndex() |
| | | |
| | | /** |
| | | * drop existing index |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @param string $name name of the index to be dropped |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function dropIndex($table, $name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->query("ALTER TABLE $table DROP INDEX $name"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTableIndexes() |
| | | |
| | | /** |
| | | * list all indexes in a table |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTableIndexes($table) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $key_name = 'Key_name'; |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | if ($db->options['field_case'] == CASE_LOWER) { |
| | | $key_name = strtolower($key_name); |
| | | } else { |
| | | $key_name = strtoupper($key_name); |
| | | } |
| | | } |
| | | |
| | | $query = "SHOW INDEX FROM $table"; |
| | | $indexes_all = $db->queryCol($query, 'text', $key_name); |
| | | if (PEAR::isError($indexes_all)) { |
| | | return $indexes_all; |
| | | } |
| | | |
| | | $indexes = array_unique($indexes_all); |
| | | |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | $indexes = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $indexes); |
| | | } |
| | | |
| | | return $indexes; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ createSequence() |
| | | |
| | | /** |
| | | * create sequence |
| | | * |
| | | * @param string $seq_name name of the sequence to be created |
| | | * @param string $start start value of the sequence; default is 1 |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function createSequence($seq_name, $start = 1) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $sequence_name = $db->getSequenceName($seq_name); |
| | | $seqcol_name = $db->options['seqcol_name']; |
| | | $result = $this->_verifyTableType($db->options['default_table_type']); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | |
| | | $res = $db->query("CREATE TABLE $sequence_name". |
| | | "($seqcol_name INT NOT NULL AUTO_INCREMENT, PRIMARY KEY ($seqcol_name))". |
| | | (strlen($db->options['default_table_type']) ? ' TYPE='.$db->options['default_table_type'] : '') |
| | | ); |
| | | |
| | | if (PEAR::isError($res)) { |
| | | return $res; |
| | | } |
| | | |
| | | if ($start == 1) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | $res = $db->query("INSERT INTO $sequence_name ($seqcol_name) VALUES (".($start-1).')'); |
| | | if (!PEAR::isError($res)) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // Handle error |
| | | $result = $db->query("DROP TABLE $sequence_name"); |
| | | if (PEAR::isError($result)) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'createSequence: could not drop inconsistent sequence table ('. |
| | | $result->getMessage().' ('.$result->getUserinfo().'))'); |
| | | } |
| | | |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'createSequence: could not create sequence table ('. |
| | | $res->getMessage().' ('.$res->getUserinfo().'))'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ dropSequence() |
| | | |
| | | /** |
| | | * drop existing sequence |
| | | * |
| | | * @param string $seq_name name of the sequence to be dropped |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function dropSequence($seq_name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $sequence_name = $db->getSequenceName($seq_name); |
| | | return $db->query("DROP TABLE $sequence_name"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listSequences() |
| | | |
| | | /** |
| | | * list all sequences in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listSequences() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $table_names = $db->queryCol('SHOW TABLES'); |
| | | if (PEAR::isError($table_names)) { |
| | | return $table_names; |
| | | } |
| | | |
| | | $sequences = array(); |
| | | for ($i = 0, $j = count($table_names); $i < $j; ++$i) { |
| | | if ($sqn = $this->_isSequenceName($table_names[$i])) { |
| | | $sequences[] = $sqn; |
| | | } |
| | | } |
| | | |
| | | return $sequences; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | /** |
| | | * MDB2 MySQL driver for the native module |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | */ |
| | | class MDB2_Driver_Native_mysql extends MDB2_Module_Common |
| | | { |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Reverse/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 MySQL driver for the schema reverse engineering module |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | */ |
| | | class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_Common |
| | | { |
| | | // {{{ getTableFieldDefinition() |
| | | |
| | | /** |
| | | * get the stucture of a field into an array |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @param string $field_name name of field that should be used in method |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function getTableFieldDefinition($table, $field_name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $result = $db->loadModule('Datatype'); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $columns = $db->queryAll("SHOW COLUMNS FROM $table", null, MDB2_FETCHMODE_ASSOC); |
| | | if (PEAR::isError($columns)) { |
| | | return $columns; |
| | | } |
| | | foreach ($columns as $column) { |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | if ($db->options['field_case'] == CASE_LOWER) { |
| | | $column['field'] = strtolower($column['field']); |
| | | } else { |
| | | $column['field'] = strtoupper($column['field']); |
| | | } |
| | | } else { |
| | | $column = array_change_key_case($column, $db->options['field_case']); |
| | | } |
| | | if ($field_name == $column['field']) { |
| | | list($types, $length) = $db->datatype->mapNativeDatatype($column); |
| | | $notnull = false; |
| | | if (array_key_exists('null', $column) && $column['null'] != 'YES') { |
| | | $notnull = true; |
| | | } |
| | | $default = false; |
| | | if (array_key_exists('default', $column)) { |
| | | $default = $column['default']; |
| | | if (is_null($default) && $notnull) { |
| | | $default = ''; |
| | | } |
| | | } |
| | | $autoincrement = false; |
| | | if (array_key_exists('extra', $column) && $column['extra'] == 'auto_increment') { |
| | | $autoincrement = true; |
| | | } |
| | | $definition = array(); |
| | | foreach ($types as $key => $type) { |
| | | $definition[$key] = array( |
| | | 'type' => $type, |
| | | 'notnull' => $notnull, |
| | | ); |
| | | if ($length > 0) { |
| | | $definition[$key]['length'] = $length; |
| | | } |
| | | if ($default !== false) { |
| | | $definition[$key]['default'] = $default; |
| | | } |
| | | if ($autoincrement !== false) { |
| | | $definition[$key]['autoincrement'] = $autoincrement; |
| | | } |
| | | } |
| | | return $definition; |
| | | } |
| | | } |
| | | |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'getTableFieldDefinition: it was not specified an existing table column'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getTableIndexDefinition() |
| | | |
| | | /** |
| | | * get the stucture of an index into an array |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @param string $index_name name of index that should be used in method |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function getTableIndexDefinition($table, $index_name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $result = $db->query("SHOW INDEX FROM $table"); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $definition = array(); |
| | | while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) { |
| | | if (!($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) |
| | | || $db->options['field_case'] != CASE_LOWER |
| | | ) { |
| | | $row = array_change_key_case($row, CASE_LOWER); |
| | | } |
| | | $key_name = $row['key_name']; |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | if ($db->options['field_case'] == CASE_LOWER) { |
| | | $key_name = strtolower($key_name); |
| | | } else { |
| | | $key_name = strtoupper($key_name); |
| | | } |
| | | } |
| | | if ($index_name == $key_name) { |
| | | if ($row['key_name'] == 'PRIMARY') { |
| | | $definition['primary'] = true; |
| | | } elseif (!$row['non_unique']) { |
| | | $definition['unique'] = true; |
| | | } |
| | | $column_name = $row['column_name']; |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | if ($db->options['field_case'] == CASE_LOWER) { |
| | | $column_name = strtolower($column_name); |
| | | } else { |
| | | $column_name = strtoupper($column_name); |
| | | } |
| | | } |
| | | $definition['fields'][$column_name] = array(); |
| | | if (array_key_exists('collation', $row)) { |
| | | $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A' |
| | | ? 'ascending' : 'descending'); |
| | | } |
| | | } |
| | | } |
| | | $result->free(); |
| | | if (!array_key_exists('fields', $definition)) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'getTableIndexDefinition: it was not specified an existing table index'); |
| | | } |
| | | return $definition; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ tableInfo() |
| | | |
| | | /** |
| | | * Returns information about a table or a result set |
| | | * |
| | | * @param object|string $result MDB2_result object from a query or a |
| | | * string containing the name of a table. |
| | | * While this also accepts a query result |
| | | * resource identifier, this behavior is |
| | | * deprecated. |
| | | * @param int $mode a valid tableInfo mode |
| | | * |
| | | * @return array an associative array with the information requested. |
| | | * A MDB2_Error object on failure. |
| | | * |
| | | * @see MDB2_Driver_Common::setOption() |
| | | */ |
| | | function tableInfo($result, $mode = null) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | if (is_string($result)) { |
| | | /* |
| | | * Probably received a table name. |
| | | * Create a result resource identifier. |
| | | */ |
| | | $connected = $db->connect(); |
| | | if (PEAR::isError($connected)) { |
| | | return $connected; |
| | | } |
| | | $id = @mysql_list_fields($db->database_name, $result, $db->connection); |
| | | $got_string = true; |
| | | } elseif (MDB2::isResultCommon($result)) { |
| | | /* |
| | | * Probably received a result object. |
| | | * Extract the result resource identifier. |
| | | */ |
| | | $id = $result->getResource(); |
| | | $got_string = false; |
| | | } else { |
| | | /* |
| | | * Probably received a result resource identifier. |
| | | * Copy it. |
| | | * Deprecated. Here for compatibility only. |
| | | */ |
| | | $id = $result; |
| | | $got_string = false; |
| | | } |
| | | |
| | | if (!is_resource($id)) { |
| | | return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA); |
| | | } |
| | | |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | if ($db->options['field_case'] == CASE_LOWER) { |
| | | $case_func = 'strtolower'; |
| | | } else { |
| | | $case_func = 'strtoupper'; |
| | | } |
| | | } else { |
| | | $case_func = 'strval'; |
| | | } |
| | | |
| | | $count = @mysql_num_fields($id); |
| | | $res = array(); |
| | | |
| | | if ($mode) { |
| | | $res['num_fields'] = $count; |
| | | } |
| | | |
| | | for ($i = 0; $i < $count; $i++) { |
| | | $res[$i] = array( |
| | | 'table' => $case_func(@mysql_field_table($id, $i)), |
| | | 'name' => $case_func(@mysql_field_name($id, $i)), |
| | | 'type' => @mysql_field_type($id, $i), |
| | | 'len' => @mysql_field_len($id, $i), |
| | | 'flags' => @mysql_field_flags($id, $i), |
| | | ); |
| | | if ($mode & MDB2_TABLEINFO_ORDER) { |
| | | $res['order'][$res[$i]['name']] = $i; |
| | | } |
| | | if ($mode & MDB2_TABLEINFO_ORDERTABLE) { |
| | | $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
| | | } |
| | | } |
| | | |
| | | // free the result only if we were called on a table |
| | | if ($got_string) { |
| | | @mysql_free_result($id); |
| | | } |
| | | return $res; |
| | | } |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // vim: set et ts=4 sw=4 fdm=marker: |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | /** |
| | | * MDB2 MySQL driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | */ |
| | | class MDB2_Driver_mysql extends MDB2_Driver_Common |
| | | { |
| | | // {{{ properties |
| | | var $escape_quotes = "\\"; |
| | | |
| | | // }}} |
| | | // {{{ constructor |
| | | |
| | | /** |
| | | * Constructor |
| | | */ |
| | | function __construct() |
| | | { |
| | | parent::__construct(); |
| | | |
| | | $this->phptype = 'mysql'; |
| | | $this->dbsyntax = 'mysql'; |
| | | |
| | | $this->supported['sequences'] = 'emulated'; |
| | | $this->supported['indexes'] = true; |
| | | $this->supported['affected_rows'] = true; |
| | | $this->supported['transactions'] = false; |
| | | $this->supported['summary_functions'] = true; |
| | | $this->supported['order_by_text'] = true; |
| | | $this->supported['current_id'] = 'emulated'; |
| | | $this->supported['limit_queries'] = true; |
| | | $this->supported['LOBs'] = true; |
| | | $this->supported['replace'] = true; |
| | | $this->supported['sub_selects'] = 'emulated'; |
| | | $this->supported['auto_increment'] = true; |
| | | $this->supported['primary_key'] = true; |
| | | |
| | | $this->options['default_table_type'] = null; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ errorInfo() |
| | | |
| | | /** |
| | | * This method is used to collect information about an error |
| | | * |
| | | * @param integer $error |
| | | * @return array |
| | | * @access public |
| | | */ |
| | | function errorInfo($error = null) |
| | | { |
| | | if ($this->connection) { |
| | | $native_code = @mysql_errno($this->connection); |
| | | $native_msg = @mysql_error($this->connection); |
| | | } else { |
| | | $native_code = @mysql_errno(); |
| | | $native_msg = @mysql_error(); |
| | | } |
| | | if (is_null($error)) { |
| | | static $ecode_map; |
| | | if (empty($ecode_map)) { |
| | | $ecode_map = array( |
| | | 1004 => MDB2_ERROR_CANNOT_CREATE, |
| | | 1005 => MDB2_ERROR_CANNOT_CREATE, |
| | | 1006 => MDB2_ERROR_CANNOT_CREATE, |
| | | 1007 => MDB2_ERROR_ALREADY_EXISTS, |
| | | 1008 => MDB2_ERROR_CANNOT_DROP, |
| | | 1022 => MDB2_ERROR_ALREADY_EXISTS, |
| | | 1044 => MDB2_ERROR_ACCESS_VIOLATION, |
| | | 1046 => MDB2_ERROR_NODBSELECTED, |
| | | 1048 => MDB2_ERROR_CONSTRAINT, |
| | | 1049 => MDB2_ERROR_NOSUCHDB, |
| | | 1050 => MDB2_ERROR_ALREADY_EXISTS, |
| | | 1051 => MDB2_ERROR_NOSUCHTABLE, |
| | | 1054 => MDB2_ERROR_NOSUCHFIELD, |
| | | 1061 => MDB2_ERROR_ALREADY_EXISTS, |
| | | 1062 => MDB2_ERROR_ALREADY_EXISTS, |
| | | 1064 => MDB2_ERROR_SYNTAX, |
| | | 1091 => MDB2_ERROR_NOT_FOUND, |
| | | 1100 => MDB2_ERROR_NOT_LOCKED, |
| | | 1136 => MDB2_ERROR_VALUE_COUNT_ON_ROW, |
| | | 1142 => MDB2_ERROR_ACCESS_VIOLATION, |
| | | 1146 => MDB2_ERROR_NOSUCHTABLE, |
| | | 1216 => MDB2_ERROR_CONSTRAINT, |
| | | 1217 => MDB2_ERROR_CONSTRAINT, |
| | | ); |
| | | } |
| | | if ($this->options['portability'] & MDB2_PORTABILITY_ERRORS) { |
| | | $ecode_map[1022] = MDB2_ERROR_CONSTRAINT; |
| | | $ecode_map[1048] = MDB2_ERROR_CONSTRAINT_NOT_NULL; |
| | | $ecode_map[1062] = MDB2_ERROR_CONSTRAINT; |
| | | } else { |
| | | // Doing this in case mode changes during runtime. |
| | | $ecode_map[1022] = MDB2_ERROR_ALREADY_EXISTS; |
| | | $ecode_map[1048] = MDB2_ERROR_CONSTRAINT; |
| | | $ecode_map[1062] = MDB2_ERROR_ALREADY_EXISTS; |
| | | } |
| | | if (isset($ecode_map[$native_code])) { |
| | | $error = $ecode_map[$native_code]; |
| | | } |
| | | } |
| | | return array($error, $native_code, $native_msg); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ escape() |
| | | |
| | | /** |
| | | * Quotes a string so it can be safely used in a query. It will quote |
| | | * the text so it can safely be used within a query. |
| | | * |
| | | * @param string $text the input string to quote |
| | | * @return string quoted string |
| | | * @access public |
| | | */ |
| | | function escape($text) |
| | | { |
| | | return @mysql_real_escape_string($text); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ quoteIdentifier() |
| | | |
| | | /** |
| | | * Quote a string so it can be safely used as a table or column name |
| | | * |
| | | * Quoting style depends on which database driver is being used. |
| | | * |
| | | * MySQL can't handle the backtick character (<kbd>`</kbd>) in |
| | | * table or column names. |
| | | * |
| | | * @param string $str identifier name to be quoted |
| | | * |
| | | * @return string quoted identifier string |
| | | * |
| | | * @access public |
| | | * @internal |
| | | */ |
| | | function quoteIdentifier($str) |
| | | { |
| | | return '`' . $str . '`'; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ beginTransaction() |
| | | |
| | | /** |
| | | * Start a transaction. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function beginTransaction() |
| | | { |
| | | $this->debug('starting transaction', 'beginTransaction'); |
| | | if (!$this->supports('transactions')) { |
| | | return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, |
| | | 'beginTransaction: transactions are not in use'); |
| | | } |
| | | if ($this->in_transaction) { |
| | | return MDB2_OK; //nothing to do |
| | | } |
| | | if (!$this->destructor_registered && $this->opened_persistent) { |
| | | $this->destructor_registered = true; |
| | | register_shutdown_function('MDB2_closeOpenTransactions'); |
| | | } |
| | | $result = $this->_doQuery('SET AUTOCOMMIT = 0', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $this->in_transaction = true; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ commit() |
| | | |
| | | /** |
| | | * Commit the database changes done during a transaction that is in |
| | | * progress. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function commit() |
| | | { |
| | | $this->debug('commit transaction', 'commit'); |
| | | if (!$this->supports('transactions')) { |
| | | return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, |
| | | 'commit: transactions are not in use'); |
| | | } |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'commit: transaction changes are being auto committed'); |
| | | } |
| | | $result = $this->_doQuery('COMMIT', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $result = $this->_doQuery('SET AUTOCOMMIT = 1', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $this->in_transaction = false; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ rollback() |
| | | |
| | | /** |
| | | * Cancel any database changes done during a transaction that is in |
| | | * progress. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function rollback() |
| | | { |
| | | $this->debug('rolling back transaction', 'rollback'); |
| | | if (!$this->supports('transactions')) { |
| | | return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, |
| | | 'rollback: transactions are not in use'); |
| | | } |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'rollback: transactions can not be rolled back when changes are auto committed'); |
| | | } |
| | | $result = $this->_doQuery('ROLLBACK', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $result = $this->_doQuery('SET AUTOCOMMIT = 1', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $this->in_transaction = false; |
| | | return MDB2_OK; |
| | | |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ connect() |
| | | |
| | | /** |
| | | * Connect to the database |
| | | * |
| | | * @return true on success, MDB2 Error Object on failure |
| | | */ |
| | | function connect() |
| | | { |
| | | if (is_resource($this->connection)) { |
| | | if (count(array_diff($this->connected_dsn, $this->dsn)) == 0 |
| | | && $this->opened_persistent == $this->options['persistent'] |
| | | ) { |
| | | return MDB2_OK; |
| | | } |
| | | $this->disconnect(false); |
| | | } |
| | | |
| | | if (!PEAR::loadExtension($this->phptype)) { |
| | | return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, |
| | | 'connect: extension '.$this->phptype.' is not compiled into PHP'); |
| | | } |
| | | |
| | | $params = array(); |
| | | if ($this->dsn['protocol'] && $this->dsn['protocol'] == 'unix') { |
| | | $params[0] = ':' . $this->dsn['socket']; |
| | | } else { |
| | | $params[0] = $this->dsn['hostspec'] ? $this->dsn['hostspec'] |
| | | : 'localhost'; |
| | | if ($this->dsn['port']) { |
| | | $params[0].= ':' . $this->dsn['port']; |
| | | } |
| | | } |
| | | $params[] = $this->dsn['username'] ? $this->dsn['username'] : null; |
| | | $params[] = $this->dsn['password'] ? $this->dsn['password'] : null; |
| | | if (!$this->options['persistent']) { |
| | | if (isset($this->dsn['new_link']) |
| | | && ($this->dsn['new_link'] == 'true' || $this->dsn['new_link'] === true) |
| | | ) { |
| | | $params[] = true; |
| | | } else { |
| | | $params[] = false; |
| | | } |
| | | } |
| | | if (version_compare(phpversion(), '4.3.0', '>=')) { |
| | | $params[] = isset($this->dsn['client_flags']) |
| | | ? $this->dsn['client_flags'] : null; |
| | | } |
| | | |
| | | $connect_function = $this->options['persistent'] ? 'mysql_pconnect' : 'mysql_connect'; |
| | | |
| | | @ini_set('track_errors', true); |
| | | $php_errormsg = ''; |
| | | $connection = @call_user_func_array($connect_function, $params); |
| | | @ini_restore('track_errors'); |
| | | if (!$connection) { |
| | | if (($err = @mysql_error()) != '') { |
| | | return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null, $err); |
| | | } else { |
| | | return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null, $php_errormsg); |
| | | } |
| | | } |
| | | |
| | | $this->connection = $connection; |
| | | $this->connected_dsn = $this->dsn; |
| | | $this->connected_database_name = ''; |
| | | $this->opened_persistent = $this->options['persistent']; |
| | | $this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype; |
| | | |
| | | $this->supported['transactions'] = false; |
| | | if ($this->options['default_table_type']) { |
| | | switch (strtoupper($this->options['default_table_type'])) { |
| | | case 'BERKELEYDB': |
| | | $this->options['default_table_type'] = 'BDB'; |
| | | case 'BDB': |
| | | case 'INNODB': |
| | | case 'GEMINI': |
| | | $this->supported['transactions'] = true; |
| | | break; |
| | | case 'HEAP': |
| | | case 'ISAM': |
| | | case 'MERGE': |
| | | case 'MRG_MYISAM': |
| | | case 'MYISAM': |
| | | break; |
| | | default: |
| | | $this->warnings[] = $default_table_type. |
| | | ' is not a supported default table type'; |
| | | } |
| | | } |
| | | |
| | | if ($this->options['use_transactions'] && !$this->supports('transactions')) { |
| | | $this->warnings[] = $this->options['default_table_type']. |
| | | ' is not a transaction-safe default table type; switched to INNODB'; |
| | | $this->options['default_table_type'] = 'INNODB'; |
| | | $this->supported['transactions'] = true; |
| | | } |
| | | |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ disconnect() |
| | | |
| | | /** |
| | | * Log out and disconnect from the database. |
| | | * |
| | | * @return mixed true on success, false if not connected and error |
| | | * object on error |
| | | * @access public |
| | | */ |
| | | function disconnect($force = true) |
| | | { |
| | | if (is_resource($this->connection)) { |
| | | if (!$this->opened_persistent || $force) { |
| | | @mysql_close($this->connection); |
| | | } |
| | | $this->connection = 0; |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _doQuery() |
| | | |
| | | /** |
| | | * Execute a query |
| | | * @param string $query query |
| | | * @param boolean $isManip if the query is a manipulation query |
| | | * @param resource $connection |
| | | * @param string $database_name |
| | | * @return result or error object |
| | | * @access protected |
| | | */ |
| | | function _doQuery($query, $isManip = false, $connection = null, $database_name = null) |
| | | { |
| | | $this->last_query = $query; |
| | | $this->debug($query, 'query'); |
| | | if ($this->options['disable_query']) { |
| | | if ($isManip) { |
| | | return 0; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | if (is_null($connection)) { |
| | | $err = $this->connect(); |
| | | if (PEAR::isError($err)) { |
| | | return $err; |
| | | } |
| | | $connection = $this->connection; |
| | | } |
| | | if (is_null($database_name)) { |
| | | $database_name = $this->database_name; |
| | | } |
| | | |
| | | if ($database_name) { |
| | | if ($database_name != $this->connected_database_name) { |
| | | if (!@mysql_select_db($database_name, $connection)) { |
| | | return $this->raiseError(); |
| | | } |
| | | $this->connected_database_name = $database_name; |
| | | } |
| | | } |
| | | |
| | | $function = $this->options['result_buffering'] |
| | | ? 'mysql_query' : 'mysql_unbuffered_query'; |
| | | $result = @$function($query, $connection); |
| | | if (!$result) { |
| | | return $this->raiseError(); |
| | | } |
| | | |
| | | if ($isManip) { |
| | | return @mysql_affected_rows($connection); |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _modifyQuery() |
| | | |
| | | /** |
| | | * Changes a query string for various DBMS specific reasons |
| | | * |
| | | * @param string $query query to modify |
| | | * @return the new (modified) query |
| | | * @access protected |
| | | */ |
| | | function _modifyQuery($query, $isManip, $limit, $offset) |
| | | { |
| | | if ($this->options['portability'] & MDB2_PORTABILITY_DELETE_COUNT) { |
| | | // "DELETE FROM table" gives 0 affected rows in MySQL. |
| | | // This little hack lets you know how many rows were deleted. |
| | | if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) { |
| | | $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/', |
| | | 'DELETE FROM \1 WHERE 1=1', $query); |
| | | } |
| | | } |
| | | if ($limit > 0 |
| | | && !preg_match('/LIMIT\s*\d(\s*(,|OFFSET)\s*\d+)?/i', $query) |
| | | ) { |
| | | $query = rtrim($query); |
| | | if (substr($query, -1) == ';') { |
| | | $query = substr($query, 0, -1); |
| | | } |
| | | if ($isManip) { |
| | | return $query . " LIMIT $limit"; |
| | | } else { |
| | | return $query . " LIMIT $offset, $limit"; |
| | | } |
| | | } |
| | | return $query; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ replace() |
| | | |
| | | /** |
| | | * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT |
| | | * query, except that if there is already a row in the table with the same |
| | | * key field values, the REPLACE query just updates its values instead of |
| | | * inserting a new row. |
| | | * |
| | | * The REPLACE type of query does not make part of the SQL standards. Since |
| | | * practically only MySQL implements it natively, this type of query is |
| | | * emulated through this method for other DBMS using standard types of |
| | | * queries inside a transaction to assure the atomicity of the operation. |
| | | * |
| | | * @access public |
| | | * |
| | | * @param string $table name of the table on which the REPLACE query will |
| | | * be executed. |
| | | * @param array $fields associative array that describes the fields and the |
| | | * values that will be inserted or updated in the specified table. The |
| | | * indexes of the array are the names of all the fields of the table. The |
| | | * values of the array are also associative arrays that describe the |
| | | * values and other properties of the table fields. |
| | | * |
| | | * Here follows a list of field properties that need to be specified: |
| | | * |
| | | * value: |
| | | * Value to be assigned to the specified field. This value may be |
| | | * of specified in database independent type format as this |
| | | * function can perform the necessary datatype conversions. |
| | | * |
| | | * Default: |
| | | * this property is required unless the Null property |
| | | * is set to 1. |
| | | * |
| | | * type |
| | | * Name of the type of the field. Currently, all types Metabase |
| | | * are supported except for clob and blob. |
| | | * |
| | | * Default: no type conversion |
| | | * |
| | | * null |
| | | * Boolean property that indicates that the value for this field |
| | | * should be set to null. |
| | | * |
| | | * The default value for fields missing in INSERT queries may be |
| | | * specified the definition of a table. Often, the default value |
| | | * is already null, but since the REPLACE may be emulated using |
| | | * an UPDATE query, make sure that all fields of the table are |
| | | * listed in this function argument array. |
| | | * |
| | | * Default: 0 |
| | | * |
| | | * key |
| | | * Boolean property that indicates that this field should be |
| | | * handled as a primary key or at least as part of the compound |
| | | * unique index of the table that will determine the row that will |
| | | * updated if it exists or inserted a new row otherwise. |
| | | * |
| | | * This function will fail if no key field is specified or if the |
| | | * value of a key field is set to null because fields that are |
| | | * part of unique index they may not be null. |
| | | * |
| | | * Default: 0 |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | */ |
| | | function replace($table, $fields) |
| | | { |
| | | $count = count($fields); |
| | | $query = $values = ''; |
| | | $keys = $colnum = 0; |
| | | for (reset($fields); $colnum < $count; next($fields), $colnum++) { |
| | | $name = key($fields); |
| | | if ($colnum > 0) { |
| | | $query .= ','; |
| | | $values.= ','; |
| | | } |
| | | $query.= $name; |
| | | if (isset($fields[$name]['null']) && $fields[$name]['null']) { |
| | | $value = 'NULL'; |
| | | } else { |
| | | $value = $this->quote($fields[$name]['value'], $fields[$name]['type']); |
| | | } |
| | | $values.= $value; |
| | | if (isset($fields[$name]['key']) && $fields[$name]['key']) { |
| | | if ($value === 'NULL') { |
| | | return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, |
| | | 'replace: key value '.$name.' may not be NULL'); |
| | | } |
| | | $keys++; |
| | | } |
| | | } |
| | | if ($keys == 0) { |
| | | return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, |
| | | 'replace: not specified which fields are keys'); |
| | | } |
| | | $query = "REPLACE INTO $table ($query) VALUES ($values)"; |
| | | $this->last_query = $query; |
| | | $this->debug($query, 'query'); |
| | | return $this->_doQuery($query, true); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ nextID() |
| | | |
| | | /** |
| | | * returns the next free id of a sequence |
| | | * |
| | | * @param string $seq_name name of the sequence |
| | | * @param boolean $ondemand when true the seqence is |
| | | * automatic created, if it |
| | | * not exists |
| | | * |
| | | * @return mixed MDB2 Error Object or id |
| | | * @access public |
| | | */ |
| | | function nextID($seq_name, $ondemand = true) |
| | | { |
| | | $sequence_name = $this->getSequenceName($seq_name); |
| | | $query = "INSERT INTO $sequence_name (".$this->options['seqcol_name'].") VALUES (NULL)"; |
| | | $this->expectError(MDB2_ERROR_NOSUCHTABLE); |
| | | $result = $this->_doQuery($query, true); |
| | | $this->popExpect(); |
| | | if (PEAR::isError($result)) { |
| | | if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) { |
| | | $this->loadModule('Manager'); |
| | | // Since we are creating the sequence on demand |
| | | // we know the first id = 1 so initialize the |
| | | // sequence at 2 |
| | | $result = $this->manager->createSequence($seq_name, 2); |
| | | if (PEAR::isError($result)) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'nextID: on demand sequence '.$seq_name.' could not be created'); |
| | | } else { |
| | | // First ID of a newly created sequence is 1 |
| | | return 1; |
| | | } |
| | | } |
| | | return $result; |
| | | } |
| | | $value = $this->queryOne('SELECT LAST_INSERT_ID()', 'integer'); |
| | | if (is_numeric($value)) { |
| | | $query = "DELETE FROM $sequence_name WHERE ".$this->options['seqcol_name']." < $value"; |
| | | $result = $this->_doQuery($query, true); |
| | | if (PEAR::isError($result)) { |
| | | $this->warnings[] = 'nextID: could not delete previous sequence table values from '.$seq_name; |
| | | } |
| | | } |
| | | return $value; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ lastInsertID() |
| | | |
| | | /** |
| | | * returns the autoincrement ID if supported or $id |
| | | * |
| | | * @param mixed $id value as returned by getBeforeId() |
| | | * @param string $table name of the table into which a new row was inserted |
| | | * @return mixed MDB2 Error Object or id |
| | | * @access public |
| | | */ |
| | | function lastInsertID($table = null, $field = null) |
| | | { |
| | | return $this->queryOne('SELECT LAST_INSERT_ID()', 'integer'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ currID() |
| | | |
| | | /** |
| | | * returns the current id of a sequence |
| | | * |
| | | * @param string $seq_name name of the sequence |
| | | * @return mixed MDB2 Error Object or id |
| | | * @access public |
| | | */ |
| | | function currID($seq_name) |
| | | { |
| | | $sequence_name = $this->getSequenceName($seq_name); |
| | | $query = "SELECT MAX(".$this->options['seqcol_name'].") FROM $sequence_name"; |
| | | return $this->queryOne($query, 'integer'); |
| | | } |
| | | } |
| | | |
| | | class MDB2_Result_mysql extends MDB2_Result_Common |
| | | { |
| | | // }}} |
| | | // {{{ fetchRow() |
| | | |
| | | /** |
| | | * Fetch a row and insert the data into an existing array. |
| | | * |
| | | * @param int $fetchmode how the array data should be indexed |
| | | * @param int $rownum number of the row where the data can be found |
| | | * @return int data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null) |
| | | { |
| | | if (!is_null($rownum)) { |
| | | $seek = $this->seek($rownum); |
| | | if (PEAR::isError($seek)) { |
| | | return $seek; |
| | | } |
| | | } |
| | | if ($fetchmode == MDB2_FETCHMODE_DEFAULT) { |
| | | $fetchmode = $this->db->fetchmode; |
| | | } |
| | | if ($fetchmode & MDB2_FETCHMODE_ASSOC) { |
| | | $row = @mysql_fetch_assoc($this->result); |
| | | if (is_array($row) |
| | | && $this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE |
| | | ) { |
| | | $row = array_change_key_case($row, $this->db->options['field_case']); |
| | | } |
| | | } else { |
| | | $row = @mysql_fetch_row($this->result); |
| | | } |
| | | |
| | | if (!$row) { |
| | | if (is_null($this->result)) { |
| | | $err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'fetchRow: resultset has already been freed'); |
| | | return $err; |
| | | } |
| | | $null = null; |
| | | return $null; |
| | | } |
| | | if ($this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL) { |
| | | $this->db->_fixResultArrayValues($row, MDB2_PORTABILITY_EMPTY_TO_NULL); |
| | | } |
| | | if (!empty($this->values)) { |
| | | $this->_assignBindColumns($row); |
| | | } |
| | | if (!empty($this->types)) { |
| | | $row = $this->db->datatype->convertResultRow($this->types, $row); |
| | | } |
| | | if ($fetchmode === MDB2_FETCHMODE_OBJECT) { |
| | | $object_class = $this->db->options['fetch_class']; |
| | | if ($object_class == 'stdClass') { |
| | | $row = (object) $row; |
| | | } else { |
| | | $row = &new $object_class($row); |
| | | } |
| | | } |
| | | ++$this->rownum; |
| | | return $row; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getColumnNames() |
| | | |
| | | /** |
| | | * Retrieve the names of columns returned by the DBMS in a query result. |
| | | * |
| | | * @return mixed an associative array variable |
| | | * that will hold the names of columns. The |
| | | * indexes of the array are the column names |
| | | * mapped to lower case and the values are the |
| | | * respective numbers of the columns starting |
| | | * from 0. Some DBMS may not return any |
| | | * columns when the result set does not |
| | | * contain any rows. |
| | | * |
| | | * a MDB2 error on failure |
| | | * @access private |
| | | */ |
| | | function _getColumnNames() |
| | | { |
| | | $columns = array(); |
| | | $numcols = $this->numCols(); |
| | | if (PEAR::isError($numcols)) { |
| | | return $numcols; |
| | | } |
| | | for ($column = 0; $column < $numcols; $column++) { |
| | | $column_name = @mysql_field_name($this->result, $column); |
| | | $columns[$column_name] = $column; |
| | | } |
| | | if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | $columns = array_change_key_case($columns, $this->db->options['field_case']); |
| | | } |
| | | return $columns; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ numCols() |
| | | |
| | | /** |
| | | * Count the number of columns returned by the DBMS in a query result. |
| | | * |
| | | * @return mixed integer value with the number of columns, a MDB2 error |
| | | * on failure |
| | | * @access public |
| | | */ |
| | | function numCols() |
| | | { |
| | | $cols = @mysql_num_fields($this->result); |
| | | if (is_null($cols)) { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numCols: resultset has already been freed'); |
| | | } |
| | | return $this->db->raiseError(); |
| | | } |
| | | return $cols; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ free() |
| | | |
| | | /** |
| | | * Free the internal resources associated with result. |
| | | * |
| | | * @return boolean true on success, false if result is invalid |
| | | * @access public |
| | | */ |
| | | function free() |
| | | { |
| | | $free = @mysql_free_result($this->result); |
| | | if (!$free) { |
| | | if (is_null($this->result)) { |
| | | return MDB2_OK; |
| | | } |
| | | return $this->db->raiseError(); |
| | | } |
| | | $this->result = null; |
| | | return MDB2_OK; |
| | | } |
| | | } |
| | | |
| | | class MDB2_BufferedResult_mysql extends MDB2_Result_mysql |
| | | { |
| | | // }}} |
| | | // {{{ seek() |
| | | |
| | | /** |
| | | * seek to a specific row in a result set |
| | | * |
| | | * @param int $rownum number of the row where the data can be found |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function seek($rownum = 0) |
| | | { |
| | | if ($this->rownum != ($rownum - 1) && !@mysql_data_seek($this->result, $rownum)) { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'seek: resultset has already been freed'); |
| | | } |
| | | return $this->db->raiseError(MDB2_ERROR_INVALID, null, null, |
| | | 'seek: tried to seek to an invalid row number ('.$rownum.')'); |
| | | } |
| | | $this->rownum = $rownum - 1; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ valid() |
| | | |
| | | /** |
| | | * check if the end of the result set has been reached |
| | | * |
| | | * @return mixed true or false on sucess, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function valid() |
| | | { |
| | | $numrows = $this->numRows(); |
| | | if (PEAR::isError($numrows)) { |
| | | return $numrows; |
| | | } |
| | | return $this->rownum < ($numrows - 1); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ numRows() |
| | | |
| | | /** |
| | | * returns the number of rows in a result object |
| | | * |
| | | * @return mixed MDB2 Error Object or the number of rows |
| | | * @access public |
| | | */ |
| | | function numRows() |
| | | { |
| | | $rows = @mysql_num_rows($this->result); |
| | | if (is_null($rows)) { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numRows: resultset has already been freed'); |
| | | } |
| | | return $this->raiseError(); |
| | | } |
| | | return $rows; |
| | | } |
| | | } |
| | | |
| | | class MDB2_Statement_mysql extends MDB2_Statement_Common |
| | | { |
| | | |
| | | } |
| | | ?> |
| | |
| | | $i++; |
| | | $lines[$i] = trim(chop($line)); |
| | | } |
| | | }while($line[0]!=")"); |
| | | }while($line[0]!=")" && strncmp($line, $key, strlen($key))); // patch from "Maksim Rubis" <siburny@hotmail.com> |
| | | |
| | | if(strncmp($line, $key, strlen($key))) |
| | | { |
| | | //process header, fill iilBasicHeader obj. |
| | | // initialize |
| | | if (is_array($headers)){ |
| | |
| | | if ($messageID) $messageID = substr(substr($messageID, 1), 0, strlen($messageID)-2); |
| | | else $messageID = "mid:".$id; |
| | | $result[$id]->messageID = $messageID; |
| | | } |
| | | else { |
| | | $a=explode(" ", $line); |
| | | } |
| | | |
| | | } |
| | | }while(strcmp($a[0], $key)!=0); |
| | |
| | | if ($field=="date"||$field=='internaldate') $field="timestamp"; |
| | | if (empty($flag)) $flag="ASC"; |
| | | $flag=strtoupper($flag); |
| | | $stripArr = ($field=='subject') ? array('Re: ','Fwd: ','Fw: ',"\"") : array("\""); |
| | | |
| | | $c=count($a); |
| | | if ($c>0){ |
| | |
| | | reset($a); |
| | | while (list($key, $val)=each($a)){ |
| | | $data=$a[$key]->$field; |
| | | if (is_string($data)) $data=strtoupper(str_replace("\"", "", $data)); |
| | | if (is_string($data)) $data=strtoupper(str_replace($stripArr, "", $data)); |
| | | $index[$key]=$data; |
| | | } |
| | | |
| | |
| | | $labels['deletefolder'] = 'Ordner löschen'; |
| | | $labels['managefolders'] = 'Ordner verwalten'; |
| | | |
| | | $labels['sortby'] = 'Sortieren nach'; |
| | | $labels['sortasc'] = 'aufsteigend sortieren'; |
| | | $labels['sortdesc'] = 'absteigend sortieren'; |
| | | |
| | | ?> |
| | |
| | | $labels['deletefolder'] = 'Delete folder'; |
| | | $labels['managefolders'] = 'Manage folders'; |
| | | |
| | | $labels['sortby'] = 'Sort by'; |
| | | $labels['sortasc'] = 'Sort ascending'; |
| | | $labels['sortdesc'] = 'Sort descending'; |
| | | |
| | | ?> |
| | |
| | | // toolbar buttons |
| | | $labels['writenewmessage'] = 'Schrijf een nieuw bericht'; |
| | | $labels['replytomessage'] = 'Beantwoord het bericht'; |
| | | $labels['forwardmessage'] = 'Doorsturen van bericht'; |
| | | $labels['forwardmessage'] = 'Stuur bericht door'; |
| | | $labels['deletemessage'] = 'Verplaats bericht naar prullenbak'; |
| | | $labels['printmessage'] = 'Print dit bericht'; |
| | | $labels['previousmessages'] = 'Toon vorige lijst met berichten'; |
| | | $labels['nextmessages'] = 'Toon volgende lijst met berichten'; |
| | | $labels['backtolist'] = 'Terug naar berichtoverzicht'; |
| | | $labels['viewsource'] = 'Bron bekijken'; |
| | | |
| | | $labels['select'] = 'Selecteer'; |
| | | $labels['all'] = 'Alle'; |
| | |
| | | $labels['sendmessage'] = 'Verstuur het bericht nu'; |
| | | $labels['addattachment'] = 'Voeg een bijlage toe'; |
| | | |
| | | $labels['attachments'] = 'Bijlage'; |
| | | $labels['attachments'] = 'Bijlages'; |
| | | $labels['upload'] = 'Toevoegen'; |
| | | $labels['close'] = 'Sluit'; |
| | | |
| | |
| | | $labels['composeto'] = 'Verstuur bericht aan'; |
| | | $labels['contactsfromto'] = 'Contactpersonen $from tot $to van $count'; |
| | | |
| | | $labels['print'] = 'Print'; |
| | | $labels['export'] = 'Exporteer'; |
| | | |
| | | |
| | | // settings |
| | | $labels['settingsfor'] = 'Instellingen voor'; |
| | |
| | | $labels['deletefolder'] = 'Verwijder map'; |
| | | $labels['managefolders'] = 'Beheer mappen'; |
| | | |
| | | $labels['sortby'] = 'Sorteer op'; |
| | | $labels['sortdesc'] = 'Sorteer (z-a)'; |
| | | $labels['sortasc'] = 'Sorteer (a-z)'; |
| | | |
| | | ?> |
| | |
| | | <?php |
| | | <?php |
| | | |
| | | /* |
| | | +-----------------------------------------------------------------------+ |
| | |
| | | function rcmail_message_list($attrib) |
| | | { |
| | | global $IMAP, $CONFIG, $COMM_PATH, $OUTPUT, $JS_OBJECT_NAME; |
| | | |
| | | |
| | | $skin_path = $CONFIG['skin_path']; |
| | | $image_tag = '<img src="%s%s" alt="%s" border="0" />'; |
| | | |
| | | |
| | | // check to see if we have some settings for sorting |
| | | $sort_col = isset($_SESSION['sort_col']) ? $_SESSION['sort_col'] : 'date'; |
| | | $sort_order = isset($_SESSION['sort_order']) ? $_SESSION['sort_order'] : 'DESC'; |
| | | $sort_col = isset($_SESSION['sort_col']) ? $_SESSION['sort_col'] : $CONFIG['message_sort_col']; |
| | | $sort_order = isset($_SESSION['sort_order']) ? $_SESSION['sort_order'] : $CONFIG['message_sort_order']; |
| | | |
| | | // get message headers |
| | | $a_headers = $IMAP->list_headers('', '', $sort_col, $sort_order); |
| | |
| | | |
| | | // define list of cols to be displayed |
| | | $a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject'); |
| | | $a_sort_cols = array('subject', 'date', 'from', 'to'); |
| | | |
| | | // show 'to' instead of from in sent messages |
| | | if (strtolower($IMAP->get_mailbox_name())=='sent' && ($f = array_search('from', $a_show_cols))) |
| | |
| | | |
| | | // add table title |
| | | $out .= "<thead><tr>\n<td class=\"icon\"> </td>\n"; |
| | | |
| | | |
| | | $javascript = ''; |
| | | foreach ($a_show_cols as $col) |
| | | { |
| | |
| | | |
| | | // make sort links |
| | | $sort = ''; |
| | | if ($col != 'size') |
| | | if (in_array($col, $a_sort_cols) && (!empty($attrib['sortdescbutton']) || !empty($attrib['sortascbutton']))) |
| | | { |
| | | $sort = ' '; |
| | | |
| | | // asc link |
| | | $asc = '_ASC'; |
| | | $sort .= '<a href="#" id="sort_' . $col_name . $asc . '" onclick="return rcmail.command(\'sort\',\'' |
| | | . $col_name . $asc . '\',this)" title="Sort by ' . $col_name . ' ascending">' |
| | | . '<img src="skins/default/images/buttons/up_arrow.png" width="11" height="11" border="0" alt="" /></a>'; |
| | | if (!empty($attrib['sortascbutton'])) |
| | | { |
| | | $sort .= rcube_button(array('command' => 'sort', |
| | | 'prop' => $col.'_ASC', |
| | | 'image' => $attrib['sortascbutton'], |
| | | 'title' => 'sortasc')); |
| | | } |
| | | |
| | | // desc link |
| | | $desc = '_DESC'; |
| | | $sort .= ' <a href="#" id="sort_' . $col_name . $desc . '" onclick="return rcmail.command(\'sort\',\'' |
| | | . $col_name . $desc . '\',this)" title="Sort by ' . $col_name . ' descending">' |
| | | . '<img src="skins/default/images/buttons/down_arrow.png" width="11" height="11" border="0" alt="" /></a>'; |
| | | if (!empty($attrib['sortdescbutton'])) |
| | | { |
| | | $sort .= rcube_button(array('command' => 'sort', |
| | | 'prop' => $col.'_DESC', |
| | | 'image' => $attrib['sortdescbutton'], |
| | | 'title' => 'sortdesc')); |
| | | } |
| | | } |
| | | |
| | | $sort_class = $col==$sort_col ? " sorted$sort_order" : ''; |
| | | |
| | | // put it all together |
| | | $out .= '<td class="'.$col.'">' . "$col_name $sort</td>\n"; |
| | | |
| | | // register sort buttons |
| | | $javascript .= "rcmail.register_button('sort', 'sort_{$col_name}_desc', 'link', 'active', '', '');\n"; |
| | | $javascript .= "rcmail.register_button('sort', 'sort_{$col_name}_asc', 'link', 'active', '', '');\n"; |
| | | $out .= '<td class="'.$col.$sort_class.'" id="rcmHead'.$col.'">' . "$col_name$sort</td>\n"; |
| | | } |
| | | |
| | | $out .= '<td class="icon">'.($attrib['attachmenticon'] ? sprintf($image_tag, $skin_path, $attrib['attachmenticon'], '') : '')."</td>\n"; |
| | |
| | | $javascript .= sprintf("%s.set_env('messagecount', %d);\n", $JS_OBJECT_NAME, $message_count); |
| | | $javascript .= sprintf("%s.set_env('current_page', %d);\n", $JS_OBJECT_NAME, $IMAP->list_page); |
| | | $javascript .= sprintf("%s.set_env('pagecount', %d);\n", $JS_OBJECT_NAME, ceil($message_count/$IMAP->page_size)); |
| | | $javascript .= sprintf("%s.set_env('sort_col', '%s');\n", $JS_OBJECT_NAME, $sort_col); |
| | | $javascript .= sprintf("%s.set_env('sort_order', '%s');\n", $JS_OBJECT_NAME, $sort_order); |
| | | |
| | | if ($attrib['messageicon']) |
| | | $javascript .= sprintf("%s.set_env('messageicon', '%s%s');\n", $JS_OBJECT_NAME, $skin_path, $attrib['messageicon']); |
| | |
| | | if (!$headers[$hkey]) |
| | | continue; |
| | | |
| | | if ($hkey=='date') |
| | | if ($hkey=='date' && !empty($headers[$hkey])) |
| | | $header_value = format_date(strtotime($headers[$hkey])); |
| | | else if (in_array($hkey, array('from', 'to', 'cc', 'reply-to'))) |
| | | $header_value = rep_specialchars_output(rcmail_address_string($IMAP->decode_header($headers[$hkey]), NULL, $attrib['addicon'])); |
| | |
| | | // yes, so set the sort vars |
| | | list($sort_col, $sort_order) = explode('_', $sort); |
| | | |
| | | // iloha mail sort func doesn't know about a 'Sender' col |
| | | $sort_col = $sort_col == 'Sender' ? 'From' : $sort_col; |
| | | |
| | | // set session vars for sort (so next page and task switch know how to sort) |
| | | $_SESSION['sort_col'] = $sort_col; |
| | | $_SESSION['sort_order'] = $sort_order; |
| | | } |
| | | else |
| | | { |
| | | // if switching folder, use default sorting |
| | | if ($_GET['_refresh'] == '1') |
| | | { |
| | | $sort_col = 'date'; |
| | | $sort_order = 'desc'; |
| | | unset($_SESSION['sort_col'], $_SESSION['sort_order']); |
| | | } |
| | | else |
| | | { |
| | | // use session settings if set, defaults if not |
| | | $sort_col = isset($_SESSION['sort_col']) ? $_SESSION['sort_col'] : 'date'; |
| | | $sort_order = isset($_SESSION['sort_order']) ? $_SESSION['sort_order'] : 'desc'; |
| | | } |
| | | { |
| | | // use session settings if set, defaults if not |
| | | $sort_col = isset($_SESSION['sort_col']) ? $_SESSION['sort_col'] : $CONFIG['message_sort_col']; |
| | | $sort_order = isset($_SESSION['sort_order']) ? $_SESSION['sort_order'] : $CONFIG['message_sort_order']; |
| | | } |
| | | |
| | | |
| | |
| | | $javascript .= sprintf("%s.set_env('safemode', '%b');", $JS_OBJECT_NAME, $_GET['_safe']); |
| | | |
| | | // get previous and next message UID |
| | | $a_msg_index = $IMAP->message_index(); |
| | | $a_msg_index = $IMAP->message_index(NULL, $_SESSION['sort_col'], $_SESSION['sort_order']); |
| | | $MESSAGE['index'] = array_search((string)$_GET['_uid'], $a_msg_index, TRUE); |
| | | |
| | | if (isset($a_msg_index[$MESSAGE['index']-1])) |
| | |
| | | <div id="taskbar"> |
| | | <roundcube:button command="mail" label="mail" class="button-mail" /> |
| | | <roundcube:button command="addressbook" label="addressbook" class="button-addressbook" /> |
| | | <roundcube:button command="settings" label="settings" class="button-settings" /> |
| | | <roundcube:button command="logout" label="logout" class="button-logout" /> |
| | | </div> |
| | | |
| | | <div id="header"><roundcube:button command="mail" image="/images/roundcube_logo.png" alt="RoundCube Webmail" width="165" height="55" /></div> |
| | | |
| | | <roundcube:object name="message" id="message" /> |
New file |
| | |
| | | <div id="taskbar"> |
| | | <roundcube:button command="mail" label="mail" class="button-mail" /> |
| | | <roundcube:button command="addressbook" label="addressbook" class="button-addressbook" /> |
| | | <roundcube:button command="settings" label="settings" class="button-settings" /> |
| | | <roundcube:button command="logout" label="logout" class="button-logout" /> |
| | | </div> |
| | |
| | | font-weight: bold; |
| | | } |
| | | |
| | | #messagelist thead tr td.sortedASC, |
| | | #messagelist thead tr td.sortedDESC |
| | | { |
| | | background-image: url(images/listheader_dark.gif); |
| | | } |
| | | |
| | | #messagelist tbody tr td |
| | | { |
| | | height: 16px !important; |
| | |
| | | </head> |
| | | <body> |
| | | |
| | | <roundcube:include file="/includes/taskbar.html" /> |
| | | <roundcube:include file="/includes/header.html" /> |
| | | <roundcube:include file="/includes/settingstabs.html" /> |
| | | |
| | |
| | | </div> |
| | | </div> |
| | | |
| | | <roundcube:include file="/includes/taskbar.html" /> |
| | | <roundcube:include file="/includes/settingscripts.html" /> |
| | | |
| | | </body> |
| | |
| | | </head> |
| | | <body> |
| | | |
| | | <roundcube:include file="/includes/taskbar.html" /> |
| | | <roundcube:include file="/includes/header.html" /> |
| | | |
| | | <div id="abooktoolbar"> |
| | |
| | | </head> |
| | | <body> |
| | | |
| | | <roundcube:include file="/includes/taskbar.html" /> |
| | | <roundcube:include file="/includes/header.html" /> |
| | | |
| | | <form name="form" method="post"> |
| | |
| | | </head> |
| | | <body> |
| | | |
| | | <roundcube:include file="/includes/taskbar.html" /> |
| | | <roundcube:include file="/includes/header.html" /> |
| | | <roundcube:include file="/includes/settingstabs.html" /> |
| | | |
| | |
| | | </div> |
| | | </div> |
| | | |
| | | <roundcube:include file="/includes/taskbar.html" /> |
| | | <roundcube:include file="/includes/settingscripts.html" /> |
| | | |
| | | </body> |
| | |
| | | </head> |
| | | <body> |
| | | |
| | | <roundcube:include file="/includes/taskbar.html" /> |
| | | <roundcube:include file="/includes/header.html" /> |
| | | <roundcube:include file="/includes/settingstabs.html" /> |
| | | |
| | |
| | | <p><roundcube:button command="add" type="input" label="newidentity" class="button" /></p> |
| | | </div> |
| | | |
| | | <roundcube:include file="/includes/taskbar.html" /> |
| | | <roundcube:include file="/includes/settingscripts.html" /> |
| | | |
| | | </body> |
| | |
| | | </head> |
| | | <body> |
| | | |
| | | <roundcube:include file="/includes/taskbar.html" /> |
| | | <roundcube:include file="/includes/header.html" /> |
| | | |
| | | <div id="messagetoolbar"> |
| | |
| | | messageIcon="/images/icons/dot.png" |
| | | unreadIcon="/images/icons/unread.png" |
| | | repliedIcon="/images/icons/replied.png" |
| | | attachmentIcon="/images/icons/attachment.png" /> |
| | | attachmentIcon="/images/icons/attachment.png" |
| | | sortDescButton="/images/buttons/up_arrow.png" |
| | | sortAscButton="/images/buttons/down_arrow.png" /> |
| | | </div> |
| | | |
| | | <div id="listcontrols"> |
| | |
| | | </head> |
| | | <body> |
| | | |
| | | <roundcube:include file="/includes/taskbar.html" /> |
| | | <roundcube:include file="/includes/header.html" /> |
| | | <roundcube:include file="/includes/settingstabs.html" /> |
| | | |
| | |
| | | |
| | | </form> |
| | | |
| | | <roundcube:include file="/includes/taskbar.html" /> |
| | | <roundcube:include file="/includes/settingscripts.html" /> |
| | | |
| | | </body> |
| | |
| | | </head> |
| | | <body> |
| | | |
| | | <roundcube:include file="/includes/taskbar.html" /> |
| | | <roundcube:include file="/includes/header.html" /> |
| | | |
| | | <div id="messagetoolbar"> |
| | |
| | | </head> |
| | | <body> |
| | | |
| | | <roundcube:include file="/includes/taskbar.html" /> |
| | | <roundcube:include file="/includes/header.html" /> |
| | | <roundcube:include file="/includes/settingstabs.html" /> |
| | | |
| | |
| | | </div> |
| | | </div> |
| | | |
| | | |
| | | <roundcube:include file="/includes/taskbar.html" /> |
| | | <roundcube:include file="/includes/settingscripts.html" /> |
| | | |
| | | </body> |