Navigation.php 9.4 KB

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