ThemeManager.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  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. /** @var Config $PMA_Config */
  187. global $PMA_Config;
  188. $name = $this->getThemeCookieName();
  189. if ($PMA_Config->issetCookie($name)) {
  190. return $PMA_Config->getCookie($name);
  191. }
  192. return false;
  193. }
  194. /**
  195. * save theme in cookie
  196. *
  197. * @return bool true
  198. * @access public
  199. */
  200. public function setThemeCookie()
  201. {
  202. $GLOBALS['PMA_Config']->setCookie(
  203. $this->getThemeCookieName(),
  204. $this->theme->id,
  205. $this->theme_default
  206. );
  207. // force a change of a dummy session variable to avoid problems
  208. // with the caching of phpmyadmin.css.php
  209. $GLOBALS['PMA_Config']->set('theme-update', $this->theme->id);
  210. return true;
  211. }
  212. /**
  213. * Checks whether folder is valid for storing themes
  214. *
  215. * @param string $folder Folder name to test
  216. *
  217. * @return boolean
  218. * @access private
  219. */
  220. private function _checkThemeFolder($folder)
  221. {
  222. if (! is_dir($folder)) {
  223. trigger_error(
  224. sprintf(
  225. __('Theme path not found for theme %s!'),
  226. htmlspecialchars($folder)
  227. ),
  228. E_USER_ERROR
  229. );
  230. return false;
  231. }
  232. return true;
  233. }
  234. /**
  235. * read all themes
  236. *
  237. * @return bool true
  238. * @access public
  239. */
  240. public function loadThemes()
  241. {
  242. $this->themes = array();
  243. if (false === ($handleThemes = opendir($this->_themes_path))) {
  244. trigger_error(
  245. 'phpMyAdmin-ERROR: cannot open themes folder: '
  246. . $this->_themes_path,
  247. E_USER_WARNING
  248. );
  249. return false;
  250. }
  251. // check for themes directory
  252. while (false !== ($PMA_Theme = readdir($handleThemes))) {
  253. // Skip non dirs, . and ..
  254. if ($PMA_Theme == '.'
  255. || $PMA_Theme == '..'
  256. || ! @is_dir($this->_themes_path . $PMA_Theme)
  257. ) {
  258. continue;
  259. }
  260. if (array_key_exists($PMA_Theme, $this->themes)) {
  261. continue;
  262. }
  263. $new_theme = Theme::load(
  264. $this->_themes_path . $PMA_Theme
  265. );
  266. if ($new_theme) {
  267. $new_theme->setId($PMA_Theme);
  268. $this->themes[$PMA_Theme] = $new_theme;
  269. }
  270. } // end get themes
  271. closedir($handleThemes);
  272. ksort($this->themes);
  273. return true;
  274. }
  275. /**
  276. * checks if given theme name is a known theme
  277. *
  278. * @param string $theme name fo theme to check for
  279. *
  280. * @return bool
  281. * @access public
  282. */
  283. public function checkTheme($theme)
  284. {
  285. return array_key_exists($theme, $this->themes);
  286. }
  287. /**
  288. * returns HTML selectbox, with or without form enclosed
  289. *
  290. * @param boolean $form whether enclosed by from tags or not
  291. *
  292. * @return string
  293. * @access public
  294. */
  295. public function getHtmlSelectBox($form = true)
  296. {
  297. $select_box = '';
  298. if ($form) {
  299. $select_box .= '<form name="setTheme" method="post"';
  300. $select_box .= ' action="index.php" class="disableAjax">';
  301. $select_box .= Url::getHiddenInputs();
  302. }
  303. $theme_preview_path= './themes.php';
  304. $theme_preview_href = '<a href="'
  305. . $theme_preview_path . '" target="themes" class="themeselect">';
  306. $select_box .= $theme_preview_href . __('Theme:') . '</a>' . "\n";
  307. $select_box .= '<select name="set_theme" lang="en" dir="ltr"'
  308. . ' class="autosubmit">';
  309. foreach ($this->themes as $each_theme_id => $each_theme) {
  310. $select_box .= '<option value="' . $each_theme_id . '"';
  311. if ($this->active_theme === $each_theme_id) {
  312. $select_box .= ' selected="selected"';
  313. }
  314. $select_box .= '>' . htmlspecialchars($each_theme->getName())
  315. . '</option>';
  316. }
  317. $select_box .= '</select>';
  318. if ($form) {
  319. $select_box .= '</form>';
  320. }
  321. return $select_box;
  322. }
  323. /**
  324. * Renders the previews for all themes
  325. *
  326. * @return string
  327. * @access public
  328. */
  329. public function getPrintPreviews()
  330. {
  331. $retval = '';
  332. foreach ($this->themes as $each_theme) {
  333. $retval .= $each_theme->getPrintPreview();
  334. } // end 'open themes'
  335. return $retval;
  336. }
  337. /**
  338. * returns Theme object for fall back theme
  339. *
  340. * @return Theme fall back theme
  341. * @access public
  342. */
  343. public function getFallBackTheme()
  344. {
  345. if (isset($this->themes[self::FALLBACK_THEME])) {
  346. return $this->themes[self::FALLBACK_THEME];
  347. }
  348. return false;
  349. }
  350. /**
  351. * prints css data
  352. *
  353. * @return bool
  354. * @access public
  355. */
  356. public function printCss()
  357. {
  358. if ($this->theme->loadCss()) {
  359. return true;
  360. }
  361. // if loading css for this theme failed, try default theme css
  362. $fallback_theme = $this->getFallBackTheme();
  363. if ($fallback_theme && $fallback_theme->loadCss()) {
  364. return true;
  365. }
  366. return false;
  367. }
  368. /**
  369. * Theme initialization
  370. *
  371. * @return void
  372. * @access public
  373. */
  374. public static function initializeTheme()
  375. {
  376. $tmanager = self::getInstance();
  377. /**
  378. * the theme object
  379. *
  380. * @global Theme $GLOBALS['PMA_Theme']
  381. */
  382. $GLOBALS['PMA_Theme'] = $tmanager->theme;
  383. // BC
  384. /**
  385. * the theme path
  386. * @global string $GLOBALS['pmaThemePath']
  387. */
  388. $GLOBALS['pmaThemePath'] = $GLOBALS['PMA_Theme']->getPath();
  389. /**
  390. * the theme image path
  391. * @global string $GLOBALS['pmaThemeImage']
  392. */
  393. $GLOBALS['pmaThemeImage'] = $GLOBALS['PMA_Theme']->getImgPath();
  394. /**
  395. * load layout file if exists
  396. */
  397. if (@file_exists($GLOBALS['PMA_Theme']->getLayoutFile())) {
  398. include $GLOBALS['PMA_Theme']->getLayoutFile();
  399. }
  400. }
  401. }