PageRenderTime 45ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/classes/Menu.php

http://github.com/phpmyadmin/phpmyadmin
PHP | 602 lines | 426 code | 87 blank | 89 comment | 59 complexity | 683ab3f6d8071b068f4747430433d6a7 MD5 | raw file
Possible License(s): GPL-2.0, MIT, LGPL-3.0
  1. <?php
  2. /**
  3. * Generates and renders the top menu
  4. */
  5. declare(strict_types=1);
  6. namespace PhpMyAdmin;
  7. use PhpMyAdmin\Query\Utilities;
  8. use PhpMyAdmin\Utils\SessionCache;
  9. use function __;
  10. use function array_key_exists;
  11. use function count;
  12. use function in_array;
  13. use function mb_strpos;
  14. use function mb_strstr;
  15. use function mb_substr;
  16. use function preg_replace;
  17. use function strlen;
  18. /**
  19. * Class for generating the top menu
  20. */
  21. class Menu
  22. {
  23. /**
  24. * Database name
  25. *
  26. * @access private
  27. * @var string
  28. */
  29. private $db;
  30. /**
  31. * Table name
  32. *
  33. * @access private
  34. * @var string
  35. */
  36. private $table;
  37. /** @var Relation */
  38. private $relation;
  39. /** @var Template */
  40. private $template;
  41. /**
  42. * Creates a new instance of Menu
  43. *
  44. * @param string $db Database name
  45. * @param string $table Table name
  46. */
  47. public function __construct($db, $table)
  48. {
  49. global $dbi;
  50. $this->db = $db;
  51. $this->table = $table;
  52. $this->relation = new Relation($dbi);
  53. $this->template = new Template();
  54. }
  55. /**
  56. * Returns the menu and the breadcrumbs as a string
  57. *
  58. * @return string
  59. */
  60. public function getDisplay()
  61. {
  62. $retval = $this->getBreadcrumbs();
  63. $retval .= $this->getMenu();
  64. return $retval;
  65. }
  66. /**
  67. * Returns the menu as HTML
  68. *
  69. * @return string HTML formatted menubar
  70. */
  71. private function getMenu(): string
  72. {
  73. $urlParams = [];
  74. $hasDbArg = strlen($this->db) > 0;
  75. // The URL will not work if the table is defined without a database
  76. if (strlen((string) $this->table) > 0 && $hasDbArg) {
  77. $tabs = $this->getTableTabs();
  78. $urlParams['db'] = $this->db;
  79. $urlParams['table'] = $this->table;
  80. $level = 'table';
  81. } elseif ($hasDbArg) {
  82. $tabs = $this->getDbTabs();
  83. $urlParams['db'] = $this->db;
  84. $level = 'db';
  85. } else {
  86. $tabs = $this->getServerTabs();
  87. $level = 'server';
  88. }
  89. $allowedTabs = $this->getAllowedTabs($level);
  90. foreach ($tabs as $key => $value) {
  91. if (array_key_exists($key, $allowedTabs)) {
  92. continue;
  93. }
  94. unset($tabs[$key]);
  95. }
  96. return $this->template->render('top_menu', [
  97. 'tabs' => $tabs,
  98. 'url_params' => $urlParams,
  99. ]);
  100. }
  101. /**
  102. * Returns a list of allowed tabs for the current user for the given level
  103. *
  104. * @param string $level 'server', 'db' or 'table' level
  105. *
  106. * @return array list of allowed tabs
  107. */
  108. private function getAllowedTabs($level)
  109. {
  110. global $dbi;
  111. $cacheKey = 'menu-levels-' . $level;
  112. if (SessionCache::has($cacheKey)) {
  113. return SessionCache::get($cacheKey);
  114. }
  115. $allowedTabs = Util::getMenuTabList($level);
  116. $cfgRelation = $this->relation->getRelationsParam();
  117. if ($cfgRelation['menuswork']) {
  118. $groupTable = Util::backquote($cfgRelation['db'])
  119. . '.'
  120. . Util::backquote($cfgRelation['usergroups']);
  121. $userTable = Util::backquote($cfgRelation['db'])
  122. . '.' . Util::backquote($cfgRelation['users']);
  123. $sqlQuery = 'SELECT `tab` FROM ' . $groupTable
  124. . " WHERE `allowed` = 'N'"
  125. . " AND `tab` LIKE '" . $level . "%'"
  126. . ' AND `usergroup` = (SELECT usergroup FROM '
  127. . $userTable . " WHERE `username` = '"
  128. . $dbi->escapeString($GLOBALS['cfg']['Server']['user']) . "')";
  129. $result = $this->relation->queryAsControlUser($sqlQuery, false);
  130. if ($result) {
  131. while ($row = $dbi->fetchAssoc($result)) {
  132. $tabName = mb_substr(
  133. $row['tab'],
  134. mb_strpos($row['tab'], '_') + 1
  135. );
  136. unset($allowedTabs[$tabName]);
  137. }
  138. }
  139. }
  140. SessionCache::set($cacheKey, $allowedTabs);
  141. return $allowedTabs;
  142. }
  143. /**
  144. * Returns the breadcrumbs as HTML
  145. *
  146. * @return string HTML formatted breadcrumbs
  147. */
  148. private function getBreadcrumbs(): string
  149. {
  150. global $cfg, $dbi;
  151. $server = [];
  152. $database = [];
  153. $table = [];
  154. if (empty($cfg['Server']['host'])) {
  155. $cfg['Server']['host'] = '';
  156. }
  157. $server['name'] = ! empty($cfg['Server']['verbose'])
  158. ? $cfg['Server']['verbose'] : $cfg['Server']['host'];
  159. $server['name'] .= empty($cfg['Server']['port'])
  160. ? '' : ':' . $cfg['Server']['port'];
  161. $server['url'] = Util::getUrlForOption($cfg['DefaultTabServer'], 'server');
  162. if (strlen($this->db) > 0) {
  163. $database['name'] = $this->db;
  164. $database['url'] = Util::getUrlForOption($cfg['DefaultTabDatabase'], 'database');
  165. if (strlen((string) $this->table) > 0) {
  166. $table['name'] = $this->table;
  167. $table['url'] = Util::getUrlForOption($cfg['DefaultTabTable'], 'table');
  168. /** @var Table $tableObj */
  169. $tableObj = $dbi->getTable($this->db, $this->table);
  170. $table['is_view'] = $tableObj->isView();
  171. $table['comment'] = '';
  172. if (! $table['is_view']) {
  173. $table['comment'] = $tableObj->getComment();
  174. }
  175. if (mb_strstr($table['comment'], '; InnoDB free')) {
  176. $table['comment'] = preg_replace('@; InnoDB free:.*?$@', '', $table['comment']);
  177. }
  178. } else {
  179. // no table selected, display database comment if present
  180. $cfgRelation = $this->relation->getRelationsParam();
  181. // Get additional information about tables for tooltip is done
  182. // in Util::getDbInfo() only once
  183. if ($cfgRelation['commwork']) {
  184. $database['comment'] = $this->relation->getDbComment($this->db);
  185. }
  186. }
  187. }
  188. return $this->template->render('menu/breadcrumbs', [
  189. 'server' => $server,
  190. 'database' => $database,
  191. 'table' => $table,
  192. ]);
  193. }
  194. /**
  195. * Returns the table tabs as an array
  196. *
  197. * @return array Data for generating table tabs
  198. */
  199. private function getTableTabs()
  200. {
  201. global $route, $dbi;
  202. $isSystemSchema = Utilities::isSystemSchema($this->db);
  203. $tableIsView = $dbi->getTable($this->db, $this->table)
  204. ->isView();
  205. $updatableView = false;
  206. if ($tableIsView) {
  207. $updatableView = $dbi->getTable($this->db, $this->table)
  208. ->isUpdatableView();
  209. }
  210. $isSuperUser = $dbi->isSuperUser();
  211. $isCreateOrGrantUser = $dbi->isGrantUser() || $dbi->isCreateUser();
  212. $tabs = [];
  213. $tabs['browse']['icon'] = 'b_browse';
  214. $tabs['browse']['text'] = __('Browse');
  215. $tabs['browse']['route'] = '/sql';
  216. $tabs['browse']['args']['pos'] = 0;
  217. $tabs['browse']['active'] = $route === '/sql';
  218. $tabs['structure']['icon'] = 'b_props';
  219. $tabs['structure']['route'] = '/table/structure';
  220. $tabs['structure']['text'] = __('Structure');
  221. $tabs['structure']['active'] = in_array($route, [
  222. '/table/relation',
  223. '/table/structure',
  224. ]);
  225. $tabs['sql']['icon'] = 'b_sql';
  226. $tabs['sql']['route'] = '/table/sql';
  227. $tabs['sql']['text'] = __('SQL');
  228. $tabs['sql']['active'] = $route === '/table/sql';
  229. $tabs['search']['icon'] = 'b_search';
  230. $tabs['search']['text'] = __('Search');
  231. $tabs['search']['route'] = '/table/search';
  232. $tabs['search']['active'] = in_array($route, [
  233. '/table/find-replace',
  234. '/table/search',
  235. '/table/zoom-search',
  236. ]);
  237. if (! $isSystemSchema && (! $tableIsView || $updatableView)) {
  238. $tabs['insert']['icon'] = 'b_insrow';
  239. $tabs['insert']['route'] = '/table/change';
  240. $tabs['insert']['text'] = __('Insert');
  241. $tabs['insert']['active'] = $route === '/table/change';
  242. }
  243. $tabs['export']['icon'] = 'b_tblexport';
  244. $tabs['export']['route'] = '/table/export';
  245. $tabs['export']['args']['single_table'] = 'true';
  246. $tabs['export']['text'] = __('Export');
  247. $tabs['export']['active'] = $route === '/table/export';
  248. /**
  249. * Don't display "Import" for views and information_schema
  250. */
  251. if (! $tableIsView && ! $isSystemSchema) {
  252. $tabs['import']['icon'] = 'b_tblimport';
  253. $tabs['import']['route'] = '/table/import';
  254. $tabs['import']['text'] = __('Import');
  255. $tabs['import']['active'] = $route === '/table/import';
  256. }
  257. if (($isSuperUser || $isCreateOrGrantUser) && ! $isSystemSchema) {
  258. $tabs['privileges']['route'] = '/server/privileges';
  259. $tabs['privileges']['args']['checkprivsdb'] = $this->db;
  260. $tabs['privileges']['args']['checkprivstable'] = $this->table;
  261. // stay on table view
  262. $tabs['privileges']['args']['viewing_mode'] = 'table';
  263. $tabs['privileges']['text'] = __('Privileges');
  264. $tabs['privileges']['icon'] = 's_rights';
  265. $tabs['privileges']['active'] = $route === '/server/privileges';
  266. }
  267. /**
  268. * Don't display "Operations" for views and information_schema
  269. */
  270. if (! $tableIsView && ! $isSystemSchema) {
  271. $tabs['operation']['icon'] = 'b_tblops';
  272. $tabs['operation']['route'] = '/table/operations';
  273. $tabs['operation']['text'] = __('Operations');
  274. $tabs['operation']['active'] = $route === '/table/operations';
  275. }
  276. /**
  277. * Views support a limited number of operations
  278. */
  279. if ($tableIsView && ! $isSystemSchema) {
  280. $tabs['operation']['icon'] = 'b_tblops';
  281. $tabs['operation']['route'] = '/view/operations';
  282. $tabs['operation']['text'] = __('Operations');
  283. $tabs['operation']['active'] = $route === '/view/operations';
  284. }
  285. if (Tracker::isActive() && ! $isSystemSchema) {
  286. $tabs['tracking']['icon'] = 'eye';
  287. $tabs['tracking']['text'] = __('Tracking');
  288. $tabs['tracking']['route'] = '/table/tracking';
  289. $tabs['tracking']['active'] = $route === '/table/tracking';
  290. }
  291. if (! $isSystemSchema && Util::currentUserHasPrivilege('TRIGGER', $this->db, $this->table) && ! $tableIsView) {
  292. $tabs['triggers']['route'] = '/table/triggers';
  293. $tabs['triggers']['text'] = __('Triggers');
  294. $tabs['triggers']['icon'] = 'b_triggers';
  295. $tabs['triggers']['active'] = $route === '/table/triggers';
  296. }
  297. return $tabs;
  298. }
  299. /**
  300. * Returns the db tabs as an array
  301. *
  302. * @return array Data for generating db tabs
  303. */
  304. private function getDbTabs()
  305. {
  306. global $route, $dbi;
  307. $isSystemSchema = Utilities::isSystemSchema($this->db);
  308. $numTables = count($dbi->getTables($this->db));
  309. $isSuperUser = $dbi->isSuperUser();
  310. $isCreateOrGrantUser = $dbi->isGrantUser() || $dbi->isCreateUser();
  311. /**
  312. * Gets the relation settings
  313. */
  314. $cfgRelation = $this->relation->getRelationsParam();
  315. $tabs = [];
  316. $tabs['structure']['route'] = '/database/structure';
  317. $tabs['structure']['text'] = __('Structure');
  318. $tabs['structure']['icon'] = 'b_props';
  319. $tabs['structure']['active'] = $route === '/database/structure';
  320. $tabs['sql']['route'] = '/database/sql';
  321. $tabs['sql']['text'] = __('SQL');
  322. $tabs['sql']['icon'] = 'b_sql';
  323. $tabs['sql']['active'] = $route === '/database/sql';
  324. $tabs['search']['text'] = __('Search');
  325. $tabs['search']['icon'] = 'b_search';
  326. $tabs['search']['route'] = '/database/search';
  327. $tabs['search']['active'] = $route === '/database/search';
  328. if ($numTables == 0) {
  329. $tabs['search']['warning'] = __('Database seems to be empty!');
  330. }
  331. $tabs['query']['text'] = __('Query');
  332. $tabs['query']['icon'] = 's_db';
  333. $tabs['query']['route'] = '/database/multi-table-query';
  334. $tabs['query']['active'] = $route === '/database/multi-table-query' || $route === '/database/qbe';
  335. if ($numTables == 0) {
  336. $tabs['query']['warning'] = __('Database seems to be empty!');
  337. }
  338. $tabs['export']['text'] = __('Export');
  339. $tabs['export']['icon'] = 'b_export';
  340. $tabs['export']['route'] = '/database/export';
  341. $tabs['export']['active'] = $route === '/database/export';
  342. if ($numTables == 0) {
  343. $tabs['export']['warning'] = __('Database seems to be empty!');
  344. }
  345. if (! $isSystemSchema) {
  346. $tabs['import']['route'] = '/database/import';
  347. $tabs['import']['text'] = __('Import');
  348. $tabs['import']['icon'] = 'b_import';
  349. $tabs['import']['active'] = $route === '/database/import';
  350. $tabs['operation']['route'] = '/database/operations';
  351. $tabs['operation']['text'] = __('Operations');
  352. $tabs['operation']['icon'] = 'b_tblops';
  353. $tabs['operation']['active'] = $route === '/database/operations';
  354. if ($isSuperUser || $isCreateOrGrantUser) {
  355. $tabs['privileges']['route'] = '/server/privileges';
  356. $tabs['privileges']['args']['checkprivsdb'] = $this->db;
  357. // stay on database view
  358. $tabs['privileges']['args']['viewing_mode'] = 'db';
  359. $tabs['privileges']['text'] = __('Privileges');
  360. $tabs['privileges']['icon'] = 's_rights';
  361. $tabs['privileges']['active'] = $route === '/server/privileges';
  362. }
  363. $tabs['routines']['route'] = '/database/routines';
  364. $tabs['routines']['text'] = __('Routines');
  365. $tabs['routines']['icon'] = 'b_routines';
  366. $tabs['routines']['active'] = $route === '/database/routines';
  367. if (Util::currentUserHasPrivilege('EVENT', $this->db)) {
  368. $tabs['events']['route'] = '/database/events';
  369. $tabs['events']['text'] = __('Events');
  370. $tabs['events']['icon'] = 'b_events';
  371. $tabs['events']['active'] = $route === '/database/events';
  372. }
  373. if (Util::currentUserHasPrivilege('TRIGGER', $this->db)) {
  374. $tabs['triggers']['route'] = '/database/triggers';
  375. $tabs['triggers']['text'] = __('Triggers');
  376. $tabs['triggers']['icon'] = 'b_triggers';
  377. $tabs['triggers']['active'] = $route === '/database/triggers';
  378. }
  379. }
  380. if (Tracker::isActive() && ! $isSystemSchema) {
  381. $tabs['tracking']['text'] = __('Tracking');
  382. $tabs['tracking']['icon'] = 'eye';
  383. $tabs['tracking']['route'] = '/database/tracking';
  384. $tabs['tracking']['active'] = $route === '/database/tracking';
  385. }
  386. if (! $isSystemSchema) {
  387. $tabs['designer']['text'] = __('Designer');
  388. $tabs['designer']['icon'] = 'b_relations';
  389. $tabs['designer']['route'] = '/database/designer';
  390. $tabs['designer']['active'] = $route === '/database/designer';
  391. }
  392. if (! $isSystemSchema && $cfgRelation['centralcolumnswork']) {
  393. $tabs['central_columns']['text'] = __('Central columns');
  394. $tabs['central_columns']['icon'] = 'centralColumns';
  395. $tabs['central_columns']['route'] = '/database/central-columns';
  396. $tabs['central_columns']['active'] = $route === '/database/central-columns';
  397. }
  398. return $tabs;
  399. }
  400. /**
  401. * Returns the server tabs as an array
  402. *
  403. * @return array Data for generating server tabs
  404. */
  405. private function getServerTabs()
  406. {
  407. global $route, $dbi;
  408. $isSuperUser = $dbi->isSuperUser();
  409. $isCreateOrGrantUser = $dbi->isGrantUser() || $dbi->isCreateUser();
  410. if (SessionCache::has('binary_logs')) {
  411. $binaryLogs = SessionCache::get('binary_logs');
  412. } else {
  413. $binaryLogs = $dbi->fetchResult(
  414. 'SHOW MASTER LOGS',
  415. 'Log_name',
  416. null,
  417. DatabaseInterface::CONNECT_USER,
  418. DatabaseInterface::QUERY_STORE
  419. );
  420. SessionCache::set('binary_logs', $binaryLogs);
  421. }
  422. $tabs = [];
  423. $tabs['databases']['icon'] = 's_db';
  424. $tabs['databases']['route'] = '/server/databases';
  425. $tabs['databases']['text'] = __('Databases');
  426. $tabs['databases']['active'] = $route === '/server/databases';
  427. $tabs['sql']['icon'] = 'b_sql';
  428. $tabs['sql']['route'] = '/server/sql';
  429. $tabs['sql']['text'] = __('SQL');
  430. $tabs['sql']['active'] = $route === '/server/sql';
  431. $tabs['status']['icon'] = 's_status';
  432. $tabs['status']['route'] = '/server/status';
  433. $tabs['status']['text'] = __('Status');
  434. $tabs['status']['active'] = in_array($route, [
  435. '/server/status',
  436. '/server/status/advisor',
  437. '/server/status/monitor',
  438. '/server/status/processes',
  439. '/server/status/queries',
  440. '/server/status/variables',
  441. ]);
  442. if ($isSuperUser || $isCreateOrGrantUser) {
  443. $tabs['rights']['icon'] = 's_rights';
  444. $tabs['rights']['route'] = '/server/privileges';
  445. $tabs['rights']['text'] = __('User accounts');
  446. $tabs['rights']['active'] = in_array($route, [
  447. '/server/privileges',
  448. '/server/user-groups',
  449. ]);
  450. $tabs['rights']['args']['viewing_mode'] = 'server';
  451. }
  452. $tabs['export']['icon'] = 'b_export';
  453. $tabs['export']['route'] = '/server/export';
  454. $tabs['export']['text'] = __('Export');
  455. $tabs['export']['active'] = $route === '/server/export';
  456. $tabs['import']['icon'] = 'b_import';
  457. $tabs['import']['route'] = '/server/import';
  458. $tabs['import']['text'] = __('Import');
  459. $tabs['import']['active'] = $route === '/server/import';
  460. $tabs['settings']['icon'] = 'b_tblops';
  461. $tabs['settings']['route'] = '/preferences/manage';
  462. $tabs['settings']['text'] = __('Settings');
  463. $tabs['settings']['active'] = in_array($route, [
  464. '/preferences/export',
  465. '/preferences/features',
  466. '/preferences/import',
  467. '/preferences/main-panel',
  468. '/preferences/manage',
  469. '/preferences/navigation',
  470. '/preferences/sql',
  471. '/preferences/two-factor',
  472. ]);
  473. if (! empty($binaryLogs)) {
  474. $tabs['binlog']['icon'] = 's_tbl';
  475. $tabs['binlog']['route'] = '/server/binlog';
  476. $tabs['binlog']['text'] = __('Binary log');
  477. $tabs['binlog']['active'] = $route === '/server/binlog';
  478. }
  479. if ($isSuperUser) {
  480. $tabs['replication']['icon'] = 's_replication';
  481. $tabs['replication']['route'] = '/server/replication';
  482. $tabs['replication']['text'] = __('Replication');
  483. $tabs['replication']['active'] = $route === '/server/replication';
  484. }
  485. $tabs['vars']['icon'] = 's_vars';
  486. $tabs['vars']['route'] = '/server/variables';
  487. $tabs['vars']['text'] = __('Variables');
  488. $tabs['vars']['active'] = $route === '/server/variables';
  489. $tabs['charset']['icon'] = 's_asci';
  490. $tabs['charset']['route'] = '/server/collations';
  491. $tabs['charset']['text'] = __('Charsets');
  492. $tabs['charset']['active'] = $route === '/server/collations';
  493. $tabs['engine']['icon'] = 'b_engine';
  494. $tabs['engine']['route'] = '/server/engines';
  495. $tabs['engine']['text'] = __('Engines');
  496. $tabs['engine']['active'] = $route === '/server/engines';
  497. $tabs['plugins']['icon'] = 'b_plugin';
  498. $tabs['plugins']['route'] = '/server/plugins';
  499. $tabs['plugins']['text'] = __('Plugins');
  500. $tabs['plugins']['active'] = $route === '/server/plugins';
  501. return $tabs;
  502. }
  503. /**
  504. * Set current table
  505. *
  506. * @param string $table Current table
  507. *
  508. * @return Menu
  509. */
  510. public function setTable($table)
  511. {
  512. $this->table = $table;
  513. return $this;
  514. }
  515. }