Header.class.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  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. if (! defined('PHPMYADMIN')) {
  9. exit;
  10. }
  11. require_once 'libraries/Scripts.class.php';
  12. require_once 'libraries/RecentFavoriteTable.class.php';
  13. require_once 'libraries/Menu.class.php';
  14. require_once 'libraries/navigation/Navigation.class.php';
  15. require_once 'libraries/url_generating.lib.php';
  16. /**
  17. * Class used to output the HTTP and HTML headers
  18. *
  19. * @package PhpMyAdmin
  20. */
  21. class PMA_Header
  22. {
  23. /**
  24. * PMA_Scripts instance
  25. *
  26. * @access private
  27. * @var PMA_Scripts
  28. */
  29. private $_scripts;
  30. /**
  31. * PMA_Menu instance
  32. *
  33. * @access private
  34. * @var PMA_Menu
  35. */
  36. private $_menu;
  37. /**
  38. * Whether to offer the option of importing user settings
  39. *
  40. * @access private
  41. * @var bool
  42. */
  43. private $_userprefsOfferImport;
  44. /**
  45. * The page title
  46. *
  47. * @access private
  48. * @var string
  49. */
  50. private $_title;
  51. /**
  52. * The value for the id attribute for the body tag
  53. *
  54. * @access private
  55. * @var string
  56. */
  57. private $_bodyId;
  58. /**
  59. * Whether to show the top menu
  60. *
  61. * @access private
  62. * @var bool
  63. */
  64. private $_menuEnabled;
  65. /**
  66. * Whether to show the warnings
  67. *
  68. * @access private
  69. * @var bool
  70. */
  71. private $_warningsEnabled;
  72. /**
  73. * Whether the page is in 'print view' mode
  74. *
  75. * @access private
  76. * @var bool
  77. */
  78. private $_isPrintView;
  79. /**
  80. * Whether we are servicing an ajax request.
  81. * We can't simply use $GLOBALS['is_ajax_request']
  82. * here since it may have not been initialised yet.
  83. *
  84. * @access private
  85. * @var bool
  86. */
  87. private $_isAjax;
  88. /**
  89. * Whether to display anything
  90. *
  91. * @access private
  92. * @var bool
  93. */
  94. private $_isEnabled;
  95. /**
  96. * Whether the HTTP headers (and possibly some HTML)
  97. * have already been sent to the browser
  98. *
  99. * @access private
  100. * @var bool
  101. */
  102. private $_headerIsSent;
  103. /**
  104. * Creates a new class instance
  105. */
  106. public function __construct()
  107. {
  108. $this->_isEnabled = true;
  109. $this->_isAjax = false;
  110. $this->_bodyId = '';
  111. $this->_title = '';
  112. $db = ! empty($GLOBALS['db']) ? $GLOBALS['db'] : '';
  113. $table = ! empty($GLOBALS['table']) ? $GLOBALS['table'] : '';
  114. $this->_menu = new PMA_Menu(
  115. $GLOBALS['server'],
  116. $db,
  117. $table
  118. );
  119. $this->_menuEnabled = true;
  120. $this->_warningsEnabled = true;
  121. $this->_isPrintView = false;
  122. $this->_scripts = new PMA_Scripts();
  123. $this->_addDefaultScripts();
  124. $this->_headerIsSent = false;
  125. // if database storage for user preferences is transient,
  126. // offer to load exported settings from localStorage
  127. // (detection will be done in JavaScript)
  128. $this->_userprefsOfferImport = false;
  129. if ($GLOBALS['PMA_Config']->get('user_preferences') == 'session'
  130. && ! isset($_SESSION['userprefs_autoload'])
  131. ) {
  132. $this->_userprefsOfferImport = true;
  133. }
  134. }
  135. /**
  136. * Loads common scripts
  137. *
  138. * @return void
  139. */
  140. private function _addDefaultScripts()
  141. {
  142. $this->_scripts->addFile('jquery/jquery-1.8.3.min.js');
  143. $this->_scripts->addFile('ajax.js');
  144. $this->_scripts->addFile('keyhandler.js');
  145. $this->_scripts->addFile('jquery/jquery-ui-1.9.2.custom.min.js');
  146. $this->_scripts->addFile('jquery/jquery.sprintf.js');
  147. $this->_scripts->addFile('jquery/jquery.cookie.js');
  148. $this->_scripts->addFile('jquery/jquery.mousewheel.js');
  149. $this->_scripts->addFile('jquery/jquery.event.drag-2.2.js');
  150. $this->_scripts->addFile('jquery/jquery-ui-timepicker-addon.js');
  151. $this->_scripts->addFile('jquery/jquery.ba-hashchange-1.3.js');
  152. $this->_scripts->addFile('jquery/jquery.debounce-1.0.5.js');
  153. $this->_scripts->addFile('jquery/jquery.menuResizer-1.0.js');
  154. // Cross-framing protection
  155. if ($GLOBALS['cfg']['AllowThirdPartyFraming'] === false) {
  156. $this->_scripts->addFile('cross_framing_protection.js');
  157. }
  158. $this->_scripts->addFile('rte.js');
  159. if ($GLOBALS['cfg']['SendErrorReports'] !== 'never') {
  160. $this->_scripts->addFile('tracekit/tracekit.js');
  161. $this->_scripts->addFile('error_report.js');
  162. }
  163. // Here would not be a good place to add CodeMirror because
  164. // the user preferences have not been merged at this point
  165. // Localised strings
  166. $params = array('lang' => $GLOBALS['lang']);
  167. if (isset($GLOBALS['db'])) {
  168. $params['db'] = $GLOBALS['db'];
  169. }
  170. $this->_scripts->addFile('messages.php' . PMA_URL_getCommon($params));
  171. // Append the theme id to this url to invalidate
  172. // the cache on a theme change. Though this might be
  173. // unavailable for fatal errors.
  174. if (isset($_SESSION['PMA_Theme'])) {
  175. $theme_id = urlencode($_SESSION['PMA_Theme']->getId());
  176. } else {
  177. $theme_id = 'default';
  178. }
  179. $this->_scripts->addFile(
  180. 'get_image.js.php?theme=' . $theme_id
  181. );
  182. $this->_scripts->addFile('doclinks.js');
  183. $this->_scripts->addFile('functions.js');
  184. $this->_scripts->addFile('navigation.js');
  185. $this->_scripts->addFile('indexes.js');
  186. $this->_scripts->addFile('common.js');
  187. $this->_scripts->addCode($this->getJsParamsCode());
  188. }
  189. /**
  190. * Returns, as an array, a list of parameters
  191. * used on the client side
  192. *
  193. * @return array
  194. */
  195. public function getJsParams()
  196. {
  197. $db = ! empty($GLOBALS['db']) ? $GLOBALS['db'] : '';
  198. $table = ! empty($GLOBALS['table']) ? $GLOBALS['table'] : '';
  199. return array(
  200. 'common_query' => PMA_URL_getCommon('', '', '&'),
  201. 'opendb_url' => $GLOBALS['cfg']['DefaultTabDatabase'],
  202. 'safari_browser' => PMA_USR_BROWSER_AGENT == 'SAFARI' ? 1 : 0,
  203. 'querywindow_height' => $GLOBALS['cfg']['QueryWindowHeight'],
  204. 'querywindow_width' => $GLOBALS['cfg']['QueryWindowWidth'],
  205. 'collation_connection' => $GLOBALS['collation_connection'],
  206. 'lang' => $GLOBALS['lang'],
  207. 'server' => $GLOBALS['server'],
  208. 'table' => $table,
  209. 'db' => $db,
  210. 'token' => $_SESSION[' PMA_token '],
  211. 'text_dir' => $GLOBALS['text_dir'],
  212. 'pma_absolute_uri' => $GLOBALS['cfg']['PmaAbsoluteUri'],
  213. 'pma_text_default_tab' => PMA_Util::getTitleForTarget(
  214. $GLOBALS['cfg']['DefaultTabTable']
  215. ),
  216. 'pma_text_left_default_tab' => PMA_Util::getTitleForTarget(
  217. $GLOBALS['cfg']['NavigationTreeDefaultTabTable']
  218. ),
  219. 'confirm' => $GLOBALS['cfg']['Confirm']
  220. );
  221. }
  222. /**
  223. * Returns, as a string, a list of parameters
  224. * used on the client side
  225. *
  226. * @return string
  227. */
  228. public function getJsParamsCode()
  229. {
  230. $params = $this->getJsParams();
  231. foreach ($params as $key => $value) {
  232. $params[$key] = $key . ':"' . PMA_escapeJsString($value) . '"';
  233. }
  234. return 'PMA_commonParams.setAll({' . implode(',', $params) . '});';
  235. }
  236. /**
  237. * Disables the rendering of the header
  238. *
  239. * @return void
  240. */
  241. public function disable()
  242. {
  243. $this->_isEnabled = false;
  244. }
  245. /**
  246. * Set the ajax flag to indicate whether
  247. * we are sevicing an ajax request
  248. *
  249. * @param bool $isAjax Whether we are sevicing an ajax request
  250. *
  251. * @return void
  252. */
  253. public function setAjax($isAjax)
  254. {
  255. $this->_isAjax = ($isAjax == true);
  256. }
  257. /**
  258. * Returns the PMA_Scripts object
  259. *
  260. * @return PMA_Scripts object
  261. */
  262. public function getScripts()
  263. {
  264. return $this->_scripts;
  265. }
  266. /**
  267. * Returns the PMA_Menu object
  268. *
  269. * @return PMA_Menu object
  270. */
  271. public function getMenu()
  272. {
  273. return $this->_menu;
  274. }
  275. /**
  276. * Setter for the ID attribute in the BODY tag
  277. *
  278. * @param string $id Value for the ID attribute
  279. *
  280. * @return void
  281. */
  282. public function setBodyId($id)
  283. {
  284. $this->_bodyId = htmlspecialchars($id);
  285. }
  286. /**
  287. * Setter for the title of the page
  288. *
  289. * @param string $title New title
  290. *
  291. * @return void
  292. */
  293. public function setTitle($title)
  294. {
  295. $this->_title = htmlspecialchars($title);
  296. }
  297. /**
  298. * Disables the display of the top menu
  299. *
  300. * @return void
  301. */
  302. public function disableMenu()
  303. {
  304. $this->_menuEnabled = false;
  305. }
  306. /**
  307. * Disables the display of the top menu
  308. *
  309. * @return void
  310. */
  311. public function disableWarnings()
  312. {
  313. $this->_warningsEnabled = false;
  314. }
  315. /**
  316. * Turns on 'print view' mode
  317. *
  318. * @return void
  319. */
  320. public function enablePrintView()
  321. {
  322. $this->disableMenu();
  323. $this->setTitle(__('Print view') . ' - phpMyAdmin ' . PMA_VERSION);
  324. $this->_isPrintView = true;
  325. }
  326. /**
  327. * Generates the header
  328. *
  329. * @return string The header
  330. */
  331. public function getDisplay()
  332. {
  333. $retval = '';
  334. if (! $this->_headerIsSent) {
  335. if (! $this->_isAjax && $this->_isEnabled) {
  336. $this->sendHttpHeaders();
  337. $retval .= $this->_getHtmlStart();
  338. $retval .= $this->_getMetaTags();
  339. $retval .= $this->_getLinkTags();
  340. $retval .= $this->getTitleTag();
  341. // The user preferences have been merged at this point
  342. // so we can conditionally add CodeMirror
  343. if ($GLOBALS['cfg']['CodemirrorEnable']) {
  344. $this->_scripts->addFile('codemirror/lib/codemirror.js');
  345. $this->_scripts->addFile('codemirror/mode/sql/sql.js');
  346. $this->_scripts->addFile('codemirror/addon/runmode/runmode.js');
  347. }
  348. if ($this->_userprefsOfferImport) {
  349. $this->_scripts->addFile('config.js');
  350. }
  351. $retval .= $this->_scripts->getDisplay();
  352. $retval .= $this->_getBodyStart();
  353. if ($this->_menuEnabled && $GLOBALS['server'] > 0) {
  354. $nav = new PMA_Navigation();
  355. $retval .= $nav->getDisplay();
  356. }
  357. // Include possible custom headers
  358. if (file_exists(CUSTOM_HEADER_FILE)) {
  359. $retval .= '<div id="pma_header">';
  360. ob_start();
  361. include CUSTOM_HEADER_FILE;
  362. $retval .= ob_get_contents();
  363. ob_end_clean();
  364. $retval .= '</div>';
  365. }
  366. // offer to load user preferences from localStorage
  367. if ($this->_userprefsOfferImport) {
  368. include_once './libraries/user_preferences.lib.php';
  369. $retval .= PMA_userprefsAutoloadGetHeader();
  370. }
  371. // pass configuration for hint tooltip display
  372. // (to be used by PMA_tooltip() in js/functions.js)
  373. if (! $GLOBALS['cfg']['ShowHint']) {
  374. $retval .= '<span id="no_hint" class="hide"></span>';
  375. }
  376. $retval .= $this->_getWarnings();
  377. if ($this->_menuEnabled && $GLOBALS['server'] > 0) {
  378. $retval .= $this->_menu->getDisplay();
  379. $retval .= sprintf(
  380. '<a id="goto_pagetop" href="#" title="%s">%s</a>',
  381. __('Click on the bar to scroll to top of page'),
  382. PMA_Util::getImage('s_top.png')
  383. );
  384. }
  385. $retval .= '<div id="page_content">';
  386. $retval .= $this->getMessage();
  387. }
  388. if ($this->_isEnabled && empty($_REQUEST['recent_table'])) {
  389. $retval .= $this->_addRecentTable(
  390. $GLOBALS['db'],
  391. $GLOBALS['table']
  392. );
  393. }
  394. }
  395. return $retval;
  396. }
  397. /**
  398. * Returns the message to be displayed at the top of
  399. * the page, including the executed SQL query, if any.
  400. *
  401. * @return string
  402. */
  403. public function getMessage()
  404. {
  405. $retval = '';
  406. $message = '';
  407. if (! empty($GLOBALS['message'])) {
  408. $message = $GLOBALS['message'];
  409. unset($GLOBALS['message']);
  410. } else if (! empty($_REQUEST['message'])) {
  411. $message = $_REQUEST['message'];
  412. }
  413. if (! empty($message)) {
  414. if (isset($GLOBALS['buffer_message'])) {
  415. $buffer_message = $GLOBALS['buffer_message'];
  416. }
  417. $retval .= PMA_Util::getMessage($message);
  418. if (isset($buffer_message)) {
  419. $GLOBALS['buffer_message'] = $buffer_message;
  420. }
  421. }
  422. return $retval;
  423. }
  424. /**
  425. * Sends out the HTTP headers
  426. *
  427. * @return void
  428. */
  429. public function sendHttpHeaders()
  430. {
  431. $https = $GLOBALS['PMA_Config']->isHttps();
  432. $mapTilesUrls = ' *.tile.openstreetmap.org *.tile.opencyclemap.org';
  433. /**
  434. * Sends http headers
  435. */
  436. $GLOBALS['now'] = gmdate('D, d M Y H:i:s') . ' GMT';
  437. if (! defined('TESTSUITE')) {
  438. $use_captcha = (
  439. !empty($GLOBALS['cfg']['CaptchaLoginPrivateKey'])
  440. && !empty($GLOBALS['cfg']['CaptchaLoginPublicKey'])
  441. );
  442. /* Prevent against ClickJacking by disabling framing */
  443. if (! $GLOBALS['cfg']['AllowThirdPartyFraming']) {
  444. header(
  445. 'X-Frame-Options: DENY'
  446. );
  447. }
  448. header(
  449. "Content-Security-Policy: default-src 'self' "
  450. . ($use_captcha ? 'https://www.google.com ' : ' ')
  451. . $GLOBALS['cfg']['CSPAllow'] . ';'
  452. . "script-src 'self' 'unsafe-inline' 'unsafe-eval' "
  453. . ($use_captcha ? 'https://www.google.com ' : ' ')
  454. . $GLOBALS['cfg']['CSPAllow'] . ';'
  455. . ";"
  456. . "style-src 'self' 'unsafe-inline' "
  457. . ($use_captcha ? 'https://www.google.com ' : ' ')
  458. . $GLOBALS['cfg']['CSPAllow']
  459. . ";"
  460. . "img-src 'self' data: "
  461. . $GLOBALS['cfg']['CSPAllow']
  462. . ($https ? "" : $mapTilesUrls)
  463. // for reCAPTCHA
  464. . ($use_captcha ? ' https://www.google.com' : ' ')
  465. . ";"
  466. );
  467. header(
  468. "X-Content-Security-Policy: default-src 'self' "
  469. . ($use_captcha ? 'https://www.google.com ' : ' ')
  470. . $GLOBALS['cfg']['CSPAllow'] . ';'
  471. . "options inline-script eval-script;"
  472. . "img-src 'self' data: "
  473. . $GLOBALS['cfg']['CSPAllow']
  474. . ($https ? "" : $mapTilesUrls)
  475. // for reCAPTCHA
  476. . ($use_captcha ? ' https://www.google.com' : ' ')
  477. . ";"
  478. );
  479. if (PMA_USR_BROWSER_AGENT == 'SAFARI'
  480. && PMA_USR_BROWSER_VER < '6.0.0'
  481. ) {
  482. header(
  483. "X-WebKit-CSP: allow 'self' "
  484. . ($use_captcha ? 'https://www.google.com ' : ' ')
  485. . $GLOBALS['cfg']['CSPAllow'] . ';'
  486. . "options inline-script eval-script;"
  487. . "img-src 'self' data: "
  488. . $GLOBALS['cfg']['CSPAllow']
  489. . ($https ? "" : $mapTilesUrls)
  490. // for reCAPTCHA
  491. . ($use_captcha ? ' https://www.google.com' : ' ')
  492. . ";"
  493. );
  494. } else {
  495. header(
  496. "X-WebKit-CSP: default-src 'self' "
  497. . ($use_captcha ? 'https://www.google.com ' : ' ')
  498. . $GLOBALS['cfg']['CSPAllow'] . ';'
  499. . "script-src 'self' "
  500. . ($use_captcha ? 'https://www.google.com ' : ' ')
  501. . $GLOBALS['cfg']['CSPAllow']
  502. . " 'unsafe-inline' 'unsafe-eval';"
  503. . "style-src 'self' 'unsafe-inline' "
  504. . ($use_captcha ? 'https://www.google.com ' : ' ')
  505. . ';'
  506. . "img-src 'self' data: "
  507. . $GLOBALS['cfg']['CSPAllow']
  508. . ($https ? "" : $mapTilesUrls)
  509. // for reCAPTCHA
  510. . ($use_captcha ? ' https://www.google.com' : ' ')
  511. . ";"
  512. );
  513. }
  514. }
  515. PMA_noCacheHeader();
  516. if (! defined('IS_TRANSFORMATION_WRAPPER') && ! defined('TESTSUITE')) {
  517. // Define the charset to be used
  518. header('Content-Type: text/html; charset=utf-8');
  519. }
  520. $this->_headerIsSent = true;
  521. }
  522. /**
  523. * Returns the DOCTYPE and the start HTML tag
  524. *
  525. * @return string DOCTYPE and HTML tags
  526. */
  527. private function _getHtmlStart()
  528. {
  529. $lang = $GLOBALS['available_languages'][$GLOBALS['lang']][1];
  530. $dir = $GLOBALS['text_dir'];
  531. $retval = "<!DOCTYPE HTML>";
  532. $retval .= "<html lang='$lang' dir='$dir' class='";
  533. $retval .= strtolower(PMA_USR_BROWSER_AGENT) . " ";
  534. $retval .= strtolower(PMA_USR_BROWSER_AGENT)
  535. . intval(PMA_USR_BROWSER_VER) . "'>";
  536. return $retval;
  537. }
  538. /**
  539. * Returns the META tags
  540. *
  541. * @return string the META tags
  542. */
  543. private function _getMetaTags()
  544. {
  545. $retval = '<meta charset="utf-8" />';
  546. $retval .= '<meta name="robots" content="noindex,nofollow" />';
  547. $retval .= '<meta http-equiv="X-UA-Compatible" content="IE=Edge">';
  548. if (! $GLOBALS['cfg']['AllowThirdPartyFraming']) {
  549. $retval .= '<style id="cfs-style">html{display: none;}</style>';
  550. }
  551. return $retval;
  552. }
  553. /**
  554. * Returns the LINK tags for the favicon and the stylesheets
  555. *
  556. * @return string the LINK tags
  557. */
  558. private function _getLinkTags()
  559. {
  560. $retval = '<link rel="icon" href="favicon.ico" '
  561. . 'type="image/x-icon" />'
  562. . '<link rel="shortcut icon" href="favicon.ico" '
  563. . 'type="image/x-icon" />';
  564. // stylesheets
  565. $basedir = defined('PMA_PATH_TO_BASEDIR') ? PMA_PATH_TO_BASEDIR : '';
  566. $common_url = PMA_URL_getCommon(array('server' => $GLOBALS['server']));
  567. $theme_id = $GLOBALS['PMA_Config']->getThemeUniqueValue();
  568. $theme_path = $GLOBALS['pmaThemePath'];
  569. if ($this->_isPrintView) {
  570. $retval .= '<link rel="stylesheet" type="text/css" href="'
  571. . $basedir . 'print.css" />';
  572. } else {
  573. $retval .= '<link rel="stylesheet" type="text/css" href="'
  574. . $basedir . 'phpmyadmin.css.php'
  575. . $common_url . '&amp;nocache='
  576. . $theme_id . $GLOBALS['text_dir'] . '" />';
  577. $retval .= '<link rel="stylesheet" type="text/css" href="'
  578. . $theme_path . '/jquery/jquery-ui-1.9.2.custom.css" />';
  579. }
  580. return $retval;
  581. }
  582. /**
  583. * Returns the TITLE tag
  584. *
  585. * @return string the TITLE tag
  586. */
  587. public function getTitleTag()
  588. {
  589. $retval = "<title>";
  590. $retval .= $this->_getPageTitle();
  591. $retval .= "</title>";
  592. return $retval;
  593. }
  594. /**
  595. * If the page is missing the title, this function
  596. * will set it to something reasonable
  597. *
  598. * @return string
  599. */
  600. private function _getPageTitle()
  601. {
  602. if (empty($this->_title)) {
  603. if ($GLOBALS['server'] > 0) {
  604. if (! empty($GLOBALS['table'])) {
  605. $temp_title = $GLOBALS['cfg']['TitleTable'];
  606. } else if (! empty($GLOBALS['db'])) {
  607. $temp_title = $GLOBALS['cfg']['TitleDatabase'];
  608. } elseif (! empty($GLOBALS['cfg']['Server']['host'])) {
  609. $temp_title = $GLOBALS['cfg']['TitleServer'];
  610. } else {
  611. $temp_title = $GLOBALS['cfg']['TitleDefault'];
  612. }
  613. $this->_title = htmlspecialchars(
  614. PMA_Util::expandUserString($temp_title)
  615. );
  616. } else {
  617. $this->_title = 'phpMyAdmin';
  618. }
  619. }
  620. return $this->_title;
  621. }
  622. /**
  623. * Returns the close tag to the HEAD
  624. * and the start tag for the BODY
  625. *
  626. * @return string HEAD and BODY tags
  627. */
  628. private function _getBodyStart()
  629. {
  630. $retval = "</head><body";
  631. if (! empty($this->_bodyId)) {
  632. $retval .= " id='" . $this->_bodyId . "'";
  633. }
  634. $retval .= ">";
  635. return $retval;
  636. }
  637. /**
  638. * Returns some warnings to be displayed at the top of the page
  639. *
  640. * @return string The warnings
  641. */
  642. private function _getWarnings()
  643. {
  644. $retval = '';
  645. if ($this->_warningsEnabled) {
  646. $retval .= "<noscript>";
  647. $retval .= PMA_message::error(
  648. __("Javascript must be enabled past this point!")
  649. )->getDisplay();
  650. $retval .= "</noscript>";
  651. }
  652. return $retval;
  653. }
  654. /**
  655. * Add recently used table and reload the navigation.
  656. *
  657. * @param string $db Database name where the table is located.
  658. * @param string $table The table name
  659. *
  660. * @return string
  661. */
  662. private function _addRecentTable($db, $table)
  663. {
  664. $retval = '';
  665. if ($this->_menuEnabled
  666. && strlen($table)
  667. && $GLOBALS['cfg']['NumRecentTables'] > 0
  668. ) {
  669. $tmp_result = PMA_RecentFavoriteTable::getInstance('recent')->add($db, $table);
  670. if ($tmp_result === true) {
  671. $params = array('ajax_request' => true, 'recent_table' => true);
  672. $url = 'index.php' . PMA_URL_getCommon($params);
  673. $retval = '<a class="hide" id="update_recent_tables"';
  674. $retval .= ' href="' . $url . '"></a>';
  675. } else {
  676. $error = $tmp_result;
  677. $retval = $error->getDisplay();
  678. }
  679. }
  680. return $retval;
  681. }
  682. }
  683. ?>