PageRenderTime 65ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/sources/subs/Themes.subs.php

https://github.com/Adrekk/Elkarte
PHP | 974 lines | 659 code | 112 blank | 203 comment | 55 complexity | 8cfcff2e176030ce5b68af8400e30f1b MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * This file contains functions for dealing with topics. Low-level functions,
  4. * i.e. database operations needed to perform.
  5. * These functions do NOT make permissions checks. (they assume those were
  6. * already made).
  7. *
  8. * @name ElkArte Forum
  9. * @copyright ElkArte Forum contributors
  10. * @license BSD http://opensource.org/licenses/BSD-3-Clause
  11. *
  12. * @version 1.0.2
  13. *
  14. */
  15. if (!defined('ELK'))
  16. die('No access...');
  17. /**
  18. * Retrieve all installed themes
  19. */
  20. function installedThemes()
  21. {
  22. $db = database();
  23. $request = $db->query('', '
  24. SELECT id_theme, variable, value
  25. FROM {db_prefix}themes
  26. WHERE variable IN ({string:name}, {string:theme_dir}, {string:theme_url}, {string:images_url}, {string:theme_templates}, {string:theme_layers})
  27. AND id_member = {int:no_member}',
  28. array(
  29. 'name' => 'name',
  30. 'theme_dir' => 'theme_dir',
  31. 'theme_url' => 'theme_url',
  32. 'images_url' => 'images_url',
  33. 'theme_templates' => 'theme_templates',
  34. 'theme_layers' => 'theme_layers',
  35. 'no_member' => 0,
  36. )
  37. );
  38. $themes = array();
  39. while ($row = $db->fetch_assoc($request))
  40. {
  41. if (!isset($themes[$row['id_theme']]))
  42. $themes[$row['id_theme']] = array(
  43. 'id' => $row['id_theme'],
  44. 'num_default_options' => 0,
  45. 'num_members' => 0,
  46. );
  47. $themes[$row['id_theme']][$row['variable']] = $row['value'];
  48. }
  49. $db->free_result($request);
  50. return $themes;
  51. }
  52. /**
  53. * Retrieve theme directory
  54. *
  55. * @param int $id_theme the id of the theme
  56. * @return string
  57. */
  58. function themeDirectory($id_theme)
  59. {
  60. $db = database();
  61. $request = $db->query('', '
  62. SELECT value
  63. FROM {db_prefix}themes
  64. WHERE variable = {string:theme_dir}
  65. AND id_theme = {int:current_theme}
  66. LIMIT 1',
  67. array(
  68. 'current_theme' => $id_theme,
  69. 'theme_dir' => 'theme_dir',
  70. )
  71. );
  72. list ($themeDirectory) = $db->fetch_row($request);
  73. $db->free_result($request);
  74. return $themeDirectory;
  75. }
  76. /**
  77. * Retrieve theme URL
  78. *
  79. * @param int $id_theme id of the theme
  80. */
  81. function themeUrl($id_theme)
  82. {
  83. $db = database();
  84. $request = $db->query('', '
  85. SELECT value
  86. FROM {db_prefix}themes
  87. WHERE variable = {string:theme_url}
  88. AND id_theme = {int:current_theme}
  89. LIMIT 1',
  90. array(
  91. 'current_theme' => $id_theme,
  92. 'theme_url' => 'theme_url',
  93. )
  94. );
  95. list ($theme_url) = $db->fetch_row($request);
  96. $db->free_result($request);
  97. return $theme_url;
  98. }
  99. /**
  100. * Validates a theme name
  101. *
  102. * @param mixed[] $indexes
  103. * @param mixed[] $value_data
  104. */
  105. function validateThemeName($indexes, $value_data)
  106. {
  107. $db = database();
  108. $request = $db->query('', '
  109. SELECT id_theme, value
  110. FROM {db_prefix}themes
  111. WHERE id_member = {int:no_member}
  112. AND variable = {string:theme_dir}
  113. AND (' . implode(' OR ', $value_data['query']) . ')',
  114. array_merge($value_data['params'], array(
  115. 'no_member' => 0,
  116. 'theme_dir' => 'theme_dir',
  117. 'index_compare_explode' => 'value LIKE \'%' . implode('\' OR value LIKE \'%', $indexes) . '\'',
  118. ))
  119. );
  120. $themes = array();
  121. while ($row = $db->fetch_assoc($request))
  122. {
  123. // Find the right one.
  124. foreach ($indexes as $index)
  125. if (strpos($row['value'], $index) !== false)
  126. $themes[$row['id_theme']] = $index;
  127. }
  128. $db->free_result($request);
  129. return $themes;
  130. }
  131. /**
  132. * Get a basic list of themes
  133. *
  134. * @param int|int[] $themes
  135. * @return array
  136. */
  137. function getBasicThemeInfos($themes)
  138. {
  139. $db = database();
  140. $themelist = array();
  141. $request = $db->query('', '
  142. SELECT id_theme, value
  143. FROM {db_prefix}themes
  144. WHERE id_member = {int:no_member}
  145. AND variable = {string:name}
  146. AND id_theme IN ({array_int:theme_list})',
  147. array(
  148. 'theme_list' => (array) $themes,
  149. 'no_member' => 0,
  150. 'name' => 'name',
  151. )
  152. );
  153. while ($row = $db->fetch_assoc($request))
  154. $themelist[$row['id_theme']] = $row['value'];
  155. $db->free_result($request);
  156. return $themelist;
  157. }
  158. /**
  159. * Gets a list of all themes from the database
  160. *
  161. * @return array $themes
  162. */
  163. function getCustomThemes()
  164. {
  165. global $settings, $txt;
  166. $db = database();
  167. $request = $db->query('', '
  168. SELECT id_theme, variable, value
  169. FROM {db_prefix}themes
  170. WHERE id_theme != {int:default_theme}
  171. AND id_member = {int:no_member}
  172. AND variable IN ({string:name}, {string:theme_dir})',
  173. array(
  174. 'default_theme' => 1,
  175. 'no_member' => 0,
  176. 'name' => 'name',
  177. 'theme_dir' => 'theme_dir',
  178. )
  179. );
  180. // Manually add in the default
  181. $themes = array(
  182. 1 => array(
  183. 'name' => $txt['dvc_default'],
  184. 'theme_dir' => $settings['default_theme_dir'],
  185. ),
  186. );
  187. while ($row = $db->fetch_assoc($request))
  188. $themes[$row['id_theme']][$row['variable']] = $row['value'];
  189. $db->free_result($request);
  190. return $themes;
  191. }
  192. /**
  193. * Returns all named and installed themes paths as an array of theme name => path
  194. *
  195. * @param int[] $theme_list
  196. */
  197. function getThemesPathbyID($theme_list = array())
  198. {
  199. global $modSettings;
  200. $db = database();
  201. // Nothing passed then we use the defaults
  202. if (empty($theme_list))
  203. $theme_list = explode(',', $modSettings['knownThemes']);
  204. if (!is_array($theme_list))
  205. $theme_list = array($theme_list);
  206. // Load up any themes we need the paths for
  207. $request = $db->query('', '
  208. SELECT id_theme, variable, value
  209. FROM {db_prefix}themes
  210. WHERE (id_theme = {int:default_theme} OR id_theme IN ({array_int:known_theme_list}))
  211. AND variable IN ({string:name}, {string:theme_dir})',
  212. array(
  213. 'known_theme_list' => $theme_list,
  214. 'default_theme' => 1,
  215. 'name' => 'name',
  216. 'theme_dir' => 'theme_dir',
  217. )
  218. );
  219. $theme_paths = array();
  220. while ($row = $db->fetch_assoc($request))
  221. $theme_paths[$row['id_theme']][$row['variable']] = $row['value'];
  222. $db->free_result($request);
  223. return $theme_paths;
  224. }
  225. /**
  226. * Load the installed themes
  227. * (minimum data)
  228. *
  229. * @param int[] $knownThemes available themes
  230. */
  231. function loadThemes($knownThemes)
  232. {
  233. $db = database();
  234. // Load up all the themes.
  235. $request = $db->query('', '
  236. SELECT id_theme, value AS name
  237. FROM {db_prefix}themes
  238. WHERE variable = {string:name}
  239. AND id_member = {int:no_member}
  240. ORDER BY id_theme',
  241. array(
  242. 'no_member' => 0,
  243. 'name' => 'name',
  244. )
  245. );
  246. $themes = array();
  247. while ($row = $db->fetch_assoc($request))
  248. $themes[] = array(
  249. 'id' => $row['id_theme'],
  250. 'name' => $row['name'],
  251. 'known' => in_array($row['id_theme'], $knownThemes),
  252. );
  253. $db->free_result($request);
  254. return $themes;
  255. }
  256. /**
  257. * Load all themes that a package is installed in
  258. *
  259. * @param int $id id of the package we are checking
  260. */
  261. function loadThemesAffected($id)
  262. {
  263. $db = database();
  264. $request = $db->query('', '
  265. SELECT themes_installed
  266. FROM {db_prefix}log_packages
  267. WHERE id_install = {int:install_id}
  268. LIMIT 1',
  269. array(
  270. 'install_id' => $id,
  271. )
  272. );
  273. $themes = array();
  274. while ($row = $db->fetch_row($request))
  275. $themes = explode(',', $row[0]);
  276. $db->free_result($request);
  277. return $themes;
  278. }
  279. /**
  280. * Generates a file listing for a given directory
  281. *
  282. * @param string $path
  283. * @param string $relative
  284. */
  285. function get_file_listing($path, $relative)
  286. {
  287. global $scripturl, $txt, $context;
  288. // Only files with these extensions will be deemed editable
  289. $editable = 'php|pl|css|js|vbs|xml|xslt|txt|xsl|html|htm|shtm|shtml|asp|aspx|cgi|py';
  290. // Is it even a directory?
  291. if (!is_dir($path))
  292. fatal_lang_error('error_invalid_dir', 'critical');
  293. // Read this directorys contents
  294. $entries = array();
  295. $dir = dir($path);
  296. while ($entry = $dir->read())
  297. $entries[] = $entry;
  298. $dir->close();
  299. // Sort it so it looks natural to the user
  300. natcasesort($entries);
  301. $listing1 = array();
  302. $listing2 = array();
  303. foreach ($entries as $entry)
  304. {
  305. // Skip all dot files, including .htaccess.
  306. if (substr($entry, 0, 1) === '.' || $entry === 'CVS')
  307. continue;
  308. // A directory entry
  309. if (is_dir($path . '/' . $entry))
  310. $listing1[] = array(
  311. 'filename' => $entry,
  312. 'is_writable' => is_writable($path . '/' . $entry),
  313. 'is_directory' => true,
  314. 'is_template' => false,
  315. 'is_image' => false,
  316. 'is_editable' => false,
  317. 'href' => $scripturl . '?action=admin;area=theme;th=' . $_GET['th'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=browse;directory=' . $relative . $entry,
  318. 'size' => '',
  319. );
  320. // A file entry has some more checks
  321. else
  322. {
  323. $size = filesize($path . '/' . $entry);
  324. if ($size > 2048 || $size == 1024)
  325. $size = comma_format($size / 1024) . ' ' . $txt['themeadmin_edit_kilobytes'];
  326. else
  327. $size = comma_format($size) . ' ' . $txt['themeadmin_edit_bytes'];
  328. $writable = is_writable($path . '/' . $entry);
  329. $listing2[] = array(
  330. 'filename' => $entry,
  331. 'is_writable' => $writable,
  332. 'is_directory' => false,
  333. 'is_template' => preg_match('~\.template\.php$~', $entry) != 0,
  334. 'is_image' => preg_match('~\.(jpg|jpeg|gif|bmp|png|ico)$~', $entry) != 0,
  335. 'is_editable' => $writable && preg_match('~\.(' . $editable . ')$~', $entry) != 0,
  336. 'href' => $scripturl . '?action=admin;area=theme;th=' . $_GET['th'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=edit;filename=' . $relative . $entry,
  337. 'size' => $size,
  338. 'last_modified' => standardTime(filemtime($path . '/' . $entry)),
  339. );
  340. }
  341. }
  342. return array_merge($listing1, $listing2);
  343. }
  344. /**
  345. * Counts the theme options configured for guests
  346. * @return array
  347. */
  348. function countConfiguredGuestOptions()
  349. {
  350. $db = database();
  351. $themes = array();
  352. $request = $db->query('', '
  353. SELECT id_theme, COUNT(*) AS value
  354. FROM {db_prefix}themes
  355. WHERE id_member = {int:guest_member}
  356. GROUP BY id_theme',
  357. array(
  358. 'guest_member' => -1,
  359. )
  360. );
  361. while ($row = $db->fetch_assoc($request))
  362. $themes[] = $row;
  363. $db->free_result($request);
  364. return($themes);
  365. }
  366. /**
  367. * Counts the theme options configured for guests
  368. *
  369. * @param int $current_theme
  370. * @param int $current_member
  371. */
  372. function availableThemes($current_theme, $current_member)
  373. {
  374. global $modSettings, $settings, $user_info, $txt, $language;
  375. $db = database();
  376. $available_themes = array();
  377. if (!empty($modSettings['knownThemes']))
  378. {
  379. $request = $db->query('', '
  380. SELECT id_theme, variable, value
  381. FROM {db_prefix}themes
  382. WHERE variable IN ({string:name}, {string:theme_url}, {string:theme_dir}, {string:images_url}, {string:disable_user_variant})' . (!allowedTo('admin_forum') ? '
  383. AND id_theme IN ({array_string:known_themes})' : '') . '
  384. AND id_theme != {int:default_theme}
  385. AND id_member = {int:no_member}',
  386. array(
  387. 'default_theme' => 0,
  388. 'name' => 'name',
  389. 'no_member' => 0,
  390. 'theme_url' => 'theme_url',
  391. 'theme_dir' => 'theme_dir',
  392. 'images_url' => 'images_url',
  393. 'disable_user_variant' => 'disable_user_variant',
  394. 'known_themes' => !empty($modSettings['theme_allow']) || allowedTo('admin_forum') ? explode(',', $modSettings['knownThemes']) : array($modSettings['theme_guests']),
  395. )
  396. );
  397. while ($row = $db->fetch_assoc($request))
  398. {
  399. if (!isset($available_themes[$row['id_theme']]))
  400. $available_themes[$row['id_theme']] = array(
  401. 'id' => $row['id_theme'],
  402. 'selected' => $current_theme == $row['id_theme'],
  403. 'num_users' => 0
  404. );
  405. $available_themes[$row['id_theme']][$row['variable']] = $row['value'];
  406. }
  407. $db->free_result($request);
  408. }
  409. // Okay, this is a complicated problem: the default theme is 1, but they aren't allowed to access 1!
  410. if (!isset($available_themes[$modSettings['theme_guests']]))
  411. {
  412. $available_themes[0] = array(
  413. 'num_users' => 0
  414. );
  415. $guest_theme = 0;
  416. }
  417. else
  418. $guest_theme = $modSettings['theme_guests'];
  419. $request = $db->query('', '
  420. SELECT id_theme, COUNT(*) AS the_count
  421. FROM {db_prefix}members
  422. GROUP BY id_theme
  423. ORDER BY id_theme DESC',
  424. array(
  425. )
  426. );
  427. while ($row = $db->fetch_assoc($request))
  428. {
  429. // Figure out which theme it is they are REALLY using.
  430. if (!empty($modSettings['knownThemes']) && !in_array($row['id_theme'], explode(',', $modSettings['knownThemes'])))
  431. $row['id_theme'] = $guest_theme;
  432. elseif (empty($modSettings['theme_allow']))
  433. $row['id_theme'] = $guest_theme;
  434. if (isset($available_themes[$row['id_theme']]))
  435. $available_themes[$row['id_theme']]['num_users'] += $row['the_count'];
  436. else
  437. $available_themes[$guest_theme]['num_users'] += $row['the_count'];
  438. }
  439. $db->free_result($request);
  440. // Get any member variant preferences.
  441. $variant_preferences = array();
  442. if ($current_member > 0)
  443. {
  444. $request = $db->query('', '
  445. SELECT id_theme, value
  446. FROM {db_prefix}themes
  447. WHERE variable = {string:theme_variant}
  448. AND id_member IN ({array_int:id_member})
  449. ORDER BY id_member ASC',
  450. array(
  451. 'theme_variant' => 'theme_variant',
  452. 'id_member' => isset($_REQUEST['sa']) && $_REQUEST['sa'] == 'pick' ? array(-1, $current_member) : array(-1),
  453. )
  454. );
  455. while ($row = $db->fetch_assoc($request))
  456. $variant_preferences[$row['id_theme']] = $row['value'];
  457. $db->free_result($request);
  458. }
  459. // Save the setting first.
  460. $current_images_url = $settings['images_url'];
  461. $current_theme_variants = !empty($settings['theme_variants']) ? $settings['theme_variants'] : array();
  462. foreach ($available_themes as $id_theme => $theme_data)
  463. {
  464. // Don't try to load the forum or board default theme's data... it doesn't have any!
  465. if ($id_theme == 0)
  466. continue;
  467. // The thumbnail needs the correct path.
  468. $settings['images_url'] = &$theme_data['images_url'];
  469. if (file_exists($theme_data['theme_dir'] . '/languages/' . $user_info['language'] . '/Settings.' . $user_info['language'] . '.php'))
  470. include($theme_data['theme_dir'] . '/languages/' . $user_info['language'] . '/Settings.' . $user_info['language'] . '.php');
  471. elseif (file_exists($theme_data['theme_dir'] . '/languages/' . $language . '/Settings.' . $language . '.php'))
  472. include($theme_data['theme_dir'] . '/languages/' . $language . '/Settings.' . $language . '.php');
  473. else
  474. {
  475. $txt['theme_thumbnail_href'] = $theme_data['images_url'] . '/thumbnail.png';
  476. $txt['theme_description'] = '';
  477. }
  478. $available_themes[$id_theme]['thumbnail_href'] = str_replace('{images_url}', $settings['images_url'], $txt['theme_thumbnail_href']);
  479. $available_themes[$id_theme]['description'] = $txt['theme_description'];
  480. // Are there any variants?
  481. if (file_exists($theme_data['theme_dir'] . '/index.template.php') && (empty($theme_data['disable_user_variant']) || allowedTo('admin_forum')))
  482. {
  483. $file_contents = implode('', file($theme_data['theme_dir'] . '/index.template.php'));
  484. if (preg_match('~\'theme_variants\'\s*=>(.+?\)),$~sm', $file_contents, $matches))
  485. {
  486. $settings['theme_variants'] = array();
  487. // Fill settings up.
  488. eval('global $settings; $settings[\'theme_variants\'] = ' . $matches[1] . ';');
  489. call_integration_hook('integrate_init_theme', array($id_theme, &$settings));
  490. if (!empty($settings['theme_variants']))
  491. {
  492. loadLanguage('Settings');
  493. $available_themes[$id_theme]['variants'] = array();
  494. foreach ($settings['theme_variants'] as $variant)
  495. $available_themes[$id_theme]['variants'][$variant] = array(
  496. 'label' => isset($txt['variant_' . $variant]) ? $txt['variant_' . $variant] : $variant,
  497. 'thumbnail' => !file_exists($theme_data['theme_dir'] . '/images/thumbnail.png') || file_exists($theme_data['theme_dir'] . '/images/thumbnail_' . $variant . '.png') ? $theme_data['images_url'] . '/thumbnail_' . $variant . '.png' : ($theme_data['images_url'] . '/thumbnail.png'),
  498. );
  499. $available_themes[$id_theme]['selected_variant'] = isset($_GET['vrt']) ? $_GET['vrt'] : (!empty($variant_preferences[$id_theme]) ? $variant_preferences[$id_theme] : (!empty($settings['default_variant']) ? $settings['default_variant'] : $settings['theme_variants'][0]));
  500. if (!isset($available_themes[$id_theme]['variants'][$available_themes[$id_theme]['selected_variant']]['thumbnail']))
  501. $available_themes[$id_theme]['selected_variant'] = $settings['theme_variants'][0];
  502. $available_themes[$id_theme]['thumbnail_href'] = $available_themes[$id_theme]['variants'][$available_themes[$id_theme]['selected_variant']]['thumbnail'];
  503. // Allow themes to override the text.
  504. $available_themes[$id_theme]['pick_label'] = isset($txt['variant_pick']) ? $txt['variant_pick'] : $txt['theme_pick_variant'];
  505. }
  506. }
  507. }
  508. }
  509. // Then return it.
  510. $settings['images_url'] = $current_images_url;
  511. $settings['theme_variants'] = $current_theme_variants;
  512. return array($available_themes, $guest_theme);
  513. }
  514. /**
  515. * Counts the theme options configured for members
  516. * @return array
  517. */
  518. function countConfiguredMemberOptions()
  519. {
  520. $db = database();
  521. $themes = array();
  522. $request = $db->query('themes_count', '
  523. SELECT COUNT(DISTINCT id_member) AS value, id_theme
  524. FROM {db_prefix}themes
  525. WHERE id_member > {int:no_member}
  526. GROUP BY id_theme',
  527. array(
  528. 'no_member' => 0,
  529. )
  530. );
  531. while ($row = $db->fetch_assoc($request))
  532. $themes[] = $row;
  533. $db->free_result($request);
  534. return $themes;
  535. }
  536. /**
  537. * Deletes all outdated options from the themes table
  538. *
  539. * @param int|string $theme : if int to remove option from a specific theme,
  540. * if string it can be:
  541. * - 'default' => to remove from the default theme
  542. * - 'custom' => to remove from all the custom themes
  543. * - 'all' => to remove from both default and custom
  544. * @param int|string $membergroups : if int a specific member
  545. * if string a "group" of members and it can assume the following values:
  546. * - 'guests' => obviously guests,
  547. * - 'members' => all members with custom settings (i.e. id_member > 0)
  548. * - 'non_default' => guests and members with custom settings (i.e. id_member != 0)
  549. * - 'all' => any record
  550. * @param string[]|string $old_settings can be a string or an array of strings. If empty deletes all settings.
  551. */
  552. function removeThemeOptions($theme, $membergroups, $old_settings = '')
  553. {
  554. $db = database();
  555. $query_param = array();
  556. // The default theme is 1 (id_theme = 1)
  557. if ($theme === 'default')
  558. $query_param = array('theme_operator' => '=', 'theme' => 1);
  559. // All the themes that are not the default one (id_theme != 1)
  560. // @todo 'non_default' would be more esplicative, though it could be confused with the one in $membergroups
  561. elseif ($theme === 'custom')
  562. $query_param = array('theme_operator' => '!=', 'theme' => 1);
  563. // If numeric means a specific theme
  564. elseif (is_numeric($theme))
  565. $query_param = array('theme_operator' => '=', 'theme' => (int) $theme);
  566. // Guests means id_member = -1
  567. if ($membergroups === 'guests' )
  568. $query_param += array('member_operator' => '=', 'member' => -1);
  569. // Members means id_member > 0
  570. elseif ($membergroups === 'members')
  571. $query_param += array('member_operator' => '>', 'member' => 0);
  572. // Non default settings id_member != 0 (that is different from id_member > 0)
  573. elseif ($membergroups === 'non_default')
  574. $query_param += array('member_operator' => '!=', 'member' => 0);
  575. // all it's all
  576. elseif ($membergroups === 'all')
  577. $query_param += array('member_operator' => '', 'member' => 0);
  578. // If it is a number, then it means a specific member (id_member = (int))
  579. elseif (is_numeric($membergroups))
  580. $query_param += array('member_operator' => '=', 'member' => (int) $membergroups);
  581. // If array or string set up the query accordingly
  582. if (is_array($old_settings))
  583. $var = 'variable IN ({array_string:old_settings})';
  584. elseif (!empty($old_settings))
  585. $var = 'variable = {string:old_settings}';
  586. // If empty then means any setting
  587. else
  588. $var = '1=1';
  589. $db->query('', '
  590. DELETE FROM {db_prefix}themes
  591. WHERE ' . $var . ($membergroups === 'all' ? '' : '
  592. AND id_member {raw:member_operator} {int:member}') . ($theme === 'all' ? '' : '
  593. AND id_theme {raw:theme_operator} {int:theme}'),
  594. array_merge(
  595. $query_param,
  596. array(
  597. 'old_settings' => $old_settings
  598. )
  599. )
  600. );
  601. }
  602. /**
  603. * Update the default options for our users.
  604. *
  605. * @param mixed[] $setValues in the order: id_theme, id_member, variable name, value
  606. */
  607. function updateThemeOptions($setValues)
  608. {
  609. $db = database();
  610. $db->insert('replace',
  611. '{db_prefix}themes',
  612. array('id_theme' => 'int', 'id_member' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'),
  613. $setValues,
  614. array('id_theme', 'variable', 'id_member')
  615. );
  616. }
  617. /**
  618. * Add predefined options to the themes table.
  619. *
  620. * @param int $id_theme
  621. * @param string $options
  622. * @param string[]|string $value
  623. */
  624. function addThemeOptions($id_theme, $options, $value)
  625. {
  626. $db = database();
  627. $db->query('substring', '
  628. INSERT INTO {db_prefix}themes
  629. (id_member, id_theme, variable, value)
  630. SELECT id_member, {int:current_theme}, SUBSTRING({string:option}, 1, 255), SUBSTRING({string:value}, 1, 65534)
  631. FROM {db_prefix}members',
  632. array(
  633. 'current_theme' => $id_theme,
  634. 'option' => $options,
  635. 'value' => (is_array($value) ? implode(',', $value) : $value),
  636. )
  637. );
  638. }
  639. /**
  640. * Deletes a theme from the database.
  641. *
  642. * @param int $id
  643. */
  644. function deleteTheme($id)
  645. {
  646. $db = database();
  647. // Make sure we never ever delete the default theme!
  648. if ($id === 1)
  649. fatal_lang_error('no_access', false);
  650. $db->query('', '
  651. DELETE FROM {db_prefix}themes
  652. WHERE id_theme = {int:current_theme}',
  653. array(
  654. 'current_theme' => $id,
  655. )
  656. );
  657. // Update the members ...
  658. $db->query('', '
  659. UPDATE {db_prefix}members
  660. SET id_theme = {int:default_theme}
  661. WHERE id_theme = {int:current_theme}',
  662. array(
  663. 'default_theme' => 0,
  664. 'current_theme' => $id,
  665. )
  666. );
  667. // ... and the boards table.
  668. $db->query('', '
  669. UPDATE {db_prefix}boards
  670. SET id_theme = {int:default_theme}
  671. WHERE id_theme = {int:current_theme}',
  672. array(
  673. 'default_theme' => 0,
  674. 'current_theme' => $id,
  675. )
  676. );
  677. }
  678. /**
  679. * Get the next free id for the theme.
  680. *
  681. * @return int
  682. */
  683. function nextTheme()
  684. {
  685. $db = database();
  686. // Find the newest id_theme.
  687. $result = $db->query('', '
  688. SELECT MAX(id_theme)
  689. FROM {db_prefix}themes',
  690. array(
  691. )
  692. );
  693. list ($id_theme) = $db->fetch_row($result);
  694. $db->free_result($result);
  695. // This will be theme number...
  696. $id_theme++;
  697. return $id_theme;
  698. }
  699. /**
  700. * Adds a new theme to the database.
  701. *
  702. * @param mixed[] $details
  703. */
  704. function addTheme($details)
  705. {
  706. $db = database();
  707. $db->insert('insert',
  708. '{db_prefix}themes',
  709. array('id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'),
  710. $details,
  711. array('id_theme', 'variable')
  712. );
  713. }
  714. /**
  715. * Get the name of a theme
  716. *
  717. * @param int $id
  718. * @return string
  719. */
  720. function getThemeName($id)
  721. {
  722. $db = database();
  723. $result = $db->query('', '
  724. SELECT value
  725. FROM {db_prefix}themes
  726. WHERE id_theme = {int:current_theme}
  727. AND id_member = {int:no_member}
  728. AND variable = {string:name}
  729. LIMIT 1',
  730. array(
  731. 'current_theme' => $id,
  732. 'no_member' => 0,
  733. 'name' => 'name',
  734. )
  735. );
  736. list ($theme_name) = $db->fetch_row($result);
  737. $db->free_result($result);
  738. return $theme_name;
  739. }
  740. /**
  741. * Deletes all variants from a given theme id.
  742. *
  743. * @param int $id
  744. */
  745. function deleteVariants($id)
  746. {
  747. $db = database();
  748. $db->query('', '
  749. DELETE FROM {db_prefix}themes
  750. WHERE id_theme = {int:current_theme}
  751. AND variable = {string:theme_variant}',
  752. array(
  753. 'current_theme' => $id,
  754. 'theme_variant' => 'theme_variant',
  755. )
  756. );
  757. }
  758. /**
  759. * Loads all of the them variable/value pairs for a member or group of members
  760. * If supplied a variable array it will only load / return those values
  761. *
  762. * @param int|int[] $theme
  763. * @param int|null $memID
  764. * @param mixed[] $options
  765. * @param string[] $variables
  766. */
  767. function loadThemeOptionsInto($theme, $memID = null, $options = array(), $variables = array())
  768. {
  769. $db = database();
  770. $variables = is_array($variables) ? $variables : array($variables);
  771. // @todo the ORDER BY may or may not be necessary:
  772. // I have the feeling that *sometimes* the default order may be a bit messy,
  773. // and considering this function is not use in frequently accessed areas the
  774. // overhead for an ORDER BY should be acceptable
  775. $request = $db->query('', '
  776. SELECT variable, value
  777. FROM {db_prefix}themes
  778. WHERE id_theme IN ({array_int:current_theme})' . ($memID === null ? '' : (is_array($memID) ? '
  779. AND id_member IN ({array_int:guest_member})' : '
  780. AND id_member = {int:guest_member}')) . (!empty($variables) ? '
  781. AND variable IN ({array_string:variables})' : '') . '
  782. ORDER BY id_theme ASC' . ($memID === null ? '' : ', id_member ASC'),
  783. array(
  784. 'current_theme' => is_array($theme) ? $theme : array($theme),
  785. 'guest_member' => $memID,
  786. 'variables' => $variables,
  787. )
  788. );
  789. while ($row = $db->fetch_assoc($request))
  790. $options[$row['variable']] = $row['value'];
  791. $db->free_result($request);
  792. return $options;
  793. }
  794. /**
  795. * Used when installing a theme that is based off an existing theme (an therefore is dependant on)
  796. * Returns based-on theme directory values needed by the install function in ManageThemes.controller
  797. *
  798. * @todo may be merged with something else?
  799. * @param string $based_on name of theme this is based on, will do a LIKE search
  800. * @param boolean $explicit_images Don't worry its not like it sounds !
  801. */
  802. function loadBasedOnTheme($based_on, $explicit_images = false)
  803. {
  804. $db = database();
  805. $request = $db->query('', '
  806. SELECT th.value AS base_theme_dir, th2.value AS base_theme_url' . (!empty($explicit_images) ? '' : ', th3.value AS images_url') . '
  807. FROM {db_prefix}themes AS th
  808. INNER JOIN {db_prefix}themes AS th2 ON (th2.id_theme = th.id_theme
  809. AND th2.id_member = {int:no_member}
  810. AND th2.variable = {string:theme_url})' . (!empty($explicit_images) ? '' : '
  811. INNER JOIN {db_prefix}themes AS th3 ON (th3.id_theme = th.id_theme
  812. AND th3.id_member = {int:no_member}
  813. AND th3.variable = {string:images_url})') . '
  814. WHERE th.id_member = {int:no_member}
  815. AND (th.value LIKE {string:based_on} OR th.value LIKE {string:based_on_path})
  816. AND th.variable = {string:theme_dir}
  817. LIMIT 1',
  818. array(
  819. 'no_member' => 0,
  820. 'theme_url' => 'theme_url',
  821. 'images_url' => 'images_url',
  822. 'theme_dir' => 'theme_dir',
  823. 'based_on' => '%/' . $based_on,
  824. 'based_on_path' => '%' . "\\" . $based_on,
  825. )
  826. );
  827. $temp = $db->fetch_assoc($request);
  828. $db->free_result($request);
  829. return $temp;
  830. }
  831. /**
  832. * Builds a theme-info.xml file for use when a new theme is installed by copying
  833. * an existing theme
  834. *
  835. * @param string $name
  836. * @param string $version
  837. * @param string $theme_dir
  838. * @param mixed[] $theme_values
  839. */
  840. function write_theme_info($name, $version, $theme_dir, $theme_values)
  841. {
  842. $xml_info = '<' . '?xml version="1.0"?' . '>
  843. <theme-info xmlns="http://www.elkarte.net/xml/theme-info" xmlns:elk="http://www.elkarte.net/">
  844. <!-- For the id, always use something unique - put your name, a colon, and then the package name. -->
  845. <id>elk:' . Util::strtolower(str_replace(array(' '), '_', $name)) . '</id>
  846. <version>' . $version . '</version>
  847. <!-- Theme name, used purely for aesthetics. -->
  848. <name>' . $name . '</name>
  849. <!-- Author: your email address or contact information. The name attribute is optional. -->
  850. <author name="Your Name">info@youremailaddress.tld</author>
  851. <!-- Website... where to get updates and more information. -->
  852. <website>http://www.yourdomain.tld/</website>
  853. <!-- Template layers to use, defaults to "html,body". -->
  854. <layers>' . (empty($theme_values['theme_layers']) ? 'html,body' : $theme_values['theme_layers']) . '</layers>
  855. <!-- Templates to load on startup. Default is "index". -->
  856. <templates>' . (empty($theme_values['theme_templates']) ? 'index' : $theme_values['theme_templates']) . '</templates>
  857. <!-- Base this theme off another? Default is blank, or no. It could be "default". -->
  858. <based-on></based-on>
  859. </theme-info>';
  860. // Now write it.
  861. file_put_contents($theme_dir . '/theme_info.xml', $xml_info);
  862. }