ThemeManager.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * phpMyAdmin theme manager
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. namespace PhpMyAdmin;
  9. use PhpMyAdmin\Theme;
  10. use PhpMyAdmin\Url;
  11. /**
  12. * phpMyAdmin theme manager
  13. *
  14. * @package PhpMyAdmin
  15. */
  16. class ThemeManager
  17. {
  18. /**
  19. * ThemeManager instance
  20. *
  21. * @access private
  22. * @static
  23. * @var ThemeManager
  24. */
  25. private static $_instance;
  26. /**
  27. * @var string path to theme folder
  28. * @access protected
  29. */
  30. private $_themes_path = './themes/';
  31. /**
  32. * @var array available themes
  33. */
  34. var $themes = array();
  35. /**
  36. * @var string cookie name
  37. */
  38. var $cookie_name = 'pma_theme';
  39. /**
  40. * @var boolean
  41. */
  42. var $per_server = false;
  43. /**
  44. * @var string name of active theme
  45. */
  46. var $active_theme = '';
  47. /**
  48. * @var Theme Theme active theme
  49. */
  50. var $theme = null;
  51. /**
  52. * @var string
  53. */
  54. var $theme_default;
  55. /**
  56. * @const string The name of the fallback theme
  57. */
  58. const FALLBACK_THEME = 'pmahomme';
  59. /**
  60. * Constructor for Theme Manager class
  61. *
  62. * @access public
  63. */
  64. public function __construct()
  65. {
  66. $this->themes = array();
  67. $this->theme_default = self::FALLBACK_THEME;
  68. $this->active_theme = '';
  69. if (! $this->setThemesPath('./themes/')) {
  70. return;
  71. }
  72. $this->setThemePerServer($GLOBALS['cfg']['ThemePerServer']);
  73. $this->loadThemes();
  74. $this->theme = new Theme;
  75. if (! $this->checkTheme($GLOBALS['cfg']['ThemeDefault'])) {
  76. trigger_error(
  77. sprintf(
  78. __('Default theme %s not found!'),
  79. htmlspecialchars($GLOBALS['cfg']['ThemeDefault'])
  80. ),
  81. E_USER_ERROR
  82. );
  83. $GLOBALS['cfg']['ThemeDefault'] = false;
  84. }
  85. $this->theme_default = $GLOBALS['cfg']['ThemeDefault'];
  86. // check if user have a theme cookie
  87. $cookie_theme = $this->getThemeCookie();
  88. if (! $cookie_theme || ! $this->setActiveTheme($cookie_theme)) {
  89. if ($GLOBALS['cfg']['ThemeDefault']) {
  90. // otherwise use default theme
  91. $this->setActiveTheme($this->theme_default);
  92. } else {
  93. // or fallback theme
  94. $this->setActiveTheme(self::FALLBACK_THEME);
  95. }
  96. }
  97. }
  98. /**
  99. * Returns the singleton Response object
  100. *
  101. * @return Response object
  102. */
  103. public static function getInstance()
  104. {
  105. if (empty(self::$_instance)) {
  106. self::$_instance = new ThemeManager();
  107. }
  108. return self::$_instance;
  109. }
  110. /**
  111. * sets path to folder containing the themes
  112. *
  113. * @param string $path path to themes folder
  114. *
  115. * @access public
  116. * @return boolean success
  117. */
  118. public function setThemesPath($path)
  119. {
  120. if (! $this->_checkThemeFolder($path)) {
  121. return false;
  122. }
  123. $this->_themes_path = trim($path);
  124. return true;
  125. }
  126. /**
  127. * sets if there are different themes per server
  128. *
  129. * @param boolean $per_server Whether to enable per server flag
  130. *
  131. * @access public
  132. * @return void
  133. */
  134. public function setThemePerServer($per_server)
  135. {
  136. $this->per_server = (bool) $per_server;
  137. }
  138. /**
  139. * Sets active theme
  140. *
  141. * @param string $theme theme name
  142. *
  143. * @access public
  144. * @return bool true on success
  145. */
  146. public function setActiveTheme($theme = null)
  147. {
  148. if (! $this->checkTheme($theme)) {
  149. trigger_error(
  150. sprintf(
  151. __('Theme %s not found!'),
  152. htmlspecialchars($theme)
  153. ),
  154. E_USER_ERROR
  155. );
  156. return false;
  157. }
  158. $this->active_theme = $theme;
  159. $this->theme = $this->themes[$theme];
  160. // need to set later
  161. //$this->setThemeCookie();
  162. return true;
  163. }
  164. /**
  165. * Returns name for storing theme
  166. *
  167. * @return string cookie name
  168. * @access public
  169. */
  170. public function getThemeCookieName()
  171. {
  172. // Allow different theme per server
  173. if (isset($GLOBALS['server']) && $this->per_server) {
  174. return $this->cookie_name . '-' . $GLOBALS['server'];
  175. }
  176. return $this->cookie_name;
  177. }
  178. /**
  179. * returns name of theme stored in the cookie
  180. *
  181. * @return string theme name from cookie
  182. * @access public
  183. */
  184. public function getThemeCookie()
  185. {
  186. $name = $this->getThemeCookieName();
  187. if (isset($_COOKIE[$name])) {
  188. return $_COOKIE[$name];
  189. }
  190. return false;
  191. }
  192. /**
  193. * save theme in cookie
  194. *
  195. * @return bool true
  196. * @access public
  197. */
  198. public function setThemeCookie()
  199. {
  200. $GLOBALS['PMA_Config']->setCookie(
  201. $this->getThemeCookieName(),
  202. $this->theme->id,
  203. $this->theme_default
  204. );
  205. // force a change of a dummy session variable to avoid problems
  206. // with the caching of phpmyadmin.css.php
  207. $GLOBALS['PMA_Config']->set('theme-update', $this->theme->id);
  208. return true;
  209. }
  210. /**
  211. * Checks whether folder is valid for storing themes
  212. *
  213. * @param string $folder Folder name to test
  214. *
  215. * @return boolean
  216. * @access private
  217. */
  218. private function _checkThemeFolder($folder)
  219. {
  220. if (! is_dir($folder)) {
  221. trigger_error(
  222. sprintf(
  223. __('Theme path not found for theme %s!'),
  224. htmlspecialchars($folder)
  225. ),
  226. E_USER_ERROR
  227. );
  228. return false;
  229. }
  230. return true;
  231. }
  232. /**
  233. * read all themes
  234. *
  235. * @return bool true
  236. * @access public
  237. */
  238. public function loadThemes()
  239. {
  240. $this->themes = array();
  241. if (false === ($handleThemes = opendir($this->_themes_path))) {
  242. trigger_error(
  243. 'phpMyAdmin-ERROR: cannot open themes folder: '
  244. . $this->_themes_path,
  245. E_USER_WARNING
  246. );
  247. return false;
  248. }
  249. // check for themes directory
  250. while (false !== ($PMA_Theme = readdir($handleThemes))) {
  251. // Skip non dirs, . and ..
  252. if ($PMA_Theme == '.'
  253. || $PMA_Theme == '..'
  254. || ! @is_dir($this->_themes_path . $PMA_Theme)
  255. ) {
  256. continue;
  257. }
  258. if (array_key_exists($PMA_Theme, $this->themes)) {
  259. continue;
  260. }
  261. $new_theme = Theme::load(
  262. $this->_themes_path . $PMA_Theme
  263. );
  264. if ($new_theme) {
  265. $new_theme->setId($PMA_Theme);
  266. $this->themes[$PMA_Theme] = $new_theme;
  267. }
  268. } // end get themes
  269. closedir($handleThemes);
  270. ksort($this->themes);
  271. return true;
  272. }
  273. /**
  274. * checks if given theme name is a known theme
  275. *
  276. * @param string $theme name fo theme to check for
  277. *
  278. * @return bool
  279. * @access public
  280. */
  281. public function checkTheme($theme)
  282. {
  283. return array_key_exists($theme, $this->themes);
  284. }
  285. /**
  286. * returns HTML selectbox, with or without form enclosed
  287. *
  288. * @param boolean $form whether enclosed by from tags or not
  289. *
  290. * @return string
  291. * @access public
  292. */
  293. public function getHtmlSelectBox($form = true)
  294. {
  295. $select_box = '';
  296. if ($form) {
  297. $select_box .= '<form name="setTheme" method="post"';
  298. $select_box .= ' action="index.php" class="disableAjax">';
  299. $select_box .= Url::getHiddenInputs();
  300. }
  301. $theme_preview_path= './themes.php';
  302. $theme_preview_href = '<a href="'
  303. . $theme_preview_path . '" target="themes" class="themeselect">';
  304. $select_box .= $theme_preview_href . __('Theme:') . '</a>' . "\n";
  305. $select_box .= '<select name="set_theme" lang="en" dir="ltr"'
  306. . ' class="autosubmit">';
  307. foreach ($this->themes as $each_theme_id => $each_theme) {
  308. $select_box .= '<option value="' . $each_theme_id . '"';
  309. if ($this->active_theme === $each_theme_id) {
  310. $select_box .= ' selected="selected"';
  311. }
  312. $select_box .= '>' . htmlspecialchars($each_theme->getName())
  313. . '</option>';
  314. }
  315. $select_box .= '</select>';
  316. if ($form) {
  317. $select_box .= '</form>';
  318. }
  319. return $select_box;
  320. }
  321. /**
  322. * Renders the previews for all themes
  323. *
  324. * @return string
  325. * @access public
  326. */
  327. public function getPrintPreviews()
  328. {
  329. $retval = '';
  330. foreach ($this->themes as $each_theme) {
  331. $retval .= $each_theme->getPrintPreview();
  332. } // end 'open themes'
  333. return $retval;
  334. }
  335. /**
  336. * returns Theme object for fall back theme
  337. *
  338. * @return Theme fall back theme
  339. * @access public
  340. */
  341. public function getFallBackTheme()
  342. {
  343. if (isset($this->themes[self::FALLBACK_THEME])) {
  344. return $this->themes[self::FALLBACK_THEME];
  345. }
  346. return false;
  347. }
  348. /**
  349. * prints css data
  350. *
  351. * @return bool
  352. * @access public
  353. */
  354. public function printCss()
  355. {
  356. if ($this->theme->loadCss()) {
  357. return true;
  358. }
  359. // if loading css for this theme failed, try default theme css
  360. $fallback_theme = $this->getFallBackTheme();
  361. if ($fallback_theme && $fallback_theme->loadCss()) {
  362. return true;
  363. }
  364. return false;
  365. }
  366. /**
  367. * Theme initialization
  368. *
  369. * @return void
  370. * @access public
  371. */
  372. public static function initializeTheme()
  373. {
  374. $tmanager = self::getInstance();
  375. /**
  376. * the theme object
  377. *
  378. * @global Theme $GLOBALS['PMA_Theme']
  379. */
  380. $GLOBALS['PMA_Theme'] = $tmanager->theme;
  381. // BC
  382. /**
  383. * the theme path
  384. * @global string $GLOBALS['pmaThemePath']
  385. */
  386. $GLOBALS['pmaThemePath'] = $GLOBALS['PMA_Theme']->getPath();
  387. /**
  388. * the theme image path
  389. * @global string $GLOBALS['pmaThemeImage']
  390. */
  391. $GLOBALS['pmaThemeImage'] = $GLOBALS['PMA_Theme']->getImgPath();
  392. /**
  393. * load layout file if exists
  394. */
  395. if (@file_exists($GLOBALS['PMA_Theme']->getLayoutFile())) {
  396. include $GLOBALS['PMA_Theme']->getLayoutFile();
  397. }
  398. }
  399. }