Czech translation update.
[phpmyadmin/last10db.git] / libraries / List_Database.class.php
blob2b9059c2cbf2bfcd8003cf1ab12b3cf67c346b4e
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * holds the PMA_List_Database class
6 * @version $Id$
7 */
9 /**
10 * the list base class
12 require_once './libraries/List.class.php';
14 /**
15 * handles database lists
17 * <code>
18 * $PMA_List_Database = new PMA_List_Database($userlink, $controllink);
19 * </code>
21 * @todo this object should be attached to the PMA_Server object
22 * @todo ? make use of INFORMATION_SCHEMA
23 * @todo ? support --skip-showdatabases and user has only global rights
24 * @access public
25 * @since phpMyAdmin 2.9.10
27 /*public*/ class PMA_List_Database extends PMA_List
29 /**
30 * @var mixed database link resource|object to be used
31 * @access protected
33 var $_db_link = null;
35 /**
36 * @var mixed user database link resource|object
37 * @access protected
39 var $_db_link_user = null;
41 /**
42 * @var mixed controluser database link resource|object
43 * @access protected
45 var $_db_link_control = null;
47 /**
48 * @var boolean whether SHOW DATABASES is disabled or not
49 * @access protected
51 var $_show_databases_disabled = false;
53 /**
54 * @var string command to retrieve databases from server
55 * @access protected
57 var $_command = null;
59 /**
60 * Constructor
62 * @uses PMA_List_Database::$_db_link
63 * @uses PMA_List_Database::$_db_link_user
64 * @uses PMA_List_Database::$_db_link_control
65 * @uses PMA_List_Database::build()
66 * @param mixed $db_link_user user database link resource|object
67 * @param mixed $db_link_control control database link resource|object
69 function __construct($db_link_user = null, $db_link_control = null) {
70 $this->_db_link = $db_link_user;
71 $this->_db_link_user = $db_link_user;
72 $this->_db_link_control = $db_link_control;
74 $this->build();
77 /**
78 * checks if the configuration wants to hide some databases
80 * @todo temporaly use this docblock to test how to doc $GLOBALS
81 * @access protected
82 * @uses PMA_List_Database::$items
83 * @uses PMA_List_Database::$_need_to_reindex to set it if reuqired
84 * @uses preg_match()
85 * @uses $cfg['Server']['hide_db']
87 function _checkHideDatabase()
89 if (empty($GLOBALS['cfg']['Server']['hide_db'])) {
90 return;
93 foreach ($this->items as $key => $db) {
94 if (preg_match('/' . $GLOBALS['cfg']['Server']['hide_db'] . '/', $db)) {
95 unset($this->items[$key]);
98 // re-index values
99 $this->_need_to_reindex = true;
103 * retrieves database list from server
105 * @todo we could also search mysql tables if all fail?
106 * @access protected
107 * @uses PMA_List_Database::$_show_databases_disabled for not retrying if SHOW DATABASES is disabled
108 * @uses PMA_List_Database::$_db_link
109 * @uses PMA_List_Database::$_db_link_control in case of SHOW DATABASES is disabled for userlink
110 * @uses PMA_DBI_fetch_result()
111 * @uses PMA_DBI_getError()
112 * @uses $GLOBALS['error_showdatabases']
113 * @uses $GLOBALS['errno']
114 * @param string $like_db_name usally a db_name containing wildcards
116 function _retrieve($like_db_name = null)
118 if ($this->_show_databases_disabled) {
119 return array();
122 if (null !== $like_db_name) {
123 $command = "SHOW DATABASES LIKE '" . $like_db_name . "'";
124 } elseif (null === $this->_command) {
125 $command = str_replace('#user#', $GLOBALS['cfg']['Server']['user'],
126 $GLOBALS['cfg']['Server']['ShowDatabasesCommand']);
127 $this->_command = $command;
128 } else {
129 $command = $this->_command;
132 $database_list = PMA_DBI_fetch_result($command, null, null, $this->_db_link);
133 PMA_DBI_getError();
135 if ($GLOBALS['errno'] !== 0) {
136 // failed to get database list, try the control user
137 // (hopefully there is one and he has SHOW DATABASES right)
138 $this->_db_link = $this->_db_link_control;
139 $database_list = PMA_DBI_fetch_result($command, null, null, $this->_db_link);
141 PMA_DBI_getError();
143 if ($GLOBALS['errno'] !== 0) {
144 // failed! we will display a warning that phpMyAdmin could not safely
145 // retrieve database list, the admin has to setup a control user or
146 // allow SHOW DATABASES
147 $GLOBALS['error_showdatabases'] = true;
148 $this->_show_databases_disabled = true;
152 return $database_list;
156 * builds up the list
158 * @uses PMA_List_Database::$items to initialize it
159 * @uses PMA_List_Database::$_need_to_reindex
160 * @uses PMA_List_Database::_checkOnlyDatabase()
161 * @uses PMA_List_Database::_retrieve()
162 * @uses PMA_List_Database::_checkHideDatabase()
163 * @uses array_values()
164 * @uses natsort()
165 * @uses $cfg['NaturalOrder']
167 function build()
169 $this->items = array();
171 if (! $this->_checkOnlyDatabase()) {
172 $this->items = $this->_retrieve();
173 if ($GLOBALS['cfg']['NaturalOrder']) {
174 natsort($this->items);
175 $this->_need_to_reindex = true;
179 $this->_checkHideDatabase();
181 if ($this->_need_to_reindex) {
182 $this->items = array_values($this->items);
187 * checks the only_db configuration
189 * @uses PMA_List_Database::$_show_databases_disabled
190 * @uses PMA_List_Database::$items
191 * @uses PMA_List_Database::_retrieve()
192 * @uses PMA_unescape_mysql_wildcards()
193 * @uses preg_match()
194 * @uses array_diff()
195 * @uses array_merge()
196 * @uses is_array()
197 * @uses strlen()
198 * @uses is_string()
199 * @uses $cfg['Server']['only_db']
200 * @return boolean false if there is no only_db, otherwise true
202 function _checkOnlyDatabase()
204 if (is_string($GLOBALS['cfg']['Server']['only_db'])
205 && strlen($GLOBALS['cfg']['Server']['only_db'])) {
206 $GLOBALS['cfg']['Server']['only_db'] = array(
207 $GLOBALS['cfg']['Server']['only_db']
211 if (! is_array($GLOBALS['cfg']['Server']['only_db'])) {
212 return false;
215 foreach ($GLOBALS['cfg']['Server']['only_db'] as $each_only_db) {
216 if ($each_only_db === '*' && ! $this->_show_databases_disabled) {
217 // append all not already listed dbs to the list
218 $this->items = array_merge($this->items,
219 array_diff($this->_retrieve(), $this->items));
220 // there can only be one '*', and this can only be last
221 break;
224 // check if the db name contains wildcard,
225 // thus containing not escaped _ or %
226 if (! preg_match('/(^|[^\\\\])(_|%)/', $each_only_db)) {
227 // ... not contains wildcard
228 $this->items[] = PMA_unescape_mysql_wildcards($each_only_db);
229 continue;
232 if (! $this->_show_databases_disabled) {
233 $this->items = array_merge($this->items, $this->_retrieve($each_only_db));
234 continue;
237 // @todo induce error, about not using wildcards with SHOW DATABASE disabled?
240 return true;
244 * returns default item
246 * @uses PMA_List::getEmpty()
247 * @uses $GLOBALS['db']
248 * @uses strlen()
249 * @return string default item
251 function getDefault()
253 if (strlen($GLOBALS['db'])) {
254 return $GLOBALS['db'];
257 return $this->getEmpty();
261 * returns array with dbs grouped with extended infos
263 * @uses $GLOBALS['PMA_List_Database']
264 * @uses $GLOBALS['cfgRelation']['commwork']
265 * @uses $cfg['ShowTooltip']
266 * @uses $cfg['LeftFrameDBTree']
267 * @uses $cfg['LeftFrameDBSeparator']
268 * @uses $cfg['ShowTooltipAliasDB']
269 * @uses PMA_getTableCount()
270 * @uses PMA_getDbComment()
271 * @uses is_array()
272 * @uses implode()
273 * @uses strstr()
274 * @uses explode()
275 * @param integer $offset
276 * @param integer $count
277 * @return array db list
279 function getGroupedDetails($offset, $count)
281 $dbgroups = array();
282 $parts = array();
284 if ($GLOBALS['cfg']['ShowTooltip']
285 && $GLOBALS['cfgRelation']['commwork']) {
286 $db_tooltips = PMA_getDbComments();
289 foreach ($this->getLimitedItems($offset, $count) as $key => $db) {
290 // garvin: Get comments from PMA comments table
291 $db_tooltip = '';
293 if (isset($db_tooltips[$db])) {
294 $db_tooltip = $_db_tooltips[$db];
297 if ($GLOBALS['cfg']['LeftFrameDBTree']
298 && $GLOBALS['cfg']['LeftFrameDBSeparator']
299 && strstr($db, $GLOBALS['cfg']['LeftFrameDBSeparator']))
301 // use strpos instead of strrpos; it seems more common to
302 // have the db name, the separator, then the rest which
303 // might contain a separator
304 // like dbname_the_rest
305 $pos = strpos($db, $GLOBALS['cfg']['LeftFrameDBSeparator']);
306 $group = substr($db, 0, $pos);
307 $disp_name_cut = substr($db, $pos);
308 } else {
309 $group = $db;
310 $disp_name_cut = $db;
313 $disp_name = $db;
314 if ($db_tooltip && $GLOBALS['cfg']['ShowTooltipAliasDB']) {
315 $disp_name = $db_tooltip;
316 $disp_name_cut = $db_tooltip;
317 $db_tooltip = $db;
320 $dbgroups[$group][$db] = array(
321 'name' => $db,
322 'disp_name_cut' => $disp_name_cut,
323 'disp_name' => $disp_name,
324 'comment' => $db_tooltip,
327 if ($GLOBALS['cfg']['Server']['CountTables']) {
328 $dbgroups[$group][$db]['num_tables'] = PMA_getTableCount($db);
330 } // end foreach ($GLOBALS['PMA_List_Database']->items as $db)
331 return $dbgroups;
335 * returns a part of the items
337 * @uses PMA_List_Database::$items
338 * @uses array_slice()
339 * @param integer $offset
340 * @param integer $count
341 * @return array some items
343 function getLimitedItems($offset, $count)
345 return(array_slice($this->items, $offset, $count));
349 * returns html code for list with dbs
351 * @return string html code list
353 function getHtmlListGrouped($selected = '', $offset, $count)
355 if (true === $selected) {
356 $selected = $this->getDefault();
359 $return = '<ul id="databaseList" xml:lang="en" dir="ltr">' . "\n";
360 foreach ($this->getGroupedDetails($offset, $count) as $group => $dbs) {
361 if (count($dbs) > 1) {
362 $return .= '<li>' . htmlspecialchars($group) . '<ul>' . "\n";
363 // wether display db_name cuted by the group part
364 $cut = true;
365 } else {
366 // .. or full
367 $cut = false;
369 foreach ($dbs as $db) {
370 $return .= '<li';
371 if ($db['name'] == $selected) {
372 $return .= ' class="selected"';
374 $return .= '><a';
375 if (! empty($db['comment'])) {
376 $return .= ' title="' . htmlspecialchars($db['comment']) . '"';
378 $return .= ' href="index.php?' . PMA_generate_common_url($db['name'])
379 . '" target="_parent">';
380 if ($cut) {
381 $return .= htmlspecialchars($db['disp_name_cut']);
382 } else {
383 $return .= htmlspecialchars($db['disp_name']);
386 if (! empty($db['num_tables'])) {
387 $return .= ' (' . $db['num_tables'] . ')';
389 $return .= '</a></li>' . "\n";
391 if (count($dbs) > 1) {
392 $return .= '</ul></li>' . "\n";
395 $return .= '</ul>';
397 return $return;
401 * returns html code for select form element with dbs
403 * @todo IE can not handle different text directions in select boxes so,
404 * as mostly names will be in english, we set the whole selectbox to LTR
405 * and EN
407 * @return string html code select
409 function getHtmlSelectGrouped($selected = '', $offset, $count)
411 if (true === $selected) {
412 $selected = $this->getDefault();
415 $return = '<select name="db" id="lightm_db" xml:lang="en" dir="ltr"'
416 . ' onchange="if (this.value != \'\') window.parent.openDb(this.value);">' . "\n"
417 . '<option value="" dir="' . $GLOBALS['text_dir'] . '">'
418 . '(' . $GLOBALS['strDatabases'] . ') ...</option>' . "\n";
419 foreach ($this->getGroupedDetails($offset, $count) as $group => $dbs) {
420 if (count($dbs) > 1) {
421 $return .= '<optgroup label="' . htmlspecialchars($group)
422 . '">' . "\n";
423 // wether display db_name cuted by the group part
424 $cut = true;
425 } else {
426 // .. or full
427 $cut = false;
429 foreach ($dbs as $db) {
430 $return .= '<option value="' . htmlspecialchars($db['name']) . '"'
431 .' title="' . htmlspecialchars($db['comment']) . '"';
432 if ($db['name'] == $selected) {
433 $return .= ' selected="selected"';
435 $return .= '>' . htmlspecialchars($cut ? $db['disp_name_cut'] : $db['disp_name']);
436 if (! empty($db['num_tables'])) {
437 $return .= ' (' . $db['num_tables'] . ')';
439 $return .= '</option>' . "\n";
441 if (count($dbs) > 1) {
442 $return .= '</optgroup>' . "\n";
445 $return .= '</select>';
447 return $return;
451 * this is just a backup, if all is fine this can be deleted later
453 * @deprecated
454 * @access protected
456 function _checkAgainstPrivTables()
458 // 1. get allowed dbs from the "mysql.db" table
459 // lem9: User can be blank (anonymous user)
460 $local_query = "
461 SELECT DISTINCT `Db` FROM `mysql`.`db`
462 WHERE `Select_priv` = 'Y'
463 AND `User`
464 IN ('" . PMA_sqlAddslashes($GLOBALS['cfg']['Server']['user']) . "', '')";
465 $tmp_mydbs = PMA_DBI_fetch_result($local_query, null, null,
466 $GLOBALS['controllink']);
467 if ($tmp_mydbs) {
468 // Will use as associative array of the following 2 code
469 // lines:
470 // the 1st is the only line intact from before
471 // correction,
472 // the 2nd replaces $dblist[] = $row['Db'];
474 // Code following those 2 lines in correction continues
475 // populating $dblist[], as previous code did. But it is
476 // now populated with actual database names instead of
477 // with regular expressions.
478 var_dump($tmp_mydbs);
479 $tmp_alldbs = PMA_DBI_query('SHOW DATABASES;', $GLOBALS['controllink']);
480 // loic1: all databases cases - part 2
481 if (isset($tmp_mydbs['%'])) {
482 while ($tmp_row = PMA_DBI_fetch_row($tmp_alldbs)) {
483 $dblist[] = $tmp_row[0];
484 } // end while
485 } else {
486 while ($tmp_row = PMA_DBI_fetch_row($tmp_alldbs)) {
487 $tmp_db = $tmp_row[0];
488 if (isset($tmp_mydbs[$tmp_db]) && $tmp_mydbs[$tmp_db] == 1) {
489 $dblist[] = $tmp_db;
490 $tmp_mydbs[$tmp_db] = 0;
491 } elseif (!isset($dblist[$tmp_db])) {
492 foreach ($tmp_mydbs as $tmp_matchpattern => $tmp_value) {
493 // loic1: fixed bad regexp
494 // TODO: db names may contain characters
495 // that are regexp instructions
496 $re = '(^|(\\\\\\\\)+|[^\])';
497 $tmp_regex = ereg_replace($re . '%', '\\1.*', ereg_replace($re . '_', '\\1.{1}', $tmp_matchpattern));
498 // Fixed db name matching
499 // 2000-08-28 -- Benjamin Gandon
500 if (ereg('^' . $tmp_regex . '$', $tmp_db)) {
501 $dblist[] = $tmp_db;
502 break;
504 } // end while
505 } // end if ... elseif ...
506 } // end while
507 } // end else
508 PMA_DBI_free_result($tmp_alldbs);
509 unset($tmp_mydbs);
510 } // end if
512 // 2. get allowed dbs from the "mysql.tables_priv" table
513 $local_query = 'SELECT DISTINCT Db FROM mysql.tables_priv WHERE Table_priv LIKE \'%Select%\' AND User = \'' . PMA_sqlAddslashes($GLOBALS['cfg']['Server']['user']) . '\'';
514 $rs = PMA_DBI_try_query($local_query, $GLOBALS['controllink']);
515 if ($rs && @PMA_DBI_num_rows($rs)) {
516 while ($row = PMA_DBI_fetch_assoc($rs)) {
517 if (!in_array($row['Db'], $dblist)) {
518 $dblist[] = $row['Db'];
520 } // end while
521 PMA_DBI_free_result($rs);
522 } // end if