Header.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Used to render the header of PMA's pages
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. namespace PhpMyAdmin;
  9. use PhpMyAdmin\Config;
  10. use PhpMyAdmin\Console;
  11. use PhpMyAdmin\Core;
  12. use PhpMyAdmin\Menu;
  13. use PhpMyAdmin\Message;
  14. use PhpMyAdmin\Navigation\Navigation;
  15. use PhpMyAdmin\RecentFavoriteTable;
  16. use PhpMyAdmin\Sanitize;
  17. use PhpMyAdmin\Scripts;
  18. use PhpMyAdmin\Url;
  19. use PhpMyAdmin\UserPreferences;
  20. use PhpMyAdmin\Util;
  21. /**
  22. * Class used to output the HTTP and HTML headers
  23. *
  24. * @package PhpMyAdmin
  25. */
  26. class Header
  27. {
  28. /**
  29. * Scripts instance
  30. *
  31. * @access private
  32. * @var Scripts
  33. */
  34. private $_scripts;
  35. /**
  36. * PhpMyAdmin\Console instance
  37. *
  38. * @access private
  39. * @var Console
  40. */
  41. private $_console;
  42. /**
  43. * Menu instance
  44. *
  45. * @access private
  46. * @var Menu
  47. */
  48. private $_menu;
  49. /**
  50. * Whether to offer the option of importing user settings
  51. *
  52. * @access private
  53. * @var bool
  54. */
  55. private $_userprefsOfferImport;
  56. /**
  57. * The page title
  58. *
  59. * @access private
  60. * @var string
  61. */
  62. private $_title;
  63. /**
  64. * The value for the id attribute for the body tag
  65. *
  66. * @access private
  67. * @var string
  68. */
  69. private $_bodyId;
  70. /**
  71. * Whether to show the top menu
  72. *
  73. * @access private
  74. * @var bool
  75. */
  76. private $_menuEnabled;
  77. /**
  78. * Whether to show the warnings
  79. *
  80. * @access private
  81. * @var bool
  82. */
  83. private $_warningsEnabled;
  84. /**
  85. * Whether the page is in 'print view' mode
  86. *
  87. * @access private
  88. * @var bool
  89. */
  90. private $_isPrintView;
  91. /**
  92. * Whether we are servicing an ajax request.
  93. *
  94. * @access private
  95. * @var bool
  96. */
  97. private $_isAjax;
  98. /**
  99. * Whether to display anything
  100. *
  101. * @access private
  102. * @var bool
  103. */
  104. private $_isEnabled;
  105. /**
  106. * Whether the HTTP headers (and possibly some HTML)
  107. * have already been sent to the browser
  108. *
  109. * @access private
  110. * @var bool
  111. */
  112. private $_headerIsSent;
  113. /**
  114. * @var UserPreferences
  115. */
  116. private $userPreferences;
  117. /**
  118. * Creates a new class instance
  119. */
  120. public function __construct()
  121. {
  122. $this->_isEnabled = true;
  123. $this->_isAjax = false;
  124. $this->_bodyId = '';
  125. $this->_title = '';
  126. $this->_console = new Console();
  127. $db = strlen($GLOBALS['db']) ? $GLOBALS['db'] : '';
  128. $table = strlen($GLOBALS['table']) ? $GLOBALS['table'] : '';
  129. $this->_menu = new Menu(
  130. $GLOBALS['server'],
  131. $db,
  132. $table
  133. );
  134. $this->_menuEnabled = true;
  135. $this->_warningsEnabled = true;
  136. $this->_isPrintView = false;
  137. $this->_scripts = new Scripts();
  138. $this->_addDefaultScripts();
  139. $this->_headerIsSent = false;
  140. // if database storage for user preferences is transient,
  141. // offer to load exported settings from localStorage
  142. // (detection will be done in JavaScript)
  143. $this->_userprefsOfferImport = false;
  144. if ($GLOBALS['PMA_Config']->get('user_preferences') == 'session'
  145. && ! isset($_SESSION['userprefs_autoload'])
  146. ) {
  147. $this->_userprefsOfferImport = true;
  148. }
  149. $this->userPreferences = new UserPreferences();
  150. }
  151. /**
  152. * Loads common scripts
  153. *
  154. * @return void
  155. */
  156. private function _addDefaultScripts()
  157. {
  158. // Localised strings
  159. $this->_scripts->addFile('vendor/jquery/jquery.min.js');
  160. $this->_scripts->addFile('vendor/jquery/jquery-migrate.js');
  161. $this->_scripts->addFile('whitelist.php');
  162. $this->_scripts->addFile('vendor/sprintf.js');
  163. $this->_scripts->addFile('ajax.js');
  164. $this->_scripts->addFile('keyhandler.js');
  165. $this->_scripts->addFile('vendor/jquery/jquery-ui.min.js');
  166. $this->_scripts->addFile('vendor/js.cookie.js');
  167. $this->_scripts->addFile('vendor/jquery/jquery.mousewheel.js');
  168. $this->_scripts->addFile('vendor/jquery/jquery.event.drag-2.2.js');
  169. $this->_scripts->addFile('vendor/jquery/jquery.validate.js');
  170. $this->_scripts->addFile('vendor/jquery/jquery-ui-timepicker-addon.js');
  171. $this->_scripts->addFile('vendor/jquery/jquery.ba-hashchange-1.3.js');
  172. $this->_scripts->addFile('vendor/jquery/jquery.debounce-1.0.5.js');
  173. $this->_scripts->addFile('menu-resizer.js');
  174. // Cross-framing protection
  175. if ($GLOBALS['cfg']['AllowThirdPartyFraming'] === false) {
  176. $this->_scripts->addFile('cross_framing_protection.js');
  177. }
  178. $this->_scripts->addFile('rte.js');
  179. if ($GLOBALS['cfg']['SendErrorReports'] !== 'never') {
  180. $this->_scripts->addFile('vendor/tracekit.js');
  181. $this->_scripts->addFile('error_report.js');
  182. }
  183. // Here would not be a good place to add CodeMirror because
  184. // the user preferences have not been merged at this point
  185. $this->_scripts->addFile('messages.php', array('l' => $GLOBALS['lang']));
  186. // Append the theme id to this url to invalidate
  187. // the cache on a theme change. Though this might be
  188. // unavailable for fatal errors.
  189. if (isset($GLOBALS['PMA_Theme'])) {
  190. $theme_id = urlencode($GLOBALS['PMA_Theme']->getId());
  191. } else {
  192. $theme_id = 'default';
  193. }
  194. $this->_scripts->addFile('config.js');
  195. $this->_scripts->addFile('doclinks.js');
  196. $this->_scripts->addFile('functions.js');
  197. $this->_scripts->addFile('navigation.js');
  198. $this->_scripts->addFile('indexes.js');
  199. $this->_scripts->addFile('common.js');
  200. $this->_scripts->addFile('page_settings.js');
  201. if (! $GLOBALS['PMA_Config']->get('DisableShortcutKeys')) {
  202. $this->_scripts->addFile('shortcuts_handler.js');
  203. }
  204. $this->_scripts->addCode($this->getJsParamsCode());
  205. }
  206. /**
  207. * Returns, as an array, a list of parameters
  208. * used on the client side
  209. *
  210. * @return array
  211. */
  212. public function getJsParams()
  213. {
  214. $db = strlen($GLOBALS['db']) ? $GLOBALS['db'] : '';
  215. $table = strlen($GLOBALS['table']) ? $GLOBALS['table'] : '';
  216. $pftext = isset($_SESSION['tmpval']['pftext'])
  217. ? $_SESSION['tmpval']['pftext'] : '';
  218. $params = array(
  219. 'common_query' => Url::getCommonRaw(),
  220. 'opendb_url' => Util::getScriptNameForOption(
  221. $GLOBALS['cfg']['DefaultTabDatabase'], 'database'
  222. ),
  223. 'lang' => $GLOBALS['lang'],
  224. 'server' => $GLOBALS['server'],
  225. 'table' => $table,
  226. 'db' => $db,
  227. 'token' => $_SESSION[' PMA_token '],
  228. 'text_dir' => $GLOBALS['text_dir'],
  229. 'show_databases_navigation_as_tree' => $GLOBALS['cfg']['ShowDatabasesNavigationAsTree'],
  230. 'pma_text_default_tab' => Util::getTitleForTarget(
  231. $GLOBALS['cfg']['DefaultTabTable']
  232. ),
  233. 'pma_text_left_default_tab' => Util::getTitleForTarget(
  234. $GLOBALS['cfg']['NavigationTreeDefaultTabTable']
  235. ),
  236. 'pma_text_left_default_tab2' => Util::getTitleForTarget(
  237. $GLOBALS['cfg']['NavigationTreeDefaultTabTable2']
  238. ),
  239. 'LimitChars' => $GLOBALS['cfg']['LimitChars'],
  240. 'pftext' => $pftext,
  241. 'confirm' => $GLOBALS['cfg']['Confirm'],
  242. 'LoginCookieValidity' => $GLOBALS['cfg']['LoginCookieValidity'],
  243. 'session_gc_maxlifetime' => (int)ini_get('session.gc_maxlifetime'),
  244. 'logged_in' => (isset($GLOBALS['dbi']) ? $GLOBALS['dbi']->isUserType('logged') : false),
  245. 'is_https' => $GLOBALS['PMA_Config']->isHttps(),
  246. 'rootPath' => $GLOBALS['PMA_Config']->getRootPath(),
  247. 'arg_separator' => URL::getArgSeparator(),
  248. 'PMA_VERSION' => PMA_VERSION
  249. );
  250. if (isset($GLOBALS['cfg']['Server'])
  251. && isset($GLOBALS['cfg']['Server']['auth_type'])
  252. ) {
  253. $params['auth_type'] = $GLOBALS['cfg']['Server']['auth_type'];
  254. if (isset($GLOBALS['cfg']['Server']['user'])) {
  255. $params['user'] = $GLOBALS['cfg']['Server']['user'];
  256. }
  257. }
  258. return $params;
  259. }
  260. /**
  261. * Returns, as a string, a list of parameters
  262. * used on the client side
  263. *
  264. * @return string
  265. */
  266. public function getJsParamsCode()
  267. {
  268. $params = $this->getJsParams();
  269. foreach ($params as $key => $value) {
  270. if (is_bool($value)) {
  271. $params[$key] = $key . ':' . ($value ? 'true' : 'false') . '';
  272. } else {
  273. $params[$key] = $key . ':"' . Sanitize::escapeJsString($value) . '"';
  274. }
  275. }
  276. return 'PMA_commonParams.setAll({' . implode(',', $params) . '});';
  277. }
  278. /**
  279. * Disables the rendering of the header
  280. *
  281. * @return void
  282. */
  283. public function disable()
  284. {
  285. $this->_isEnabled = false;
  286. }
  287. /**
  288. * Set the ajax flag to indicate whether
  289. * we are servicing an ajax request
  290. *
  291. * @param bool $isAjax Whether we are servicing an ajax request
  292. *
  293. * @return void
  294. */
  295. public function setAjax($isAjax)
  296. {
  297. $this->_isAjax = (boolean) $isAjax;
  298. $this->_console->setAjax($isAjax);
  299. }
  300. /**
  301. * Returns the Scripts object
  302. *
  303. * @return Scripts object
  304. */
  305. public function getScripts()
  306. {
  307. return $this->_scripts;
  308. }
  309. /**
  310. * Returns the Menu object
  311. *
  312. * @return Menu object
  313. */
  314. public function getMenu()
  315. {
  316. return $this->_menu;
  317. }
  318. /**
  319. * Setter for the ID attribute in the BODY tag
  320. *
  321. * @param string $id Value for the ID attribute
  322. *
  323. * @return void
  324. */
  325. public function setBodyId($id)
  326. {
  327. $this->_bodyId = htmlspecialchars($id);
  328. }
  329. /**
  330. * Setter for the title of the page
  331. *
  332. * @param string $title New title
  333. *
  334. * @return void
  335. */
  336. public function setTitle($title)
  337. {
  338. $this->_title = htmlspecialchars($title);
  339. }
  340. /**
  341. * Disables the display of the top menu
  342. *
  343. * @return void
  344. */
  345. public function disableMenuAndConsole()
  346. {
  347. $this->_menuEnabled = false;
  348. $this->_console->disable();
  349. }
  350. /**
  351. * Disables the display of the top menu
  352. *
  353. * @return void
  354. */
  355. public function disableWarnings()
  356. {
  357. $this->_warningsEnabled = false;
  358. }
  359. /**
  360. * Turns on 'print view' mode
  361. *
  362. * @return void
  363. */
  364. public function enablePrintView()
  365. {
  366. $this->disableMenuAndConsole();
  367. $this->setTitle(__('Print view') . ' - phpMyAdmin ' . PMA_VERSION);
  368. $this->_isPrintView = true;
  369. }
  370. /**
  371. * Generates the header
  372. *
  373. * @return string The header
  374. */
  375. public function getDisplay()
  376. {
  377. $retval = '';
  378. if (! $this->_headerIsSent) {
  379. if (! $this->_isAjax && $this->_isEnabled) {
  380. $this->sendHttpHeaders();
  381. $retval .= $this->_getHtmlStart();
  382. $retval .= $this->_getMetaTags();
  383. $retval .= $this->_getLinkTags();
  384. $retval .= $this->getTitleTag();
  385. // The user preferences have been merged at this point
  386. // so we can conditionally add CodeMirror
  387. if ($GLOBALS['cfg']['CodemirrorEnable']) {
  388. $this->_scripts->addFile('vendor/codemirror/lib/codemirror.js');
  389. $this->_scripts->addFile('vendor/codemirror/mode/sql/sql.js');
  390. $this->_scripts->addFile('vendor/codemirror/addon/runmode/runmode.js');
  391. $this->_scripts->addFile('vendor/codemirror/addon/hint/show-hint.js');
  392. $this->_scripts->addFile('vendor/codemirror/addon/hint/sql-hint.js');
  393. if ($GLOBALS['cfg']['LintEnable']) {
  394. $this->_scripts->addFile('vendor/codemirror/addon/lint/lint.js');
  395. $this->_scripts->addFile(
  396. 'codemirror/addon/lint/sql-lint.js'
  397. );
  398. }
  399. }
  400. $this->_scripts->addCode(
  401. 'ConsoleEnterExecutes='
  402. . ($GLOBALS['cfg']['ConsoleEnterExecutes'] ? 'true' : 'false')
  403. );
  404. $this->_scripts->addFiles($this->_console->getScripts());
  405. if ($this->_userprefsOfferImport) {
  406. $this->_scripts->addFile('config.js');
  407. }
  408. $retval .= $this->_scripts->getDisplay();
  409. $retval .= '<noscript>';
  410. $retval .= '<style>html{display:block}</style>';
  411. $retval .= '</noscript>';
  412. $retval .= $this->_getBodyStart();
  413. if ($this->_menuEnabled && $GLOBALS['server'] > 0) {
  414. $nav = new Navigation();
  415. $retval .= $nav->getDisplay();
  416. }
  417. // Include possible custom headers
  418. $retval .= Config::renderHeader();
  419. // offer to load user preferences from localStorage
  420. if ($this->_userprefsOfferImport) {
  421. $retval .= $this->userPreferences->autoloadGetHeader();
  422. }
  423. // pass configuration for hint tooltip display
  424. // (to be used by PMA_tooltip() in js/functions.js)
  425. if (! $GLOBALS['cfg']['ShowHint']) {
  426. $retval .= '<span id="no_hint" class="hide"></span>';
  427. }
  428. $retval .= $this->_getWarnings();
  429. if ($this->_menuEnabled && $GLOBALS['server'] > 0) {
  430. $retval .= $this->_menu->getDisplay();
  431. $retval .= '<span id="page_nav_icons">';
  432. $retval .= '<span id="lock_page_icon"></span>';
  433. $retval .= '<span id="page_settings_icon">'
  434. . Util::getImage(
  435. 's_cog',
  436. __('Page-related settings')
  437. )
  438. . '</span>';
  439. $retval .= sprintf(
  440. '<a id="goto_pagetop" href="#">%s</a>',
  441. Util::getImage(
  442. 's_top',
  443. __('Click on the bar to scroll to top of page')
  444. )
  445. );
  446. $retval .= '</span>';
  447. }
  448. $retval .= $this->_console->getDisplay();
  449. $retval .= '<div id="page_content">';
  450. $retval .= $this->getMessage();
  451. }
  452. if ($this->_isEnabled && empty($_REQUEST['recent_table'])) {
  453. $retval .= $this->_addRecentTable(
  454. $GLOBALS['db'],
  455. $GLOBALS['table']
  456. );
  457. }
  458. }
  459. return $retval;
  460. }
  461. /**
  462. * Returns the message to be displayed at the top of
  463. * the page, including the executed SQL query, if any.
  464. *
  465. * @return string
  466. */
  467. public function getMessage()
  468. {
  469. $retval = '';
  470. $message = '';
  471. if (! empty($GLOBALS['message'])) {
  472. $message = $GLOBALS['message'];
  473. unset($GLOBALS['message']);
  474. } elseif (! empty($_REQUEST['message'])) {
  475. $message = $_REQUEST['message'];
  476. }
  477. if (! empty($message)) {
  478. if (isset($GLOBALS['buffer_message'])) {
  479. $buffer_message = $GLOBALS['buffer_message'];
  480. }
  481. $retval .= Util::getMessage($message);
  482. if (isset($buffer_message)) {
  483. $GLOBALS['buffer_message'] = $buffer_message;
  484. }
  485. }
  486. return $retval;
  487. }
  488. /**
  489. * Sends out the HTTP headers
  490. *
  491. * @return void
  492. */
  493. public function sendHttpHeaders()
  494. {
  495. if (defined('TESTSUITE')) {
  496. return;
  497. }
  498. $map_tile_urls = ' *.tile.openstreetmap.org';
  499. /**
  500. * Sends http headers
  501. */
  502. $GLOBALS['now'] = gmdate('D, d M Y H:i:s') . ' GMT';
  503. if (!empty($GLOBALS['cfg']['CaptchaLoginPrivateKey'])
  504. && !empty($GLOBALS['cfg']['CaptchaLoginPublicKey'])
  505. ) {
  506. $captcha_url
  507. = ' https://apis.google.com https://www.google.com/recaptcha/'
  508. . ' https://www.gstatic.com/recaptcha/ https://ssl.gstatic.com/ ';
  509. } else {
  510. $captcha_url = '';
  511. }
  512. /* Prevent against ClickJacking by disabling framing */
  513. if (! $GLOBALS['cfg']['AllowThirdPartyFraming']) {
  514. header(
  515. 'X-Frame-Options: DENY'
  516. );
  517. }
  518. header('Referrer-Policy: no-referrer');
  519. header(
  520. "Content-Security-Policy: default-src 'self' "
  521. . $captcha_url
  522. . $GLOBALS['cfg']['CSPAllow'] . ';'
  523. . "script-src 'self' 'unsafe-inline' 'unsafe-eval' "
  524. . $captcha_url
  525. . $GLOBALS['cfg']['CSPAllow'] . ';'
  526. . "style-src 'self' 'unsafe-inline' "
  527. . $captcha_url
  528. . $GLOBALS['cfg']['CSPAllow']
  529. . ";"
  530. . "img-src 'self' data: "
  531. . $GLOBALS['cfg']['CSPAllow']
  532. . $map_tile_urls
  533. . $captcha_url
  534. . ";"
  535. . "object-src 'none';"
  536. );
  537. header(
  538. "X-Content-Security-Policy: default-src 'self' "
  539. . $captcha_url
  540. . $GLOBALS['cfg']['CSPAllow'] . ';'
  541. . "options inline-script eval-script;"
  542. . "referrer no-referrer;"
  543. . "img-src 'self' data: "
  544. . $GLOBALS['cfg']['CSPAllow']
  545. . $map_tile_urls
  546. . $captcha_url
  547. . ";"
  548. . "object-src 'none';"
  549. );
  550. header(
  551. "X-WebKit-CSP: default-src 'self' "
  552. . $captcha_url
  553. . $GLOBALS['cfg']['CSPAllow'] . ';'
  554. . "script-src 'self' "
  555. . $captcha_url
  556. . $GLOBALS['cfg']['CSPAllow']
  557. . " 'unsafe-inline' 'unsafe-eval';"
  558. . "referrer no-referrer;"
  559. . "style-src 'self' 'unsafe-inline' "
  560. . $captcha_url
  561. . ';'
  562. . "img-src 'self' data: "
  563. . $GLOBALS['cfg']['CSPAllow']
  564. . $map_tile_urls
  565. . $captcha_url
  566. . ";"
  567. . "object-src 'none';"
  568. );
  569. // Re-enable possible disabled XSS filters
  570. // see https://www.owasp.org/index.php/List_of_useful_HTTP_headers
  571. header(
  572. 'X-XSS-Protection: 1; mode=block'
  573. );
  574. // "nosniff", prevents Internet Explorer and Google Chrome from MIME-sniffing
  575. // a response away from the declared content-type
  576. // see https://www.owasp.org/index.php/List_of_useful_HTTP_headers
  577. header(
  578. 'X-Content-Type-Options: nosniff'
  579. );
  580. // Adobe cross-domain-policies
  581. // see https://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html
  582. header(
  583. 'X-Permitted-Cross-Domain-Policies: none'
  584. );
  585. // Robots meta tag
  586. // see https://developers.google.com/webmasters/control-crawl-index/docs/robots_meta_tag
  587. header(
  588. 'X-Robots-Tag: noindex, nofollow'
  589. );
  590. Core::noCacheHeader();
  591. if (! defined('IS_TRANSFORMATION_WRAPPER')) {
  592. // Define the charset to be used
  593. header('Content-Type: text/html; charset=utf-8');
  594. }
  595. $this->_headerIsSent = true;
  596. }
  597. /**
  598. * Returns the DOCTYPE and the start HTML tag
  599. *
  600. * @return string DOCTYPE and HTML tags
  601. */
  602. private function _getHtmlStart()
  603. {
  604. $lang = $GLOBALS['lang'];
  605. $dir = $GLOBALS['text_dir'];
  606. $retval = "<!DOCTYPE HTML>";
  607. $retval .= "<html lang='$lang' dir='$dir'>";
  608. $retval .= '<head>';
  609. return $retval;
  610. }
  611. /**
  612. * Returns the META tags
  613. *
  614. * @return string the META tags
  615. */
  616. private function _getMetaTags()
  617. {
  618. $retval = '<meta charset="utf-8" />';
  619. $retval .= '<meta name="referrer" content="no-referrer" />';
  620. $retval .= '<meta name="robots" content="noindex,nofollow" />';
  621. $retval .= '<meta http-equiv="X-UA-Compatible" content="IE=Edge" />';
  622. $retval .= '<meta name="viewport" content="width=device-width, initial-scale=1.0">';
  623. if (! $GLOBALS['cfg']['AllowThirdPartyFraming']) {
  624. $retval .= '<style id="cfs-style">html{display: none;}</style>';
  625. }
  626. return $retval;
  627. }
  628. /**
  629. * Returns the LINK tags for the favicon and the stylesheets
  630. *
  631. * @return string the LINK tags
  632. */
  633. private function _getLinkTags()
  634. {
  635. $retval = '<link rel="icon" href="favicon.ico" '
  636. . 'type="image/x-icon" />'
  637. . '<link rel="shortcut icon" href="favicon.ico" '
  638. . 'type="image/x-icon" />';
  639. // stylesheets
  640. $basedir = defined('PMA_PATH_TO_BASEDIR') ? PMA_PATH_TO_BASEDIR : '';
  641. $theme_id = $GLOBALS['PMA_Config']->getThemeUniqueValue();
  642. $theme_path = $GLOBALS['pmaThemePath'];
  643. $v = self::getVersionParameter();
  644. if ($this->_isPrintView) {
  645. $retval .= '<link rel="stylesheet" type="text/css" href="'
  646. . $basedir . 'print.css?' . $v . '" />';
  647. } else {
  648. // load jQuery's CSS prior to our theme's CSS, to let the theme
  649. // override jQuery's CSS
  650. $retval .= '<link rel="stylesheet" type="text/css" href="'
  651. . $theme_path . '/jquery/jquery-ui.css" />';
  652. $retval .= '<link rel="stylesheet" type="text/css" href="'
  653. . $basedir . 'js/vendor/codemirror/lib/codemirror.css?' . $v . '" />';
  654. $retval .= '<link rel="stylesheet" type="text/css" href="'
  655. . $basedir . 'js/vendor/codemirror/addon/hint/show-hint.css?' . $v . '" />';
  656. $retval .= '<link rel="stylesheet" type="text/css" href="'
  657. . $basedir . 'js/vendor/codemirror/addon/lint/lint.css?' . $v . '" />';
  658. $retval .= '<link rel="stylesheet" type="text/css" href="'
  659. . $basedir . 'phpmyadmin.css.php?'
  660. . 'nocache=' . $theme_id . $GLOBALS['text_dir']
  661. . (isset($GLOBALS['server']) ? '&amp;server=' . $GLOBALS['server'] : '')
  662. . '" />';
  663. // load Print view's CSS last, so that it overrides all other CSS while
  664. // 'printing'
  665. $retval .= '<link rel="stylesheet" type="text/css" href="'
  666. . $theme_path . '/css/printview.css?' . $v . '" media="print" id="printcss"/>';
  667. }
  668. return $retval;
  669. }
  670. /**
  671. * Returns the TITLE tag
  672. *
  673. * @return string the TITLE tag
  674. */
  675. public function getTitleTag()
  676. {
  677. $retval = "<title>";
  678. $retval .= $this->_getPageTitle();
  679. $retval .= "</title>";
  680. return $retval;
  681. }
  682. /**
  683. * If the page is missing the title, this function
  684. * will set it to something reasonable
  685. *
  686. * @return string
  687. */
  688. private function _getPageTitle()
  689. {
  690. if (strlen($this->_title) == 0) {
  691. if ($GLOBALS['server'] > 0) {
  692. if (strlen($GLOBALS['table'])) {
  693. $temp_title = $GLOBALS['cfg']['TitleTable'];
  694. } elseif (strlen($GLOBALS['db'])) {
  695. $temp_title = $GLOBALS['cfg']['TitleDatabase'];
  696. } elseif (strlen($GLOBALS['cfg']['Server']['host'])) {
  697. $temp_title = $GLOBALS['cfg']['TitleServer'];
  698. } else {
  699. $temp_title = $GLOBALS['cfg']['TitleDefault'];
  700. }
  701. $this->_title = htmlspecialchars(
  702. Util::expandUserString($temp_title)
  703. );
  704. } else {
  705. $this->_title = 'phpMyAdmin';
  706. }
  707. }
  708. return $this->_title;
  709. }
  710. /**
  711. * Returns the close tag to the HEAD
  712. * and the start tag for the BODY
  713. *
  714. * @return string HEAD and BODY tags
  715. */
  716. private function _getBodyStart()
  717. {
  718. $retval = "</head><body";
  719. if (strlen($this->_bodyId)) {
  720. $retval .= " id='" . $this->_bodyId . "'";
  721. }
  722. $retval .= ">";
  723. return $retval;
  724. }
  725. /**
  726. * Returns some warnings to be displayed at the top of the page
  727. *
  728. * @return string The warnings
  729. */
  730. private function _getWarnings()
  731. {
  732. $retval = '';
  733. if ($this->_warningsEnabled) {
  734. $retval .= "<noscript>";
  735. $retval .= Message::error(
  736. __("Javascript must be enabled past this point!")
  737. )->getDisplay();
  738. $retval .= "</noscript>";
  739. }
  740. return $retval;
  741. }
  742. /**
  743. * Add recently used table and reload the navigation.
  744. *
  745. * @param string $db Database name where the table is located.
  746. * @param string $table The table name
  747. *
  748. * @return string
  749. */
  750. private function _addRecentTable($db, $table)
  751. {
  752. $retval = '';
  753. if ($this->_menuEnabled
  754. && strlen($table) > 0
  755. && $GLOBALS['cfg']['NumRecentTables'] > 0
  756. ) {
  757. $tmp_result = RecentFavoriteTable::getInstance('recent')
  758. ->add($db, $table);
  759. if ($tmp_result === true) {
  760. $retval = RecentFavoriteTable::getHtmlUpdateRecentTables();
  761. } else {
  762. $error = $tmp_result;
  763. $retval = $error->getDisplay();
  764. }
  765. }
  766. return $retval;
  767. }
  768. /**
  769. * Returns the phpMyAdmin version to be appended to the url to avoid caching
  770. * between versions
  771. *
  772. * @return string urlenocded pma version as a parameter
  773. */
  774. public static function getVersionParameter()
  775. {
  776. return "v=" . urlencode(PMA_VERSION);
  777. }
  778. }