Navigation.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. <?php
  2. /**
  3. * This class is responsible for instantiating
  4. * the various components of the navigation panel
  5. */
  6. declare(strict_types=1);
  7. namespace PhpMyAdmin\Navigation;
  8. use PhpMyAdmin\Config\PageSettings;
  9. use PhpMyAdmin\DatabaseInterface;
  10. use PhpMyAdmin\Relation;
  11. use PhpMyAdmin\Response;
  12. use PhpMyAdmin\Sanitize;
  13. use PhpMyAdmin\Server\Select;
  14. use PhpMyAdmin\Template;
  15. use PhpMyAdmin\Theme;
  16. use PhpMyAdmin\Url;
  17. use PhpMyAdmin\Util;
  18. use const PHP_URL_HOST;
  19. use function count;
  20. use function defined;
  21. use function file_exists;
  22. use function is_bool;
  23. use function parse_url;
  24. use function strpos;
  25. use function trim;
  26. /**
  27. * The navigation panel - displays server, db and table selection tree
  28. */
  29. class Navigation
  30. {
  31. /** @var Template */
  32. private $template;
  33. /** @var Relation */
  34. private $relation;
  35. /** @var DatabaseInterface */
  36. private $dbi;
  37. /** @var NavigationTree */
  38. private $tree;
  39. /**
  40. * @param Template $template Template instance
  41. * @param Relation $relation Relation instance
  42. * @param DatabaseInterface $dbi DatabaseInterface instance
  43. */
  44. public function __construct($template, $relation, $dbi)
  45. {
  46. $this->template = $template;
  47. $this->relation = $relation;
  48. $this->dbi = $dbi;
  49. $this->tree = new NavigationTree($this->template, $this->dbi);
  50. }
  51. /**
  52. * Renders the navigation tree, or part of it
  53. *
  54. * @return string The navigation tree
  55. */
  56. public function getDisplay(): string
  57. {
  58. global $cfg;
  59. $logo = [
  60. 'is_displayed' => $cfg['NavigationDisplayLogo'],
  61. 'has_link' => false,
  62. 'link' => '#',
  63. 'attributes' => ' target="_blank" rel="noopener noreferrer"',
  64. 'source' => '',
  65. ];
  66. $response = Response::getInstance();
  67. if (! $response->isAjax()) {
  68. $logo['source'] = $this->getLogoSource();
  69. $logo['has_link'] = (string) $cfg['NavigationLogoLink'] !== '';
  70. $logo['link'] = trim((string) $cfg['NavigationLogoLink']);
  71. if (! Sanitize::checkLink($logo['link'], true)) {
  72. $logo['link'] = 'index.php';
  73. }
  74. if ($cfg['NavigationLogoLinkWindow'] === 'main') {
  75. if (empty(parse_url($logo['link'], PHP_URL_HOST))) {
  76. $hasStartChar = strpos($logo['link'], '?');
  77. $logo['link'] .= Url::getCommon(
  78. [],
  79. is_bool($hasStartChar) ? '?' : Url::getArgSeparator()
  80. );
  81. // Internal link detected
  82. $logo['attributes'] = '';
  83. } else {
  84. // External links having a domain name should not be considered
  85. // to be links that can use our internal ajax loading
  86. $logo['attributes'] = ' class="disableAjax"';
  87. }
  88. }
  89. if ($cfg['NavigationDisplayServers'] && count($cfg['Servers']) > 1) {
  90. $serverSelect = Select::render(true, true);
  91. }
  92. if (! defined('PMA_DISABLE_NAVI_SETTINGS')) {
  93. $pageSettings = new PageSettings('Navi', 'pma_navigation_settings');
  94. $response->addHTML($pageSettings->getErrorHTML());
  95. $navigationSettings = $pageSettings->getHTML();
  96. }
  97. }
  98. if (! $response->isAjax()
  99. || ! empty($_POST['full'])
  100. || ! empty($_POST['reload'])
  101. ) {
  102. if ($cfg['ShowDatabasesNavigationAsTree']) {
  103. // provide database tree in navigation
  104. $navRender = $this->tree->renderState();
  105. } else {
  106. // provide legacy pre-4.0 navigation
  107. $navRender = $this->tree->renderDbSelect();
  108. }
  109. } else {
  110. $navRender = $this->tree->renderPath();
  111. }
  112. return $this->template->render('navigation/main', [
  113. 'is_ajax' => $response->isAjax(),
  114. 'logo' => $logo,
  115. 'config_navigation_width' => $cfg['NavigationWidth'],
  116. 'is_synced' => $cfg['NavigationLinkWithMainPanel'],
  117. 'is_highlighted' => $cfg['NavigationTreePointerEnable'],
  118. 'is_autoexpanded' => $cfg['NavigationTreeAutoexpandSingleDb'],
  119. 'server' => $GLOBALS['server'],
  120. 'auth_type' => $cfg['Server']['auth_type'],
  121. 'is_servers_displayed' => $cfg['NavigationDisplayServers'],
  122. 'servers' => $cfg['Servers'],
  123. 'server_select' => $serverSelect ?? '',
  124. 'navigation_tree' => $navRender,
  125. 'is_navigation_settings_enabled' => ! defined('PMA_DISABLE_NAVI_SETTINGS'),
  126. 'navigation_settings' => $navigationSettings ?? '',
  127. 'is_drag_drop_import_enabled' => $cfg['enable_drag_drop_import'] === true,
  128. 'is_mariadb' => $this->dbi->isMariaDB(),
  129. ]);
  130. }
  131. /**
  132. * Add an item of navigation tree to the hidden items list in PMA database.
  133. *
  134. * @param string $itemName name of the navigation tree item
  135. * @param string $itemType type of the navigation tree item
  136. * @param string $dbName database name
  137. * @param string $tableName table name if applicable
  138. *
  139. * @return void
  140. */
  141. public function hideNavigationItem(
  142. $itemName,
  143. $itemType,
  144. $dbName,
  145. $tableName = null
  146. ) {
  147. $navTable = Util::backquote($GLOBALS['cfgRelation']['db'])
  148. . '.' . Util::backquote($GLOBALS['cfgRelation']['navigationhiding']);
  149. $sqlQuery = 'INSERT INTO ' . $navTable
  150. . '(`username`, `item_name`, `item_type`, `db_name`, `table_name`)'
  151. . ' VALUES ('
  152. . "'" . $this->dbi->escapeString($GLOBALS['cfg']['Server']['user']) . "',"
  153. . "'" . $this->dbi->escapeString($itemName) . "',"
  154. . "'" . $this->dbi->escapeString($itemType) . "',"
  155. . "'" . $this->dbi->escapeString($dbName) . "',"
  156. . "'" . (! empty($tableName) ? $this->dbi->escapeString($tableName) : '' )
  157. . "')";
  158. $this->relation->queryAsControlUser($sqlQuery, false);
  159. }
  160. /**
  161. * Remove a hidden item of navigation tree from the
  162. * list of hidden items in PMA database.
  163. *
  164. * @param string $itemName name of the navigation tree item
  165. * @param string $itemType type of the navigation tree item
  166. * @param string $dbName database name
  167. * @param string $tableName table name if applicable
  168. *
  169. * @return void
  170. */
  171. public function unhideNavigationItem(
  172. $itemName,
  173. $itemType,
  174. $dbName,
  175. $tableName = null
  176. ) {
  177. $navTable = Util::backquote($GLOBALS['cfgRelation']['db'])
  178. . '.' . Util::backquote($GLOBALS['cfgRelation']['navigationhiding']);
  179. $sqlQuery = 'DELETE FROM ' . $navTable
  180. . ' WHERE'
  181. . " `username`='"
  182. . $this->dbi->escapeString($GLOBALS['cfg']['Server']['user']) . "'"
  183. . " AND `item_name`='" . $this->dbi->escapeString($itemName) . "'"
  184. . " AND `item_type`='" . $this->dbi->escapeString($itemType) . "'"
  185. . " AND `db_name`='" . $this->dbi->escapeString($dbName) . "'"
  186. . (! empty($tableName)
  187. ? " AND `table_name`='" . $this->dbi->escapeString($tableName) . "'"
  188. : ''
  189. );
  190. $this->relation->queryAsControlUser($sqlQuery, false);
  191. }
  192. /**
  193. * Returns HTML for the dialog to show hidden navigation items.
  194. *
  195. * @param string $database database name
  196. * @param string $itemType type of the items to include
  197. * @param string $table table name
  198. *
  199. * @return string HTML for the dialog to show hidden navigation items
  200. */
  201. public function getItemUnhideDialog($database, $itemType = null, $table = null)
  202. {
  203. $hidden = $this->getHiddenItems($database, $table);
  204. $typeMap = [
  205. 'group' => __('Groups:'),
  206. 'event' => __('Events:'),
  207. 'function' => __('Functions:'),
  208. 'procedure' => __('Procedures:'),
  209. 'table' => __('Tables:'),
  210. 'view' => __('Views:'),
  211. ];
  212. return $this->template->render('navigation/item_unhide_dialog', [
  213. 'database' => $database,
  214. 'table' => $table,
  215. 'hidden' => $hidden,
  216. 'types' => $typeMap,
  217. 'item_type' => $itemType,
  218. ]);
  219. }
  220. /**
  221. * @param string $database Database name
  222. * @param string|null $table Table name
  223. *
  224. * @return array
  225. */
  226. private function getHiddenItems(string $database, ?string $table): array
  227. {
  228. $navTable = Util::backquote($GLOBALS['cfgRelation']['db'])
  229. . '.' . Util::backquote($GLOBALS['cfgRelation']['navigationhiding']);
  230. $sqlQuery = 'SELECT `item_name`, `item_type` FROM ' . $navTable
  231. . " WHERE `username`='"
  232. . $this->dbi->escapeString($GLOBALS['cfg']['Server']['user']) . "'"
  233. . " AND `db_name`='" . $this->dbi->escapeString($database) . "'"
  234. . " AND `table_name`='"
  235. . (! empty($table) ? $this->dbi->escapeString($table) : '') . "'";
  236. $result = $this->relation->queryAsControlUser($sqlQuery, false);
  237. $hidden = [];
  238. if ($result) {
  239. while ($row = $this->dbi->fetchArray($result)) {
  240. $type = $row['item_type'];
  241. if (! isset($hidden[$type])) {
  242. $hidden[$type] = [];
  243. }
  244. $hidden[$type][] = $row['item_name'];
  245. }
  246. }
  247. $this->dbi->freeResult($result);
  248. return $hidden;
  249. }
  250. /**
  251. * @return string Logo source
  252. */
  253. private function getLogoSource(): string
  254. {
  255. /** @var Theme|null $PMA_Theme */
  256. global $PMA_Theme;
  257. if ($PMA_Theme !== null) {
  258. if (@file_exists($PMA_Theme->getFsPath() . 'img/logo_left.png')) {
  259. return $PMA_Theme->getPath() . '/img/logo_left.png';
  260. }
  261. if (@file_exists($PMA_Theme->getFsPath() . 'img/pma_logo2.png')) {
  262. return $PMA_Theme->getPath() . '/img/pma_logo2.png';
  263. }
  264. }
  265. return '';
  266. }
  267. }