Refactored ConfigFile class so that it is no longer a singleton
[phpmyadmin.git] / libraries / List_Database.class.php
blob607441204a420a73b8cac806f344bd19dc1e73d1
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * holds the PMA_List_Database class
6 * @package PhpMyAdmin
7 */
9 if (! defined('PHPMYADMIN')) {
10 exit;
13 /**
14 * the list base class
16 require_once './libraries/List.class.php';
18 /**
19 * handles database lists
21 * <code>
22 * $PMA_List_Database = new PMA_List_Database($userlink, $controllink);
23 * </code>
25 * @todo this object should be attached to the PMA_Server object
26 * @todo ? make use of INFORMATION_SCHEMA
27 * @todo ? support --skip-showdatabases and user has only global rights
29 * @package PhpMyAdmin
30 * @since phpMyAdmin 2.9.10
32 class PMA_List_Database extends PMA_List
34 /**
35 * @var mixed database link resource|object to be used
36 * @access protected
38 protected $db_link = null;
40 /**
41 * @var mixed user database link resource|object
42 * @access protected
44 protected $db_link_user = null;
46 /**
47 * @var mixed controluser database link resource|object
48 * @access protected
50 protected $db_link_control = null;
52 /**
53 * @var boolean whether SHOW DATABASES is disabled or not
54 * @access protected
56 protected $show_databases_disabled = false;
58 /**
59 * @var string command to retrieve databases from server
60 * @access protected
62 protected $command = null;
64 /**
65 * Constructor
67 * @param mixed $db_link_user user database link resource|object
68 * @param mixed $db_link_control control database link resource|object
70 * @return void
72 public function __construct($db_link_user = null, $db_link_control = null)
74 $this->db_link = $db_link_user;
75 $this->db_link_user = $db_link_user;
76 $this->db_link_control = $db_link_control;
78 parent::__construct();
79 $this->build();
82 /**
83 * checks if the configuration wants to hide some databases
85 * @return void
87 protected function checkHideDatabase()
89 if (empty($GLOBALS['cfg']['Server']['hide_db'])) {
90 return;
93 foreach ($this->getArrayCopy() as $key => $db) {
94 if (preg_match('/' . $GLOBALS['cfg']['Server']['hide_db'] . '/', $db)) {
95 $this->offsetUnset($key);
101 * retrieves database list from server
103 * @param string $like_db_name usually a db_name containing wildcards
105 * @return array
106 * @todo we could also search mysql tables if all fail?
108 protected function retrieve($like_db_name = null)
110 if ($this->show_databases_disabled) {
111 return array();
114 if (null !== $like_db_name) {
115 $command = "SHOW DATABASES LIKE '" . $like_db_name . "'";
116 } elseif (null === $this->command) {
117 $command = str_replace(
118 '#user#', $GLOBALS['cfg']['Server']['user'],
119 $GLOBALS['cfg']['Server']['ShowDatabasesCommand']
121 $this->command = $command;
122 } else {
123 $command = $this->command;
126 $database_list = $GLOBALS['dbi']->fetchResult(
127 $command, null, null, $this->db_link
129 $GLOBALS['dbi']->getError();
131 if ($GLOBALS['errno'] !== 0) {
132 // failed to get database list, try the control user
133 // (hopefully there is one and he has SHOW DATABASES right)
134 $this->db_link = $this->db_link_control;
135 $database_list = $GLOBALS['dbi']->fetchResult(
136 $command, null, null, $this->db_link
139 $GLOBALS['dbi']->getError();
141 if ($GLOBALS['errno'] !== 0) {
142 // failed! we will display a warning that phpMyAdmin could not
143 // safely retrieve database list, the admin has to setup a control
144 // user or allow SHOW DATABASES
145 $GLOBALS['error_showdatabases'] = true;
146 $this->show_databases_disabled = true;
150 if ($GLOBALS['cfg']['NaturalOrder']) {
151 natsort($database_list);
152 } else {
153 // need to sort anyway, otherwise information_schema
154 // goes at the top
155 sort($database_list);
158 return $database_list;
162 * builds up the list
164 * @return void
166 public function build()
168 if (! $this->checkOnlyDatabase()) {
169 $items = $this->retrieve();
170 $this->exchangeArray($items);
173 $this->checkHideDatabase();
177 * checks the only_db configuration
179 * @return boolean false if there is no only_db, otherwise true
181 protected function checkOnlyDatabase()
183 if (is_string($GLOBALS['cfg']['Server']['only_db'])
184 && strlen($GLOBALS['cfg']['Server']['only_db'])
186 $GLOBALS['cfg']['Server']['only_db'] = array(
187 $GLOBALS['cfg']['Server']['only_db']
191 if (! is_array($GLOBALS['cfg']['Server']['only_db'])) {
192 return false;
195 $items = array();
197 foreach ($GLOBALS['cfg']['Server']['only_db'] as $each_only_db) {
199 // check if the db name contains wildcard,
200 // thus containing not escaped _ or %
201 if (! preg_match('/(^|[^\\\\])(_|%)/', $each_only_db)) {
202 // ... not contains wildcard
203 $items[] = PMA_Util::unescapeMysqlWildcards($each_only_db);
204 continue;
207 if (! $this->show_databases_disabled) {
208 $items = array_merge($items, $this->retrieve($each_only_db));
209 continue;
212 // @todo induce error, about not using wildcards
213 // with SHOW DATABASE disabled?
216 $this->exchangeArray($items);
218 return true;
222 * returns default item
224 * @return string default item
226 public function getDefault()
228 if (strlen($GLOBALS['db'])) {
229 return $GLOBALS['db'];
232 return $this->getEmpty();
236 * this is just a backup, if all is fine this can be deleted later
238 * @deprecated
239 * @return void
241 protected function checkAgainstPrivTables()
243 // 1. get allowed dbs from the "mysql.db" table
244 // User can be blank (anonymous user)
245 $local_query = "
246 SELECT DISTINCT `Db` FROM `mysql`.`db`
247 WHERE `Select_priv` = 'Y'
248 AND `User`
249 IN ('"
250 . PMA_Util::sqlAddSlashes($GLOBALS['cfg']['Server']['user'])
251 . "', '')";
252 $tmp_mydbs = $GLOBALS['dbi']->fetchResult(
253 $local_query, null, null, $GLOBALS['controllink']
255 $dblist = array();
256 if ($tmp_mydbs) {
257 // Will use as associative array of the following 2 code
258 // lines:
259 // the 1st is the only line intact from before
260 // correction,
261 // the 2nd replaces $dblist[] = $row['Db'];
263 // Code following those 2 lines in correction continues
264 // populating $dblist[], as previous code did. But it is
265 // now populated with actual database names instead of
266 // with regular expressions.
267 $tmp_alldbs = $GLOBALS['dbi']->query(
268 'SHOW DATABASES;', $GLOBALS['controllink']
270 // all databases cases - part 2
271 if (isset($tmp_mydbs['%'])) {
272 while ($tmp_row = $GLOBALS['dbi']->fetchRow($tmp_alldbs)) {
273 $dblist[] = $tmp_row[0];
274 } // end while
275 } else {
276 while ($tmp_row = $GLOBALS['dbi']->fetchRow($tmp_alldbs)) {
277 $tmp_db = $tmp_row[0];
278 if (isset($tmp_mydbs[$tmp_db]) && $tmp_mydbs[$tmp_db] == 1) {
279 $dblist[] = $tmp_db;
280 $tmp_mydbs[$tmp_db] = 0;
281 } elseif (! isset($dblist[$tmp_db])) {
282 foreach ($tmp_mydbs as $tmp_matchpattern => $tmp_value) {
283 // fixed bad regexp
284 // TODO: db names may contain characters
285 // that are regexp instructions
286 $re = '(^|(\\\\\\\\)+|[^\])';
287 $tmp_regex = preg_replace(
288 '/' . addcslashes($re, '/') . '%/',
289 '\\1.*',
290 preg_replace(
291 '/' . addcslashes($re, '/') . '_/',
292 '\\1.{1}',
293 $tmp_matchpattern
296 $tmp_regex = '/^' . addcslashes($tmp_regex, '/') . '$/';
297 if (preg_match($tmp_regex, $tmp_db)) {
298 $dblist[] = $tmp_db;
299 break;
301 } // end while
302 } // end if ... elseif ...
303 } // end while
304 } // end else
305 $GLOBALS['dbi']->freeResult($tmp_alldbs);
306 unset($tmp_mydbs);
307 } // end if
309 // 2. get allowed dbs from the "mysql.tables_priv" table
310 $local_query = 'SELECT DISTINCT `Db` FROM `mysql`.`tables_priv`';
311 $local_query .= ' WHERE `Table_priv` LIKE \'%Select%\'';
312 $local_query .= ' AND `User` = \'';
313 $local_query .= PMA_Util::sqlAddSlashes(
314 $GLOBALS['cfg']['Server']['user']
315 ) . '\'';
316 $rs = $GLOBALS['dbi']->tryQuery($local_query, $GLOBALS['controllink']);
317 if ($rs && @$GLOBALS['dbi']->numRows($rs)) {
318 while ($row = $GLOBALS['dbi']->fetchAssoc($rs)) {
319 if (!in_array($row['Db'], $dblist)) {
320 $dblist[] = $row['Db'];
322 } // end while
323 $GLOBALS['dbi']->freeResult($rs);
324 } // end if