List_Database.class.php 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * holds the PMA_List_Database class
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. if (! defined('PHPMYADMIN')) {
  9. exit;
  10. }
  11. /**
  12. * the list base class
  13. */
  14. require_once './libraries/List.class.php';
  15. /**
  16. * handles database lists
  17. *
  18. * <code>
  19. * $PMA_List_Database = new PMA_List_Database($userlink, $controllink);
  20. * </code>
  21. *
  22. * @todo this object should be attached to the PMA_Server object
  23. * @todo ? make use of INFORMATION_SCHEMA
  24. * @todo ? support --skip-showdatabases and user has only global rights
  25. *
  26. * @package PhpMyAdmin
  27. * @since phpMyAdmin 2.9.10
  28. */
  29. class PMA_List_Database extends PMA_List
  30. {
  31. /**
  32. * @var mixed database link resource|object to be used
  33. * @access protected
  34. */
  35. protected $db_link = null;
  36. /**
  37. * @var mixed user database link resource|object
  38. * @access protected
  39. */
  40. protected $db_link_user = null;
  41. /**
  42. * @var mixed controluser database link resource|object
  43. * @access protected
  44. */
  45. protected $db_link_control = null;
  46. /**
  47. * @var boolean whether SHOW DATABASES is disabled or not
  48. * @access protected
  49. */
  50. protected $show_databases_disabled = false;
  51. /**
  52. * @var string command to retrieve databases from server
  53. * @access protected
  54. */
  55. protected $command = null;
  56. /**
  57. * Constructor
  58. *
  59. * @param mixed $db_link_user user database link resource|object
  60. * @param mixed $db_link_control control database link resource|object
  61. *
  62. * @return void
  63. */
  64. public function __construct($db_link_user = null, $db_link_control = null)
  65. {
  66. $this->db_link = $db_link_user;
  67. $this->db_link_user = $db_link_user;
  68. $this->db_link_control = $db_link_control;
  69. parent::__construct();
  70. $this->build();
  71. }
  72. /**
  73. * checks if the configuration wants to hide some databases
  74. *
  75. * @return void
  76. */
  77. protected function checkHideDatabase()
  78. {
  79. if (empty($GLOBALS['cfg']['Server']['hide_db'])) {
  80. return;
  81. }
  82. foreach ($this->getArrayCopy() as $key => $db) {
  83. if (preg_match('/' . $GLOBALS['cfg']['Server']['hide_db'] . '/', $db)) {
  84. $this->offsetUnset($key);
  85. }
  86. }
  87. }
  88. /**
  89. * retrieves database list from server
  90. *
  91. * @param string $like_db_name usally a db_name containing wildcards
  92. *
  93. * @return array
  94. * @todo we could also search mysql tables if all fail?
  95. */
  96. protected function retrieve($like_db_name = null)
  97. {
  98. if ($this->show_databases_disabled) {
  99. return array();
  100. }
  101. if (null !== $like_db_name) {
  102. $command = "SHOW DATABASES LIKE '" . $like_db_name . "'";
  103. } elseif (null === $this->command) {
  104. $command = str_replace(
  105. '#user#', $GLOBALS['cfg']['Server']['user'],
  106. $GLOBALS['cfg']['Server']['ShowDatabasesCommand']
  107. );
  108. $this->command = $command;
  109. } else {
  110. $command = $this->command;
  111. }
  112. $database_list = PMA_DBI_fetch_result($command, null, null, $this->db_link);
  113. PMA_DBI_getError();
  114. if ($GLOBALS['errno'] !== 0) {
  115. // failed to get database list, try the control user
  116. // (hopefully there is one and he has SHOW DATABASES right)
  117. $this->db_link = $this->db_link_control;
  118. $database_list = PMA_DBI_fetch_result(
  119. $command, null, null, $this->db_link
  120. );
  121. PMA_DBI_getError();
  122. if ($GLOBALS['errno'] !== 0) {
  123. // failed! we will display a warning that phpMyAdmin could not safely
  124. // retrieve database list, the admin has to setup a control user or
  125. // allow SHOW DATABASES
  126. $GLOBALS['error_showdatabases'] = true;
  127. $this->show_databases_disabled = true;
  128. }
  129. }
  130. if ($GLOBALS['cfg']['NaturalOrder']) {
  131. natsort($database_list);
  132. } else {
  133. // need to sort anyway, otherwise information_schema
  134. // goes at the top
  135. sort($database_list);
  136. }
  137. return $database_list;
  138. }
  139. /**
  140. * builds up the list
  141. *
  142. * @return void
  143. */
  144. public function build()
  145. {
  146. if (! $this->checkOnlyDatabase()) {
  147. $items = $this->retrieve();
  148. $this->exchangeArray($items);
  149. }
  150. $this->checkHideDatabase();
  151. }
  152. /**
  153. * checks the only_db configuration
  154. *
  155. * @return boolean false if there is no only_db, otherwise true
  156. */
  157. protected function checkOnlyDatabase()
  158. {
  159. if (is_string($GLOBALS['cfg']['Server']['only_db'])
  160. && strlen($GLOBALS['cfg']['Server']['only_db'])
  161. ) {
  162. $GLOBALS['cfg']['Server']['only_db'] = array(
  163. $GLOBALS['cfg']['Server']['only_db']
  164. );
  165. }
  166. if (! is_array($GLOBALS['cfg']['Server']['only_db'])) {
  167. return false;
  168. }
  169. $items = array();
  170. foreach ($GLOBALS['cfg']['Server']['only_db'] as $each_only_db) {
  171. // check if the db name contains wildcard,
  172. // thus containing not escaped _ or %
  173. if (! preg_match('/(^|[^\\\\])(_|%)/', $each_only_db)) {
  174. // ... not contains wildcard
  175. $items[] = PMA_Util::unescapeMysqlWildcards($each_only_db);
  176. continue;
  177. }
  178. if (! $this->show_databases_disabled) {
  179. $items = array_merge($items, $this->retrieve($each_only_db));
  180. continue;
  181. }
  182. // @todo induce error, about not using wildcards
  183. // with SHOW DATABASE disabled?
  184. }
  185. $this->exchangeArray($items);
  186. return true;
  187. }
  188. /**
  189. * returns default item
  190. *
  191. * @return string default item
  192. */
  193. public function getDefault()
  194. {
  195. if (strlen($GLOBALS['db'])) {
  196. return $GLOBALS['db'];
  197. }
  198. return $this->getEmpty();
  199. }
  200. /**
  201. * this is just a backup, if all is fine this can be deleted later
  202. *
  203. * @deprecated
  204. * @return void
  205. */
  206. protected function checkAgainstPrivTables()
  207. {
  208. // 1. get allowed dbs from the "mysql.db" table
  209. // User can be blank (anonymous user)
  210. $local_query = "
  211. SELECT DISTINCT `Db` FROM `mysql`.`db`
  212. WHERE `Select_priv` = 'Y'
  213. AND `User`
  214. IN ('" . PMA_Util::sqlAddSlashes($GLOBALS['cfg']['Server']['user']) . "', '')";
  215. $tmp_mydbs = PMA_DBI_fetch_result(
  216. $local_query, null, null, $GLOBALS['controllink']
  217. );
  218. if ($tmp_mydbs) {
  219. // Will use as associative array of the following 2 code
  220. // lines:
  221. // the 1st is the only line intact from before
  222. // correction,
  223. // the 2nd replaces $dblist[] = $row['Db'];
  224. // Code following those 2 lines in correction continues
  225. // populating $dblist[], as previous code did. But it is
  226. // now populated with actual database names instead of
  227. // with regular expressions.
  228. $tmp_alldbs = PMA_DBI_query('SHOW DATABASES;', $GLOBALS['controllink']);
  229. // all databases cases - part 2
  230. if (isset($tmp_mydbs['%'])) {
  231. while ($tmp_row = PMA_DBI_fetch_row($tmp_alldbs)) {
  232. $dblist[] = $tmp_row[0];
  233. } // end while
  234. } else {
  235. while ($tmp_row = PMA_DBI_fetch_row($tmp_alldbs)) {
  236. $tmp_db = $tmp_row[0];
  237. if (isset($tmp_mydbs[$tmp_db]) && $tmp_mydbs[$tmp_db] == 1) {
  238. $dblist[] = $tmp_db;
  239. $tmp_mydbs[$tmp_db] = 0;
  240. } elseif (! isset($dblist[$tmp_db])) {
  241. foreach ($tmp_mydbs as $tmp_matchpattern => $tmp_value) {
  242. // fixed bad regexp
  243. // TODO: db names may contain characters
  244. // that are regexp instructions
  245. $re = '(^|(\\\\\\\\)+|[^\])';
  246. $tmp_regex = preg_replace(
  247. '/' . addcslashes($re, '/') . '%/',
  248. '\\1.*',
  249. preg_replace(
  250. '/' . addcslashes($re, '/') . '_/',
  251. '\\1.{1}',
  252. $tmp_matchpattern
  253. )
  254. );
  255. // Fixed db name matching
  256. // 2000-08-28 -- Benjamin Gandon
  257. if (preg_match('/^' . addcslashes($tmp_regex, '/') . '$/', $tmp_db)) {
  258. $dblist[] = $tmp_db;
  259. break;
  260. }
  261. } // end while
  262. } // end if ... elseif ...
  263. } // end while
  264. } // end else
  265. PMA_DBI_free_result($tmp_alldbs);
  266. unset($tmp_mydbs);
  267. } // end if
  268. // 2. get allowed dbs from the "mysql.tables_priv" table
  269. $local_query = 'SELECT DISTINCT `Db` FROM `mysql`.`tables_priv`';
  270. $local_query .= ' WHERE `Table_priv` LIKE \'%Select%\'';
  271. $local_query .= ' AND `User` = \'';
  272. $local_query .= PMA_Util::sqlAddSlashes($GLOBALS['cfg']['Server']['user']) . '\'';
  273. $rs = PMA_DBI_try_query($local_query, $GLOBALS['controllink']);
  274. if ($rs && @PMA_DBI_num_rows($rs)) {
  275. while ($row = PMA_DBI_fetch_assoc($rs)) {
  276. if (!in_array($row['Db'], $dblist)) {
  277. $dblist[] = $row['Db'];
  278. }
  279. } // end while
  280. PMA_DBI_free_result($rs);
  281. } // end if
  282. }
  283. }
  284. ?>