PageRenderTime 44ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/classes/ThemeManager.php

http://github.com/phpmyadmin/phpmyadmin
PHP | 307 lines | 170 code | 52 blank | 85 comment | 18 complexity | 490e13bf1048f43a45fa5bd92e42bf10 MD5 | raw file
Possible License(s): GPL-2.0, MIT, LGPL-3.0
  1. <?php
  2. declare(strict_types=1);
  3. namespace PhpMyAdmin;
  4. use function __;
  5. use function array_key_exists;
  6. use function closedir;
  7. use function htmlspecialchars;
  8. use function is_dir;
  9. use function ksort;
  10. use function opendir;
  11. use function readdir;
  12. use function sprintf;
  13. use function trigger_error;
  14. use const DIRECTORY_SEPARATOR;
  15. use const E_USER_ERROR;
  16. use const E_USER_WARNING;
  17. /**
  18. * phpMyAdmin theme manager
  19. */
  20. class ThemeManager
  21. {
  22. /**
  23. * ThemeManager instance
  24. *
  25. * @access private
  26. * @static
  27. * @var ThemeManager
  28. */
  29. private static $instance;
  30. /**
  31. * @var string file-system path to the theme folder
  32. * @access protected
  33. */
  34. private $themesPath;
  35. /** @var string path to theme folder as an URL */
  36. private $themesPathUrl;
  37. /** @var array<string,Theme> available themes */
  38. public $themes = [];
  39. /** @var string cookie name */
  40. public $cookieName = 'pma_theme';
  41. /** @var bool */
  42. public $perServer = false;
  43. /** @var string name of active theme */
  44. public $activeTheme = '';
  45. /** @var Theme Theme active theme */
  46. public $theme = null;
  47. /** @var string */
  48. public $themeDefault;
  49. /**
  50. * @const string The name of the fallback theme
  51. */
  52. public const FALLBACK_THEME = 'pmahomme';
  53. public function __construct()
  54. {
  55. $this->themes = [];
  56. $this->themeDefault = self::FALLBACK_THEME;
  57. $this->activeTheme = '';
  58. $this->themesPath = self::getThemesFsDir();
  59. $this->themesPathUrl = self::getThemesDir();
  60. $this->setThemePerServer($GLOBALS['cfg']['ThemePerServer']);
  61. $this->loadThemes();
  62. $this->theme = new Theme();
  63. $configThemeExists = true;
  64. if (! $this->checkTheme($GLOBALS['cfg']['ThemeDefault'])) {
  65. trigger_error(
  66. sprintf(
  67. __('Default theme %s not found!'),
  68. htmlspecialchars($GLOBALS['cfg']['ThemeDefault'])
  69. ),
  70. E_USER_ERROR
  71. );
  72. $configThemeExists = false;
  73. } else {
  74. $this->themeDefault = $GLOBALS['cfg']['ThemeDefault'];
  75. }
  76. // check if user have a theme cookie
  77. $cookieTheme = $this->getThemeCookie();
  78. if ($cookieTheme && $this->setActiveTheme($cookieTheme)) {
  79. return;
  80. }
  81. if ($configThemeExists) {
  82. // otherwise use default theme
  83. $this->setActiveTheme($this->themeDefault);
  84. } else {
  85. // or fallback theme
  86. $this->setActiveTheme(self::FALLBACK_THEME);
  87. }
  88. }
  89. /**
  90. * Returns the singleton ThemeManager object
  91. *
  92. * @return ThemeManager The instance
  93. */
  94. public static function getInstance(): ThemeManager
  95. {
  96. if (empty(self::$instance)) {
  97. self::$instance = new ThemeManager();
  98. }
  99. return self::$instance;
  100. }
  101. /**
  102. * sets if there are different themes per server
  103. *
  104. * @param bool $perServer Whether to enable per server flag
  105. *
  106. * @access public
  107. */
  108. public function setThemePerServer($perServer): void
  109. {
  110. $this->perServer = (bool) $perServer;
  111. }
  112. /**
  113. * Sets active theme
  114. *
  115. * @param string|null $theme theme name
  116. *
  117. * @access public
  118. */
  119. public function setActiveTheme(?string $theme): bool
  120. {
  121. if (! $this->checkTheme($theme)) {
  122. trigger_error(
  123. sprintf(
  124. __('Theme %s not found!'),
  125. htmlspecialchars((string) $theme)
  126. ),
  127. E_USER_ERROR
  128. );
  129. return false;
  130. }
  131. $this->activeTheme = $theme;
  132. $this->theme = $this->themes[$theme];
  133. // need to set later
  134. //$this->setThemeCookie();
  135. return true;
  136. }
  137. /**
  138. * Returns name for storing theme
  139. *
  140. * @return string cookie name
  141. *
  142. * @access public
  143. */
  144. public function getThemeCookieName()
  145. {
  146. // Allow different theme per server
  147. if (isset($GLOBALS['server']) && $this->perServer) {
  148. return $this->cookieName . '-' . $GLOBALS['server'];
  149. }
  150. return $this->cookieName;
  151. }
  152. /**
  153. * returns name of theme stored in the cookie
  154. *
  155. * @return string|false theme name from cookie or false
  156. *
  157. * @access public
  158. */
  159. public function getThemeCookie()
  160. {
  161. global $config;
  162. $name = $this->getThemeCookieName();
  163. if ($config->issetCookie($name)) {
  164. return $config->getCookie($name);
  165. }
  166. return false;
  167. }
  168. /**
  169. * save theme in cookie
  170. *
  171. * @return true
  172. *
  173. * @access public
  174. */
  175. public function setThemeCookie(): bool
  176. {
  177. $themeId = $this->theme !== null ? (string) $this->theme->id : '';
  178. $GLOBALS['config']->setCookie(
  179. $this->getThemeCookieName(),
  180. $themeId,
  181. $this->themeDefault
  182. );
  183. // force a change of a dummy session variable to avoid problems
  184. // with the caching of phpmyadmin.css.php
  185. $GLOBALS['config']->set('theme-update', $themeId);
  186. return true;
  187. }
  188. public function loadThemes(): void
  189. {
  190. $this->themes = [];
  191. $dirHandle = opendir($this->themesPath);
  192. if ($dirHandle === false) {
  193. trigger_error('Error: cannot open themes folder: ./themes', E_USER_WARNING);
  194. return;
  195. }
  196. while (($dir = readdir($dirHandle)) !== false) {
  197. if ($dir === '.' || $dir === '..' || ! @is_dir($this->themesPath . $dir)) {
  198. continue;
  199. }
  200. if (array_key_exists($dir, $this->themes)) {
  201. continue;
  202. }
  203. $newTheme = Theme::load($this->themesPathUrl . $dir, $this->themesPath . $dir . DIRECTORY_SEPARATOR, $dir);
  204. if (! $newTheme instanceof Theme) {
  205. continue;
  206. }
  207. $this->themes[$dir] = $newTheme;
  208. }
  209. closedir($dirHandle);
  210. ksort($this->themes);
  211. }
  212. /**
  213. * checks if given theme name is a known theme
  214. *
  215. * @param string|null $theme name fo theme to check for
  216. *
  217. * @access public
  218. */
  219. public function checkTheme(?string $theme): bool
  220. {
  221. return array_key_exists($theme ?? '', $this->themes);
  222. }
  223. public function getThemesArray(): array
  224. {
  225. $themes = [];
  226. foreach ($this->themes as $theme) {
  227. $themes[] = [
  228. 'id' => $theme->getId(),
  229. 'name' => $theme->getName(),
  230. 'version' => $theme->getVersion(),
  231. 'is_active' => $theme->getId() === $this->activeTheme,
  232. ];
  233. }
  234. return $themes;
  235. }
  236. public static function initializeTheme(): ?Theme
  237. {
  238. $themeManager = self::getInstance();
  239. return $themeManager->theme;
  240. }
  241. /**
  242. * Return the themes directory with a trailing slash
  243. */
  244. public static function getThemesFsDir(): string
  245. {
  246. return ROOT_PATH . 'themes' . DIRECTORY_SEPARATOR;
  247. }
  248. /**
  249. * Return the themes directory with a trailing slash as a relative public path
  250. */
  251. public static function getThemesDir(): string
  252. {
  253. return './themes/';// This is an URL
  254. }
  255. }