gl-website-deployer/admin/phpMyAdmin/libraries/classes/Menu.php

586 lines
20 KiB
PHP
Raw Normal View History

2024-11-23 20:45:29 +01:00
<?php
/**
* Generates and renders the top menu
*/
declare(strict_types=1);
namespace PhpMyAdmin;
use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\Query\Utilities;
use PhpMyAdmin\Utils\SessionCache;
use function __;
use function array_intersect_key;
use function count;
use function in_array;
use function mb_strpos;
use function mb_strstr;
use function mb_substr;
use function preg_replace;
/**
* Class for generating the top menu
*/
class Menu
{
/**
* Database name
*
* @var string
*/
private $db;
/** @var DatabaseInterface */
private $dbi;
/**
* Table name
*
* @var string
*/
private $table;
/** @var Relation */
private $relation;
/** @var Template */
private $template;
/**
* Creates a new instance of Menu
*
* @param string $db Database name
* @param string $table Table name
*/
public function __construct(DatabaseInterface $dbi, string $db, string $table)
{
$this->db = $db;
$this->dbi = $dbi;
$this->table = $table;
$this->relation = new Relation($dbi);
$this->template = new Template();
}
/**
* Returns the menu and the breadcrumbs as a string
*/
public function getDisplay(): string
{
$retval = $this->getBreadcrumbs();
$retval .= $this->getMenu();
return $retval;
}
/**
* Returns the menu as HTML
*
* @return string HTML formatted menubar
*/
private function getMenu(): string
{
$urlParams = [];
// The URL will not work if the table is defined without a database
if ($this->table !== '' && $this->db !== '') {
$tabs = $this->getTableTabs();
$urlParams['db'] = $this->db;
$urlParams['table'] = $this->table;
$level = 'table';
} elseif ($this->db !== '') {
$tabs = $this->getDbTabs();
$urlParams['db'] = $this->db;
$level = 'db';
} else {
$tabs = $this->getServerTabs();
$level = 'server';
}
$allowedTabs = $this->getAllowedTabs($level);
// Filter out any tabs that are not allowed
$tabs = array_intersect_key($tabs, $allowedTabs);
return $this->template->render('top_menu', [
'tabs' => $tabs,
'url_params' => $urlParams,
]);
}
/**
* Returns a list of allowed tabs for the current user for the given level
*
* @param string $level 'server', 'db' or 'table' level
*
* @return array list of allowed tabs
*/
private function getAllowedTabs($level)
{
$cacheKey = 'menu-levels-' . $level;
if (SessionCache::has($cacheKey)) {
return SessionCache::get($cacheKey);
}
$allowedTabs = Util::getMenuTabList($level) ?? [];
$configurableMenusFeature = $this->relation->getRelationParameters()->configurableMenusFeature;
if ($configurableMenusFeature !== null) {
$groupTable = Util::backquote($configurableMenusFeature->database)
. '.' . Util::backquote($configurableMenusFeature->userGroups);
$userTable = Util::backquote($configurableMenusFeature->database)
. '.' . Util::backquote($configurableMenusFeature->users);
$sqlQuery = 'SELECT `tab` FROM ' . $groupTable
. " WHERE `allowed` = 'N'"
. " AND `tab` LIKE '" . $level . "%'"
. ' AND `usergroup` = (SELECT usergroup FROM '
. $userTable . " WHERE `username` = '"
. $this->dbi->escapeString($GLOBALS['cfg']['Server']['user']) . "')";
$result = $this->dbi->tryQueryAsControlUser($sqlQuery);
if ($result) {
while ($row = $result->fetchAssoc()) {
$tab = (string) $row['tab'];
$tabName = mb_substr(
$tab,
mb_strpos($tab, '_') + 1
);
unset($allowedTabs[$tabName]);
}
}
}
SessionCache::set($cacheKey, $allowedTabs);
return $allowedTabs;
}
/**
* Returns the breadcrumbs as HTML
*
* @return string HTML formatted breadcrumbs
*/
private function getBreadcrumbs(): string
{
global $cfg;
$server = [];
$database = [];
$table = [];
if (empty($cfg['Server']['host'])) {
$cfg['Server']['host'] = '';
}
$server['name'] = ! empty($cfg['Server']['verbose'])
? $cfg['Server']['verbose'] : $cfg['Server']['host'];
$server['name'] .= empty($cfg['Server']['port'])
? '' : ':' . $cfg['Server']['port'];
$server['url'] = Util::getUrlForOption($cfg['DefaultTabServer'], 'server');
if ($this->db !== '') {
$database['name'] = $this->db;
$database['url'] = Util::getUrlForOption($cfg['DefaultTabDatabase'], 'database');
if ($this->table !== '') {
$table['name'] = $this->table;
$table['url'] = Util::getUrlForOption($cfg['DefaultTabTable'], 'table');
$tableObj = $this->dbi->getTable($this->db, $this->table);
$table['is_view'] = $tableObj->isView();
$table['comment'] = '';
if (! $table['is_view']) {
$table['comment'] = $tableObj->getComment();
}
if (mb_strstr($table['comment'], '; InnoDB free')) {
$table['comment'] = preg_replace('@; InnoDB free:.*?$@', '', $table['comment']);
}
} else {
// no table selected, display database comment if present
$relationParameters = $this->relation->getRelationParameters();
// Get additional information about tables for tooltip is done
// in Util::getDbInfo() only once
if ($relationParameters->columnCommentsFeature !== null) {
$database['comment'] = $this->relation->getDbComment($this->db);
}
}
}
return $this->template->render('menu/breadcrumbs', [
'server' => $server,
'database' => $database,
'table' => $table,
]);
}
/**
* Returns the table tabs as an array
*
* @return array Data for generating table tabs
*/
private function getTableTabs(): array
{
global $route;
$isSystemSchema = Utilities::isSystemSchema($this->db);
$tableIsView = $this->dbi->getTable($this->db, $this->table)
->isView();
$updatableView = false;
if ($tableIsView) {
$updatableView = $this->dbi->getTable($this->db, $this->table)
->isUpdatableView();
}
$isSuperUser = $this->dbi->isSuperUser();
$isCreateOrGrantUser = $this->dbi->isGrantUser() || $this->dbi->isCreateUser();
$tabs = [];
$tabs['browse']['icon'] = 'b_browse';
$tabs['browse']['text'] = __('Browse');
$tabs['browse']['route'] = '/sql';
$tabs['browse']['args']['pos'] = 0;
$tabs['browse']['active'] = $route === '/sql';
$tabs['structure']['icon'] = 'b_props';
$tabs['structure']['route'] = '/table/structure';
$tabs['structure']['text'] = __('Structure');
$tabs['structure']['active'] = in_array($route, [
'/table/relation',
'/table/structure',
]);
$tabs['sql']['icon'] = 'b_sql';
$tabs['sql']['route'] = '/table/sql';
$tabs['sql']['text'] = __('SQL');
$tabs['sql']['active'] = $route === '/table/sql';
$tabs['search']['icon'] = 'b_search';
$tabs['search']['text'] = __('Search');
$tabs['search']['route'] = '/table/search';
$tabs['search']['active'] = in_array($route, [
'/table/find-replace',
'/table/search',
'/table/zoom-search',
]);
if (! $isSystemSchema && (! $tableIsView || $updatableView)) {
$tabs['insert']['icon'] = 'b_insrow';
$tabs['insert']['route'] = '/table/change';
$tabs['insert']['text'] = __('Insert');
$tabs['insert']['active'] = $route === '/table/change';
}
$tabs['export']['icon'] = 'b_tblexport';
$tabs['export']['route'] = '/table/export';
$tabs['export']['args']['single_table'] = 'true';
$tabs['export']['text'] = __('Export');
$tabs['export']['active'] = $route === '/table/export';
/**
* Don't display "Import" for views and information_schema
*/
if (! $tableIsView && ! $isSystemSchema) {
$tabs['import']['icon'] = 'b_tblimport';
$tabs['import']['route'] = '/table/import';
$tabs['import']['text'] = __('Import');
$tabs['import']['active'] = $route === '/table/import';
}
if (($isSuperUser || $isCreateOrGrantUser) && ! $isSystemSchema) {
$tabs['privileges']['route'] = '/server/privileges';
$tabs['privileges']['args']['checkprivsdb'] = $this->db;
$tabs['privileges']['args']['checkprivstable'] = $this->table;
// stay on table view
$tabs['privileges']['args']['viewing_mode'] = 'table';
$tabs['privileges']['text'] = __('Privileges');
$tabs['privileges']['icon'] = 's_rights';
$tabs['privileges']['active'] = $route === '/server/privileges';
}
/**
* Don't display "Operations" for views and information_schema
*/
if (! $tableIsView && ! $isSystemSchema) {
$tabs['operation']['icon'] = 'b_tblops';
$tabs['operation']['route'] = '/table/operations';
$tabs['operation']['text'] = __('Operations');
$tabs['operation']['active'] = $route === '/table/operations';
}
/**
* Views support a limited number of operations
*/
if ($tableIsView && ! $isSystemSchema) {
$tabs['operation']['icon'] = 'b_tblops';
$tabs['operation']['route'] = '/view/operations';
$tabs['operation']['text'] = __('Operations');
$tabs['operation']['active'] = $route === '/view/operations';
}
if (Tracker::isActive() && ! $isSystemSchema) {
$tabs['tracking']['icon'] = 'eye';
$tabs['tracking']['text'] = __('Tracking');
$tabs['tracking']['route'] = '/table/tracking';
$tabs['tracking']['active'] = $route === '/table/tracking';
}
if (! $isSystemSchema && Util::currentUserHasPrivilege('TRIGGER', $this->db, $this->table) && ! $tableIsView) {
$tabs['triggers']['route'] = '/table/triggers';
$tabs['triggers']['text'] = __('Triggers');
$tabs['triggers']['icon'] = 'b_triggers';
$tabs['triggers']['active'] = $route === '/table/triggers';
}
return $tabs;
}
/**
* Returns the db tabs as an array
*
* @return array Data for generating db tabs
*/
private function getDbTabs(): array
{
global $route;
$isSystemSchema = Utilities::isSystemSchema($this->db);
$numTables = count($this->dbi->getTables($this->db));
$isSuperUser = $this->dbi->isSuperUser();
$isCreateOrGrantUser = $this->dbi->isGrantUser() || $this->dbi->isCreateUser();
$relationParameters = $this->relation->getRelationParameters();
$tabs = [];
$tabs['structure']['route'] = '/database/structure';
$tabs['structure']['text'] = __('Structure');
$tabs['structure']['icon'] = 'b_props';
$tabs['structure']['active'] = $route === '/database/structure';
$tabs['sql']['route'] = '/database/sql';
$tabs['sql']['text'] = __('SQL');
$tabs['sql']['icon'] = 'b_sql';
$tabs['sql']['active'] = $route === '/database/sql';
$tabs['search']['text'] = __('Search');
$tabs['search']['icon'] = 'b_search';
$tabs['search']['route'] = '/database/search';
$tabs['search']['active'] = $route === '/database/search';
if ($numTables == 0) {
$tabs['search']['warning'] = __('Database seems to be empty!');
}
$tabs['query']['text'] = __('Query');
$tabs['query']['icon'] = 's_db';
$tabs['query']['route'] = '/database/multi-table-query';
$tabs['query']['active'] = $route === '/database/multi-table-query' || $route === '/database/qbe';
if ($numTables == 0) {
$tabs['query']['warning'] = __('Database seems to be empty!');
}
$tabs['export']['text'] = __('Export');
$tabs['export']['icon'] = 'b_export';
$tabs['export']['route'] = '/database/export';
$tabs['export']['active'] = $route === '/database/export';
if ($numTables == 0) {
$tabs['export']['warning'] = __('Database seems to be empty!');
}
if (! $isSystemSchema) {
$tabs['import']['route'] = '/database/import';
$tabs['import']['text'] = __('Import');
$tabs['import']['icon'] = 'b_import';
$tabs['import']['active'] = $route === '/database/import';
$tabs['operation']['route'] = '/database/operations';
$tabs['operation']['text'] = __('Operations');
$tabs['operation']['icon'] = 'b_tblops';
$tabs['operation']['active'] = $route === '/database/operations';
if ($isSuperUser || $isCreateOrGrantUser) {
$tabs['privileges']['route'] = '/server/privileges';
$tabs['privileges']['args']['checkprivsdb'] = $this->db;
// stay on database view
$tabs['privileges']['args']['viewing_mode'] = 'db';
$tabs['privileges']['text'] = __('Privileges');
$tabs['privileges']['icon'] = 's_rights';
$tabs['privileges']['active'] = $route === '/server/privileges';
}
$tabs['routines']['route'] = '/database/routines';
$tabs['routines']['text'] = __('Routines');
$tabs['routines']['icon'] = 'b_routines';
$tabs['routines']['active'] = $route === '/database/routines';
if (Util::currentUserHasPrivilege('EVENT', $this->db)) {
$tabs['events']['route'] = '/database/events';
$tabs['events']['text'] = __('Events');
$tabs['events']['icon'] = 'b_events';
$tabs['events']['active'] = $route === '/database/events';
}
if (Util::currentUserHasPrivilege('TRIGGER', $this->db)) {
$tabs['triggers']['route'] = '/database/triggers';
$tabs['triggers']['text'] = __('Triggers');
$tabs['triggers']['icon'] = 'b_triggers';
$tabs['triggers']['active'] = $route === '/database/triggers';
}
}
if (Tracker::isActive() && ! $isSystemSchema) {
$tabs['tracking']['text'] = __('Tracking');
$tabs['tracking']['icon'] = 'eye';
$tabs['tracking']['route'] = '/database/tracking';
$tabs['tracking']['active'] = $route === '/database/tracking';
}
if (! $isSystemSchema) {
$tabs['designer']['text'] = __('Designer');
$tabs['designer']['icon'] = 'b_relations';
$tabs['designer']['route'] = '/database/designer';
$tabs['designer']['active'] = $route === '/database/designer';
}
if (! $isSystemSchema && $relationParameters->centralColumnsFeature !== null) {
$tabs['central_columns']['text'] = __('Central columns');
$tabs['central_columns']['icon'] = 'centralColumns';
$tabs['central_columns']['route'] = '/database/central-columns';
$tabs['central_columns']['active'] = $route === '/database/central-columns';
}
return $tabs;
}
/**
* Returns the server tabs as an array
*
* @return array Data for generating server tabs
*/
private function getServerTabs(): array
{
global $route;
$isSuperUser = $this->dbi->isSuperUser();
$isCreateOrGrantUser = $this->dbi->isGrantUser() || $this->dbi->isCreateUser();
if (SessionCache::has('binary_logs')) {
$binaryLogs = SessionCache::get('binary_logs');
} else {
$binaryLogs = $this->dbi->fetchResult(
'SHOW MASTER LOGS',
'Log_name'
);
SessionCache::set('binary_logs', $binaryLogs);
}
$tabs = [];
$tabs['databases']['icon'] = 's_db';
$tabs['databases']['route'] = '/server/databases';
$tabs['databases']['text'] = __('Databases');
$tabs['databases']['active'] = $route === '/server/databases';
$tabs['sql']['icon'] = 'b_sql';
$tabs['sql']['route'] = '/server/sql';
$tabs['sql']['text'] = __('SQL');
$tabs['sql']['active'] = $route === '/server/sql';
$tabs['status']['icon'] = 's_status';
$tabs['status']['route'] = '/server/status';
$tabs['status']['text'] = __('Status');
$tabs['status']['active'] = in_array($route, [
'/server/status',
'/server/status/advisor',
'/server/status/monitor',
'/server/status/processes',
'/server/status/queries',
'/server/status/variables',
]);
if ($isSuperUser || $isCreateOrGrantUser) {
$tabs['rights']['icon'] = 's_rights';
$tabs['rights']['route'] = '/server/privileges';
$tabs['rights']['text'] = __('User accounts');
$tabs['rights']['active'] = in_array($route, [
'/server/privileges',
'/server/user-groups',
]);
$tabs['rights']['args']['viewing_mode'] = 'server';
}
$tabs['export']['icon'] = 'b_export';
$tabs['export']['route'] = '/server/export';
$tabs['export']['text'] = __('Export');
$tabs['export']['active'] = $route === '/server/export';
$tabs['import']['icon'] = 'b_import';
$tabs['import']['route'] = '/server/import';
$tabs['import']['text'] = __('Import');
$tabs['import']['active'] = $route === '/server/import';
$tabs['settings']['icon'] = 'b_tblops';
$tabs['settings']['route'] = '/preferences/manage';
$tabs['settings']['text'] = __('Settings');
$tabs['settings']['active'] = in_array($route, [
'/preferences/export',
'/preferences/features',
'/preferences/import',
'/preferences/main-panel',
'/preferences/manage',
'/preferences/navigation',
'/preferences/sql',
'/preferences/two-factor',
]);
if (! empty($binaryLogs)) {
$tabs['binlog']['icon'] = 's_tbl';
$tabs['binlog']['route'] = '/server/binlog';
$tabs['binlog']['text'] = __('Binary log');
$tabs['binlog']['active'] = $route === '/server/binlog';
}
if ($isSuperUser) {
$tabs['replication']['icon'] = 's_replication';
$tabs['replication']['route'] = '/server/replication';
$tabs['replication']['text'] = __('Replication');
$tabs['replication']['active'] = $route === '/server/replication';
}
$tabs['vars']['icon'] = 's_vars';
$tabs['vars']['route'] = '/server/variables';
$tabs['vars']['text'] = __('Variables');
$tabs['vars']['active'] = $route === '/server/variables';
$tabs['charset']['icon'] = 's_asci';
$tabs['charset']['route'] = '/server/collations';
$tabs['charset']['text'] = __('Charsets');
$tabs['charset']['active'] = $route === '/server/collations';
$tabs['engine']['icon'] = 'b_engine';
$tabs['engine']['route'] = '/server/engines';
$tabs['engine']['text'] = __('Engines');
$tabs['engine']['active'] = $route === '/server/engines';
$tabs['plugins']['icon'] = 'b_plugin';
$tabs['plugins']['route'] = '/server/plugins';
$tabs['plugins']['text'] = __('Plugins');
$tabs['plugins']['active'] = $route === '/server/plugins';
return $tabs;
}
/**
* Set current table
*
* @param string $table Current table
*
* @return Menu
*/
public function setTable(string $table)
{
$this->table = $table;
return $this;
}
}