bug #2363919 [display] Incorrect size for view
[phpmyadmin/crack.git] / libraries / List_Database.class.php
blobddb141dad1fe8b31501688a2aa95eb8d40e81a2c
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
32 protected $_db_link = null;
34 /**
35 * @var mixed user database link resource|object
37 protected $_db_link_user = null;
39 /**
40 * @var mixed controluser database link resource|object
42 protected $_db_link_control = null;
44 /**
45 * @var boolean whether SHOW DATABASES is disabled or not
46 * @access protected
48 protected $_show_databases_disabled = false;
50 /**
51 * @var string command to retrieve databases from server
53 protected $_command = null;
55 /**
56 * Constructor
58 * @uses PMA_List_Database::$_db_link
59 * @uses PMA_List_Database::$_db_link_user
60 * @uses PMA_List_Database::$_db_link_control
61 * @uses PMA_List_Database::build()
62 * @param mixed $db_link_user user database link resource|object
63 * @param mixed $db_link_control control database link resource|object
65 public function __construct($db_link_user = null, $db_link_control = null)
67 $this->_db_link = $db_link_user;
68 $this->_db_link_user = $db_link_user;
69 $this->_db_link_control = $db_link_control;
71 parent::__construct();
72 $this->build();
75 /**
76 * checks if the configuration wants to hide some databases
78 * @todo temporaly use this docblock to test how to doc $GLOBALS
79 * @uses PMA_List_Database::$items
80 * @uses preg_match()
81 * @uses $cfg['Server']['hide_db']
83 protected function _checkHideDatabase()
85 if (empty($GLOBALS['cfg']['Server']['hide_db'])) {
86 return;
89 foreach ($this as $key => $db) {
90 if (preg_match('/' . $GLOBALS['cfg']['Server']['hide_db'] . '/', $db)) {
91 $this->offsetUnset($key);
96 /**
97 * retrieves database list from server
99 * @todo we could also search mysql tables if all fail?
100 * @uses PMA_List_Database::$_show_databases_disabled for not retrying if SHOW DATABASES is disabled
101 * @uses PMA_List_Database::$_db_link
102 * @uses PMA_List_Database::$_db_link_control in case of SHOW DATABASES is disabled for userlink
103 * @uses PMA_DBI_fetch_result()
104 * @uses PMA_DBI_getError()
105 * @uses $GLOBALS['error_showdatabases']
106 * @uses $GLOBALS['errno']
107 * @param string $like_db_name usally a db_name containing wildcards
109 protected function _retrieve($like_db_name = null)
111 if ($this->_show_databases_disabled) {
112 return array();
115 if (null !== $like_db_name) {
116 $command = "SHOW DATABASES LIKE '" . $like_db_name . "'";
117 } elseif (null === $this->_command) {
118 $command = str_replace('#user#', $GLOBALS['cfg']['Server']['user'],
119 $GLOBALS['cfg']['Server']['ShowDatabasesCommand']);
120 $this->_command = $command;
121 } else {
122 $command = $this->_command;
125 $database_list = PMA_DBI_fetch_result($command, null, null, $this->_db_link);
126 PMA_DBI_getError();
128 if ($GLOBALS['errno'] !== 0) {
129 // failed to get database list, try the control user
130 // (hopefully there is one and he has SHOW DATABASES right)
131 $this->_db_link = $this->_db_link_control;
132 $database_list = PMA_DBI_fetch_result($command, null, null, $this->_db_link);
134 PMA_DBI_getError();
136 if ($GLOBALS['errno'] !== 0) {
137 // failed! we will display a warning that phpMyAdmin could not safely
138 // retrieve database list, the admin has to setup a control user or
139 // allow SHOW DATABASES
140 $GLOBALS['error_showdatabases'] = true;
141 $this->_show_databases_disabled = true;
145 return $database_list;
149 * builds up the list
151 * @uses PMA_List_Database::$items to initialize it
152 * @uses PMA_List_Database::_checkOnlyDatabase()
153 * @uses PMA_List_Database::_retrieve()
154 * @uses PMA_List_Database::_checkHideDatabase()
155 * @uses array_values()
156 * @uses natsort()
157 * @uses $cfg['NaturalOrder']
159 public function build()
161 if (! $this->_checkOnlyDatabase()) {
162 $items = $this->_retrieve();
163 if ($GLOBALS['cfg']['NaturalOrder']) {
164 natsort($items);
166 $this->exchangeArray($items);
169 $this->_checkHideDatabase();
173 * checks the only_db configuration
175 * @uses PMA_List_Database::$_show_databases_disabled
176 * @uses PMA_List_Database::$items
177 * @uses PMA_List_Database::_retrieve()
178 * @uses PMA_unescape_mysql_wildcards()
179 * @uses preg_match()
180 * @uses array_diff()
181 * @uses array_merge()
182 * @uses is_array()
183 * @uses strlen()
184 * @uses is_string()
185 * @uses $cfg['Server']['only_db']
186 * @return boolean false if there is no only_db, otherwise true
188 protected function _checkOnlyDatabase()
190 if (is_string($GLOBALS['cfg']['Server']['only_db'])
191 && strlen($GLOBALS['cfg']['Server']['only_db'])) {
192 $GLOBALS['cfg']['Server']['only_db'] = array(
193 $GLOBALS['cfg']['Server']['only_db']
197 if (! is_array($GLOBALS['cfg']['Server']['only_db'])) {
198 return false;
201 $items = array();
203 foreach ($GLOBALS['cfg']['Server']['only_db'] as $each_only_db) {
204 if ($each_only_db === '*' && ! $this->_show_databases_disabled) {
205 // append all not already listed dbs to the list
206 $items = array_merge($items,
207 array_diff($this->_retrieve(), $items));
208 // there can only be one '*', and this can only be last
209 break;
212 // check if the db name contains wildcard,
213 // thus containing not escaped _ or %
214 if (! preg_match('/(^|[^\\\\])(_|%)/', $each_only_db)) {
215 // ... not contains wildcard
216 $items[] = PMA_unescape_mysql_wildcards($each_only_db);
217 continue;
220 if (! $this->_show_databases_disabled) {
221 $items = array_merge($items, $this->_retrieve($each_only_db));
222 continue;
225 // @todo induce error, about not using wildcards with SHOW DATABASE disabled?
228 $this->exchangeArray($items);
230 return true;
234 * returns default item
236 * @uses PMA_List::getEmpty()
237 * @uses $GLOBALS['db']
238 * @uses strlen()
239 * @return string default item
241 public function getDefault()
243 if (strlen($GLOBALS['db'])) {
244 return $GLOBALS['db'];
247 return $this->getEmpty();
251 * returns array with dbs grouped with extended infos
253 * @uses $GLOBALS['PMA_List_Database']
254 * @uses $GLOBALS['cfgRelation']['commwork']
255 * @uses $cfg['ShowTooltip']
256 * @uses $cfg['LeftFrameDBTree']
257 * @uses $cfg['LeftFrameDBSeparator']
258 * @uses $cfg['ShowTooltipAliasDB']
259 * @uses PMA_getTableCount()
260 * @uses PMA_getDbComment()
261 * @uses is_array()
262 * @uses implode()
263 * @uses strstr()
264 * @uses explode()
265 * @param integer $offset
266 * @param integer $count
267 * @return array db list
269 public function getGroupedDetails($offset, $count)
271 $dbgroups = array();
272 $parts = array();
274 if ($GLOBALS['cfg']['ShowTooltip']
275 && $GLOBALS['cfgRelation']['commwork']) {
276 $db_tooltips = PMA_getDbComments();
279 foreach ($this->getLimitedItems($offset, $count) as $key => $db) {
280 // garvin: Get comments from PMA comments table
281 $db_tooltip = '';
283 if (isset($db_tooltips[$db])) {
284 $db_tooltip = $_db_tooltips[$db];
287 if ($GLOBALS['cfg']['LeftFrameDBTree']
288 && $GLOBALS['cfg']['LeftFrameDBSeparator']
289 && strstr($db, $GLOBALS['cfg']['LeftFrameDBSeparator']))
291 // use strpos instead of strrpos; it seems more common to
292 // have the db name, the separator, then the rest which
293 // might contain a separator
294 // like dbname_the_rest
295 $pos = strpos($db, $GLOBALS['cfg']['LeftFrameDBSeparator']);
296 $group = substr($db, 0, $pos);
297 $disp_name_cut = substr($db, $pos);
298 } else {
299 $group = $db;
300 $disp_name_cut = $db;
303 $disp_name = $db;
304 if ($db_tooltip && $GLOBALS['cfg']['ShowTooltipAliasDB']) {
305 $disp_name = $db_tooltip;
306 $disp_name_cut = $db_tooltip;
307 $db_tooltip = $db;
310 $dbgroups[$group][$db] = array(
311 'name' => $db,
312 'disp_name_cut' => $disp_name_cut,
313 'disp_name' => $disp_name,
314 'comment' => $db_tooltip,
317 if ($GLOBALS['cfg']['Server']['CountTables']) {
318 $dbgroups[$group][$db]['num_tables'] = PMA_getTableCount($db);
320 } // end foreach ($GLOBALS['PMA_List_Database']->items as $db)
321 return $dbgroups;
325 * returns a part of the items
327 * @uses array_slice()
328 * @param integer $offset
329 * @param integer $count
330 * @return array some items
332 public function getLimitedItems($offset, $count)
334 return array_slice($this->getArrayCopy(), $offset, $count);
338 * returns html code for list with dbs
340 * @return string html code list
342 public function getHtmlListGrouped($selected = '', $offset, $count)
344 if (true === $selected) {
345 $selected = $this->getDefault();
348 $return = '<ul id="databaseList" xml:lang="en" dir="ltr">' . "\n";
349 foreach ($this->getGroupedDetails($offset, $count) as $group => $dbs) {
350 if (count($dbs) > 1) {
351 $return .= '<li>' . htmlspecialchars($group) . '<ul>' . "\n";
352 // whether display db_name cut by the group part
353 $cut = true;
354 } else {
355 // .. or full
356 $cut = false;
358 foreach ($dbs as $db) {
359 $return .= '<li';
360 if ($db['name'] == $selected) {
361 $return .= ' class="selected"';
363 $return .= '><a';
364 if (! empty($db['comment'])) {
365 $return .= ' title="' . htmlspecialchars($db['comment']) . '"';
367 $return .= ' href="index.php?' . PMA_generate_common_url($db['name'])
368 . '" target="_parent">';
369 if ($cut) {
370 $return .= htmlspecialchars($db['disp_name_cut']);
371 } else {
372 $return .= htmlspecialchars($db['disp_name']);
375 if (! empty($db['num_tables'])) {
376 $return .= ' (' . $db['num_tables'] . ')';
378 $return .= '</a></li>' . "\n";
380 if (count($dbs) > 1) {
381 $return .= '</ul></li>' . "\n";
384 $return .= '</ul>';
386 return $return;
390 * returns html code for select form element with dbs
392 * @todo IE can not handle different text directions in select boxes so,
393 * as mostly names will be in english, we set the whole selectbox to LTR
394 * and EN
396 * @return string html code select
398 public function getHtmlSelectGrouped($selected = '', $offset, $count)
400 if (true === $selected) {
401 $selected = $this->getDefault();
404 $return = '<select name="db" id="lightm_db" xml:lang="en" dir="ltr"'
405 . ' onchange="if (this.value != \'\') window.parent.openDb(this.value);">' . "\n"
406 . '<option value="" dir="' . $GLOBALS['text_dir'] . '">'
407 . '(' . $GLOBALS['strDatabases'] . ') ...</option>' . "\n";
408 foreach ($this->getGroupedDetails($offset, $count) as $group => $dbs) {
409 if (count($dbs) > 1) {
410 $return .= '<optgroup label="' . htmlspecialchars($group)
411 . '">' . "\n";
412 // whether display db_name cuted by the group part
413 $cut = true;
414 } else {
415 // .. or full
416 $cut = false;
418 foreach ($dbs as $db) {
419 $return .= '<option value="' . htmlspecialchars($db['name']) . '"'
420 .' title="' . htmlspecialchars($db['comment']) . '"';
421 if ($db['name'] == $selected) {
422 $return .= ' selected="selected"';
424 $return .= '>' . htmlspecialchars($cut ? $db['disp_name_cut'] : $db['disp_name']);
425 if (! empty($db['num_tables'])) {
426 $return .= ' (' . $db['num_tables'] . ')';
428 $return .= '</option>' . "\n";
430 if (count($dbs) > 1) {
431 $return .= '</optgroup>' . "\n";
434 $return .= '</select>';
436 return $return;
440 * this is just a backup, if all is fine this can be deleted later
442 * @deprecated
444 protected function _checkAgainstPrivTables()
446 // 1. get allowed dbs from the "mysql.db" table
447 // lem9: User can be blank (anonymous user)
448 $local_query = "
449 SELECT DISTINCT `Db` FROM `mysql`.`db`
450 WHERE `Select_priv` = 'Y'
451 AND `User`
452 IN ('" . PMA_sqlAddslashes($GLOBALS['cfg']['Server']['user']) . "', '')";
453 $tmp_mydbs = PMA_DBI_fetch_result($local_query, null, null,
454 $GLOBALS['controllink']);
455 if ($tmp_mydbs) {
456 // Will use as associative array of the following 2 code
457 // lines:
458 // the 1st is the only line intact from before
459 // correction,
460 // the 2nd replaces $dblist[] = $row['Db'];
462 // Code following those 2 lines in correction continues
463 // populating $dblist[], as previous code did. But it is
464 // now populated with actual database names instead of
465 // with regular expressions.
466 $tmp_alldbs = PMA_DBI_query('SHOW DATABASES;', $GLOBALS['controllink']);
467 // loic1: all databases cases - part 2
468 if (isset($tmp_mydbs['%'])) {
469 while ($tmp_row = PMA_DBI_fetch_row($tmp_alldbs)) {
470 $dblist[] = $tmp_row[0];
471 } // end while
472 } else {
473 while ($tmp_row = PMA_DBI_fetch_row($tmp_alldbs)) {
474 $tmp_db = $tmp_row[0];
475 if (isset($tmp_mydbs[$tmp_db]) && $tmp_mydbs[$tmp_db] == 1) {
476 $dblist[] = $tmp_db;
477 $tmp_mydbs[$tmp_db] = 0;
478 } elseif (!isset($dblist[$tmp_db])) {
479 foreach ($tmp_mydbs as $tmp_matchpattern => $tmp_value) {
480 // loic1: fixed bad regexp
481 // TODO: db names may contain characters
482 // that are regexp instructions
483 $re = '(^|(\\\\\\\\)+|[^\])';
484 $tmp_regex = ereg_replace($re . '%', '\\1.*', ereg_replace($re . '_', '\\1.{1}', $tmp_matchpattern));
485 // Fixed db name matching
486 // 2000-08-28 -- Benjamin Gandon
487 if (ereg('^' . $tmp_regex . '$', $tmp_db)) {
488 $dblist[] = $tmp_db;
489 break;
491 } // end while
492 } // end if ... elseif ...
493 } // end while
494 } // end else
495 PMA_DBI_free_result($tmp_alldbs);
496 unset($tmp_mydbs);
497 } // end if
499 // 2. get allowed dbs from the "mysql.tables_priv" table
500 $local_query = 'SELECT DISTINCT Db FROM mysql.tables_priv WHERE Table_priv LIKE \'%Select%\' AND User = \'' . PMA_sqlAddslashes($GLOBALS['cfg']['Server']['user']) . '\'';
501 $rs = PMA_DBI_try_query($local_query, $GLOBALS['controllink']);
502 if ($rs && @PMA_DBI_num_rows($rs)) {
503 while ($row = PMA_DBI_fetch_assoc($rs)) {
504 if (!in_array($row['Db'], $dblist)) {
505 $dblist[] = $row['Db'];
507 } // end while
508 PMA_DBI_free_result($rs);
509 } // end if