From ce8e5b220a4eb8db5540b38895be5d887310f137 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Wed, 20 Sep 2006 12:14:43 +0000 Subject: [PATCH] new PMA_List_Database class (i knew there was something missing ...) --- libraries/PMA_List_Database.class.php | 467 ++++++++++++++++++++++++++ 1 file changed, 467 insertions(+) create mode 100644 libraries/PMA_List_Database.class.php diff --git a/libraries/PMA_List_Database.class.php b/libraries/PMA_List_Database.class.php new file mode 100644 index 000000000..e244f68ee --- /dev/null +++ b/libraries/PMA_List_Database.class.php @@ -0,0 +1,467 @@ + PMA_Config + * -> PMA_Theme + * -> ... + * -> PMA_List + * -> PMA_List_Table + * -> PMA_List_Server + * -> PMA_List_Database + * -> PMA_List_Database_Mysql + * -> PMA_List_Database_Mysql_3 + * -> PMA_List_Database_Mysql_4 + * -> PMA_List_Database_Mysql_5 + * -> PMA_List_Database_OtherDbms + * -> ... + * + */ +//require_once 'PMA_List.class.php'; + +/** + * handles database lists + * + * @todo this object should be attached to the server object + * @todo make use of INFORMATION_SCHEMA !? + * @todo support --skip-showdatabases and user has only global rights? + * @todo add caching + * @access public + */ +/*public*/ class PMA_List_Database /* extends PMA_List */ { + + /** + * @var array the list items + * @access public + * @todo move into PMA_List + */ + var $items = array(); + + /** + * @var mixed database link resource|object to be used + * @access protected + */ + var $_db_link = null; + + /** + * @var mixed user database link resource|object + * @access protected + */ + var $_db_link_user = null; + + /** + * @var mixed controluser database link resource|object + * @access protected + */ + var $_db_link_control = null; + + /** + * @var bool whether we need to re-index the database list for consistency keys + * @access protected + */ + var $_need_to_reindex = false; + + /** + * @var boolean whether SHOW DATABASES is disabled or not + * @access protected + */ + var $_show_databases_disabled = false; + + /** + * Constructor + * + * @uses PMA_List_Database::$_db_link + * @uses PMA_List_Database::$_db_link_user + * @uses PMA_List_Database::$_db_link_control + * @uses PMA_List_Database::build() + * @param mixed $db_link_user user database link resource|object + * @param mixed $db_link_control control database link resource|object + */ + function __construct($db_link_user = null, $db_link_control = null) { + $this->_db_link = $db_link_user; + $this->_db_link_user = $db_link_user; + $this->_db_link_control = $db_link_control; + + $this->build(); + } + + /** + * old PHP 4 style constructor + * + * @see PMA_List_Database::__construct() + */ + function PMA_List_Database($db_link_user = null, $db_link_control = null) { + $this->__construct($db_link_user, $db_link_control); + } + + /** + * removes all databases not accessible by current user from list + * + * @access protected + * @uses PMA_List_Database::$items + * @uses PMA_List_Database::$_db_link_user + * @uses PMA_List_Database::$_need_to_reindex to set it if reuqired + * @uses PMA_DBI_select_db() + */ + function _checkAccess() + { + foreach ($this->items as $key => $db) { + if (! @PMA_DBI_select_db($db, $this->_db_link_user)) { + unset($this->items[$key]); + } + } + + // re-index values + $this->_need_to_reindex = true; + } + + /** + * checks if the configuration wants to hide some databases + * + * @access protected + * @uses PMA_List_Database::$items + * @uses PMA_List_Database::$_need_to_reindex to set it if reuqired + * @uses preg_match() + * @global $cfg + */ + function _checkHideDatabase() + { + if (empty($GLOBALS['cfg']['Server']['hide_db'])) { + return; + } + + foreach ($this->items as $key => $db) { + if (preg_match('/' . $GLOBALS['cfg']['Server']['hide_db'] . '/', $db)) { + unset($this->items[$key]); + } + } + // re-index values + $this->_need_to_reindex = true; + } + + /** + * retrieves database list from server + * + * @todo we could also search mysql tables if all fail? + * @access protected + * @uses PMA_List_Database::$_show_databases_disabled for not retrying if SHOW DATABASES is disabled + * @uses PMA_List_Database::$_db_link + * @uses PMA_List_Database::$_db_link_control in case of SHOW DATABASES is disabled for userlink + * @uses PMA_DBI_fetch_result() + * @uses PMA_DBI_getError() + * @global $error_showdatabases to alert not allowed SHOW DATABASE + * @global $errno from PMA_DBI_getError() + * @param string $like_db_name usally a db_name containing wildcards + */ + function _retrieve($like_db_name = '') + { + if ($this->_show_databases_disabled) { + return array(); + } + + if (! empty($like_db_name)) { + $like = " LIKE '" . $like_db_name . "';"; + } else { + $like = ";"; + } + + $database_list = PMA_DBI_fetch_result('SHOW DATABASES' . $like, null, null, $this->_db_link); + PMA_DBI_getError(); + + if ($GLOBALS['errno'] !== 0) { + // failed to get database list, try the control user + // (hopefully there is one and he has SHOW DATABASES right) + $this->_db_link = $this->_db_link_control; + $database_list = PMA_DBI_fetch_result('SHOW DATABASES' . $like, null, null, $this->_db_link); + + PMA_DBI_getError(); + + if ($GLOBALS['errno'] !== 0) { + // failed! we will display a warning that phpMyAdmin could not safely + // retrieve database list, the admin has to setup a control user or + // allow SHOW DATABASES + $GLOBALS['error_showdatabases'] = true; + $this->_show_databases_disabled = true; + } + } + + return $database_list; + } + + /** + * builds up the list + * + * @uses PMA_List_Database::$items to initialize it + * @uses PMA_List_Database::$_need_to_reindex + * @uses PMA_List_Database::_checkOnlyDatabase() + * @uses PMA_List_Database::_retrieve() + * @uses PMA_List_Database::_checkHideDatabase() + * @uses PMA_List_Database::_checkAccess() + * @uses PMA_MYSQL_INT_VERSION + * @uses array_values() + * @uses natsort() + * @global $cfg + */ + function build() + { + $this->items = array(); + + if (! $this->_checkOnlyDatabase()) { + $this->items = $this->_retrieve(); + + if ($GLOBALS['cfg']['NaturalOrder']) { + natsort($this->items); + $this->_need_to_reindex = true; + } + } + + $this->_checkHideDatabase(); + + // Before MySQL 4.0.2, SHOW DATABASES could send the + // whole list, so check if we really have access: + if (PMA_MYSQL_INT_VERSION < 40002) { + $this->_checkAccess(); + } + + if ($this->_need_to_reindex) { + $this->items = array_values($this->items); + } + } + + /** + * checks the only_db configuration + * + * @uses PMA_List_Database::$_show_databases_disabled + * @uses PMA_List_Database::$items + * @uses PMA_List_Database::_retrieve() + * @uses PMA_unescape_mysql_wildcards() + * @uses preg_match() + * @uses array_diff() + * @uses array_merge() + * @uses is_array() + * @uses strlen() + * @uses is_string() + * @global $cfg + * @return boolean false if there is no only_db, otherwise true + */ + function _checkOnlyDatabase() + { + if (is_string($GLOBALS['cfg']['Server']['only_db']) + && strlen($GLOBALS['cfg']['Server']['only_db'])) { + $GLOBALS['cfg']['Server']['only_db'] = array( + $GLOBALS['cfg']['Server']['only_db'] + ); + } + + if (! is_array($GLOBALS['cfg']['Server']['only_db'])) { + return false; + } + + foreach ($GLOBALS['cfg']['Server']['only_db'] as $each_only_db) { + if ($each_only_db === '*' && ! $this->_show_databases_disabled) { + // append all not already listed dbs to the list + $this->items = array_merge($this->items, + array_diff($this->_retrieve(), $this->items)); + // there can only be one '*', and this can only be last + break; + } + + // check if the db name contains wildcard, + // thus containing not escaped _ or % + if (! preg_match('/(^|[^\\\\])(_|%)/', $each_only_db)) { + // ... not contains wildcard + $this->items[] = PMA_unescape_mysql_wildcards($each_only_db); + continue; + } + + if (! $this->_show_databases_disabled) { + $this->items = array_merge($this->items, $this->_retrieve($each_only_db)); + continue; + } + + // @todo induce error, about not using wildcards with SHOW DATABASE disabled? + } + + return true; + } + + /** + * returns first item from list + * + * @todo move into PMA_List + * @uses PMA_List_Database::$items + * @uses reset() + * @return string value of first item + */ + function getFirst() + { + return reset($this->items); + } + + /** + * returns item only if there is only one in the list + * + * @todo move into PMA_List + * @uses PMA_List_Database::count() + * @uses PMA_List_Database::getFirst() + * @uses PMA_List_Database::emptyItem() + * @return single item + */ + function getSingleItem() + { + if ($this->count() === 1) { + return $this->getFirst(); + } + + return $this->emptyItem(); + } + + /** + * returns list item count + * + * @todo move into PMA_List + * @uses PMA_List_Database::$items + * @uses count() + */ + function count() + { + return count($this->items); + } + + /** + * defines what is an empty item (0, '', false or null) + * + * @todo add as abstract into PMA_List + */ + function emptyItem() + { + return ''; + } + + /** + * checks if the given db names exists in the current list, if there is + * missing at least one item it reutrns false other wise true + * + * @uses PMA_List_Database::$items + * @uses func_get_args() + * @uses in_array() + * @param string $db_name,.. one or more mysql result resources + * @return boolean true if all items exists, otheriwse false + */ + function exists() + { + foreach (func_get_args() as $result) { + if (! in_array($result, $this->items)) { + return false; + } + } + + return true; + } + + /** + * returns HTML