PageRenderTime 91ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/includes/acp/acp_styles.php

https://github.com/Vexilurz/phpbb_forum
PHP | 3976 lines | 3093 code | 612 blank | 271 comment | 535 complexity | cd116c306ee718d755f10962ec5030e6 MD5 | raw file
Possible License(s): AGPL-1.0
  1. <?php
  2. /**
  3. *
  4. * @package acp
  5. * @version $Id$
  6. * @copyright (c) 2005 phpBB Group
  7. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  8. *
  9. */
  10. /**
  11. * @ignore
  12. */
  13. if (!defined('IN_PHPBB'))
  14. {
  15. exit;
  16. }
  17. /**
  18. * @package acp
  19. */
  20. class acp_styles
  21. {
  22. var $u_action;
  23. var $style_cfg;
  24. var $template_cfg;
  25. var $theme_cfg;
  26. var $imageset_cfg;
  27. var $imageset_keys;
  28. function main($id, $mode)
  29. {
  30. global $db, $user, $auth, $template, $cache;
  31. global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
  32. // Hardcoded template bitfield to add for new templates
  33. $bitfield = new bitfield();
  34. $bitfield->set(0);
  35. $bitfield->set(1);
  36. $bitfield->set(2);
  37. $bitfield->set(3);
  38. $bitfield->set(4);
  39. $bitfield->set(8);
  40. $bitfield->set(9);
  41. $bitfield->set(11);
  42. $bitfield->set(12);
  43. define('TEMPLATE_BITFIELD', $bitfield->get_base64());
  44. unset($bitfield);
  45. $user->add_lang('acp/styles');
  46. $this->tpl_name = 'acp_styles';
  47. $this->page_title = 'ACP_CAT_STYLES';
  48. $action = request_var('action', '');
  49. $action = (isset($_POST['add'])) ? 'add' : $action;
  50. $style_id = request_var('id', 0);
  51. // Fill the configuration variables
  52. $this->style_cfg = $this->template_cfg = $this->theme_cfg = $this->imageset_cfg = '
  53. #
  54. # phpBB {MODE} configuration file
  55. #
  56. # @package phpBB3
  57. # @copyright (c) 2005 phpBB Group
  58. # @license http://opensource.org/licenses/gpl-license.php GNU Public License
  59. #
  60. #
  61. # At the left is the name, please do not change this
  62. # At the right the value is entered
  63. # For on/off options the valid values are on, off, 1, 0, true and false
  64. #
  65. # Values get trimmed, if you want to add a space in front or at the end of
  66. # the value, then enclose the value with single or double quotes.
  67. # Single and double quotes do not need to be escaped.
  68. #
  69. #
  70. # General Information about this {MODE}
  71. name = {NAME}
  72. copyright = {COPYRIGHT}
  73. version = {VERSION}
  74. ';
  75. $this->theme_cfg .= '
  76. # Some configuration options
  77. #
  78. # You have to turn this option on if you want to use the
  79. # path template variables ({T_IMAGESET_PATH} for example) within
  80. # your css file.
  81. # This is mostly the case if you want to use language specific
  82. # images within your css file.
  83. #
  84. parse_css_file = {PARSE_CSS_FILE}
  85. ';
  86. $this->template_cfg .= '
  87. # Some configuration options
  88. # Template inheritance
  89. # See http://blog.phpbb.com/2008/07/31/templating-just-got-easier/
  90. # Set value to empty or this template name to ignore template inheritance.
  91. inherit_from = {INHERIT_FROM}
  92. ';
  93. $this->imageset_keys = array(
  94. 'logos' => array(
  95. 'site_logo',
  96. ),
  97. 'buttons' => array(
  98. 'icon_back_top', 'icon_contact_aim', 'icon_contact_email', 'icon_contact_icq', 'icon_contact_jabber', 'icon_contact_msnm', 'icon_contact_pm', 'icon_contact_yahoo', 'icon_contact_www', 'icon_post_delete', 'icon_post_edit', 'icon_post_info', 'icon_post_quote', 'icon_post_report', 'icon_user_online', 'icon_user_offline', 'icon_user_profile', 'icon_user_search', 'icon_user_warn', 'button_pm_forward', 'button_pm_new', 'button_pm_reply', 'button_topic_locked', 'button_topic_new', 'button_topic_reply', 'thankposts', 'removethanks',
  99. ),
  100. 'icons' => array(
  101. 'icon_post_target', 'icon_post_target_unread', 'icon_topic_attach', 'icon_topic_latest', 'icon_topic_newest', 'icon_topic_reported', 'icon_topic_unapproved', 'icon_friend', 'icon_foe',
  102. ),
  103. 'forums' => array(
  104. 'forum_link', 'forum_read', 'forum_read_locked', 'forum_read_subforum', 'forum_unread', 'forum_unread_locked', 'forum_unread_subforum', 'subforum_read', 'subforum_unread'
  105. ),
  106. 'folders' => array(
  107. 'topic_moved', 'topic_read', 'topic_read_mine', 'topic_read_hot', 'topic_read_hot_mine', 'topic_read_locked', 'topic_read_locked_mine', 'topic_unread', 'topic_unread_mine', 'topic_unread_hot', 'topic_unread_hot_mine', 'topic_unread_locked', 'topic_unread_locked_mine', 'sticky_read', 'sticky_read_mine', 'sticky_read_locked', 'sticky_read_locked_mine', 'sticky_unread', 'sticky_unread_mine', 'sticky_unread_locked', 'sticky_unread_locked_mine', 'announce_read', 'announce_read_mine', 'announce_read_locked', 'announce_read_locked_mine', 'announce_unread', 'announce_unread_mine', 'announce_unread_locked', 'announce_unread_locked_mine', 'global_read', 'global_read_mine', 'global_read_locked', 'global_read_locked_mine', 'global_unread', 'global_unread_mine', 'global_unread_locked', 'global_unread_locked_mine', 'pm_read', 'pm_unread',
  108. ),
  109. 'polls' => array(
  110. 'poll_left', 'poll_center', 'poll_right',
  111. ),
  112. 'ui' => array(
  113. 'upload_bar',
  114. ),
  115. 'user' => array(
  116. 'user_icon1', 'user_icon2', 'user_icon3', 'user_icon4', 'user_icon5', 'user_icon6', 'user_icon7', 'user_icon8', 'user_icon9', 'user_icon10',
  117. ),
  118. );
  119. // Execute overall actions
  120. switch ($action)
  121. {
  122. case 'delete':
  123. if ($style_id)
  124. {
  125. $this->remove($mode, $style_id);
  126. return;
  127. }
  128. break;
  129. case 'export':
  130. if ($style_id)
  131. {
  132. $this->export($mode, $style_id);
  133. return;
  134. }
  135. break;
  136. case 'install':
  137. $this->install($mode);
  138. return;
  139. break;
  140. case 'add':
  141. $this->add($mode);
  142. return;
  143. break;
  144. case 'details':
  145. if ($style_id)
  146. {
  147. $this->details($mode, $style_id);
  148. return;
  149. }
  150. break;
  151. case 'edit':
  152. if ($style_id)
  153. {
  154. switch ($mode)
  155. {
  156. case 'imageset':
  157. return $this->edit_imageset($style_id);
  158. case 'template':
  159. return $this->edit_template($style_id);
  160. case 'theme':
  161. return $this->edit_theme($style_id);
  162. }
  163. }
  164. break;
  165. case 'cache':
  166. if ($style_id)
  167. {
  168. switch ($mode)
  169. {
  170. case 'template':
  171. return $this->template_cache($style_id);
  172. }
  173. }
  174. break;
  175. }
  176. switch ($mode)
  177. {
  178. case 'style':
  179. switch ($action)
  180. {
  181. case 'activate':
  182. case 'deactivate':
  183. if ($style_id == $config['default_style'])
  184. {
  185. trigger_error($user->lang['DEACTIVATE_DEFAULT'] . adm_back_link($this->u_action), E_USER_WARNING);
  186. }
  187. if (($action == 'deactivate' && confirm_box(true)) || $action == 'activate')
  188. {
  189. $sql = 'UPDATE ' . STYLES_TABLE . '
  190. SET style_active = ' . (($action == 'activate') ? 1 : 0) . '
  191. WHERE style_id = ' . $style_id;
  192. $db->sql_query($sql);
  193. // Set style to default for any member using deactivated style
  194. if ($action == 'deactivate')
  195. {
  196. $sql = 'UPDATE ' . USERS_TABLE . '
  197. SET user_style = ' . $config['default_style'] . "
  198. WHERE user_style = $style_id";
  199. $db->sql_query($sql);
  200. $sql = 'UPDATE ' . FORUMS_TABLE . '
  201. SET forum_style = 0
  202. WHERE forum_style = ' . $style_id;
  203. $db->sql_query($sql);
  204. }
  205. }
  206. else if ($action == 'deactivate')
  207. {
  208. $s_hidden_fields = array(
  209. 'i' => $id,
  210. 'mode' => $mode,
  211. 'action' => $action,
  212. 'style_id' => $style_id,
  213. );
  214. confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($s_hidden_fields));
  215. }
  216. break;
  217. }
  218. $this->frontend('style', array('details'), array('export', 'delete'));
  219. break;
  220. case 'template':
  221. switch ($action)
  222. {
  223. // Refresh template data stored in db and clear cache
  224. case 'refresh':
  225. $sql = 'SELECT *
  226. FROM ' . STYLES_TEMPLATE_TABLE . "
  227. WHERE template_id = $style_id";
  228. $result = $db->sql_query($sql);
  229. $template_row = $db->sql_fetchrow($result);
  230. $db->sql_freeresult($result);
  231. if (!$template_row)
  232. {
  233. trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING);
  234. }
  235. if (confirm_box(true))
  236. {
  237. $template_refreshed = '';
  238. // Only refresh database if the template is stored in the database
  239. if ($template_row['template_storedb'] && file_exists("{$phpbb_root_path}styles/{$template_row['template_path']}/template/"))
  240. {
  241. $filelist = array('' => array());
  242. $sql = 'SELECT template_filename, template_mtime
  243. FROM ' . STYLES_TEMPLATE_DATA_TABLE . "
  244. WHERE template_id = $style_id";
  245. $result = $db->sql_query($sql);
  246. while ($row = $db->sql_fetchrow($result))
  247. {
  248. // if (@filemtime("{$phpbb_root_path}styles/{$template_row['template_path']}/template/" . $row['template_filename']) > $row['template_mtime'])
  249. // {
  250. // get folder info from the filename
  251. if (($slash_pos = strrpos($row['template_filename'], '/')) === false)
  252. {
  253. $filelist[''][] = $row['template_filename'];
  254. }
  255. else
  256. {
  257. $filelist[substr($row['template_filename'], 0, $slash_pos + 1)][] = substr($row['template_filename'], $slash_pos + 1, strlen($row['template_filename']) - $slash_pos - 1);
  258. }
  259. // }
  260. }
  261. $db->sql_freeresult($result);
  262. $this->store_templates('update', $style_id, $template_row['template_path'], $filelist);
  263. unset($filelist);
  264. $template_refreshed = $user->lang['TEMPLATE_REFRESHED'] . '<br />';
  265. add_log('admin', 'LOG_TEMPLATE_REFRESHED', $template_row['template_name']);
  266. }
  267. $this->clear_template_cache($template_row);
  268. trigger_error($template_refreshed . $user->lang['TEMPLATE_CACHE_CLEARED'] . adm_back_link($this->u_action));
  269. }
  270. else
  271. {
  272. confirm_box(false, ($template_row['template_storedb']) ? $user->lang['CONFIRM_TEMPLATE_REFRESH'] : $user->lang['CONFIRM_TEMPLATE_CLEAR_CACHE'], build_hidden_fields(array(
  273. 'i' => $id,
  274. 'mode' => $mode,
  275. 'action' => $action,
  276. 'id' => $style_id
  277. )));
  278. }
  279. break;
  280. }
  281. $this->frontend('template', array('edit', 'cache', 'details'), array('refresh', 'export', 'delete'));
  282. break;
  283. case 'theme':
  284. switch ($action)
  285. {
  286. // Refresh theme data stored in the database
  287. case 'refresh':
  288. $sql = 'SELECT *
  289. FROM ' . STYLES_THEME_TABLE . "
  290. WHERE theme_id = $style_id";
  291. $result = $db->sql_query($sql);
  292. $theme_row = $db->sql_fetchrow($result);
  293. $db->sql_freeresult($result);
  294. if (!$theme_row)
  295. {
  296. trigger_error($user->lang['NO_THEME'] . adm_back_link($this->u_action), E_USER_WARNING);
  297. }
  298. if (!$theme_row['theme_storedb'])
  299. {
  300. trigger_error($user->lang['THEME_ERR_REFRESH_FS'] . adm_back_link($this->u_action), E_USER_WARNING);
  301. }
  302. if (confirm_box(true))
  303. {
  304. if ($theme_row['theme_storedb'] && file_exists("{$phpbb_root_path}styles/{$theme_row['theme_path']}/theme/stylesheet.css"))
  305. {
  306. // Save CSS contents
  307. $sql_ary = array(
  308. 'theme_mtime' => (int) filemtime("{$phpbb_root_path}styles/{$theme_row['theme_path']}/theme/stylesheet.css"),
  309. 'theme_data' => $this->db_theme_data($theme_row)
  310. );
  311. $sql = 'UPDATE ' . STYLES_THEME_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . "
  312. WHERE theme_id = $style_id";
  313. $db->sql_query($sql);
  314. $cache->destroy('sql', STYLES_THEME_TABLE);
  315. add_log('admin', 'LOG_THEME_REFRESHED', $theme_row['theme_name']);
  316. trigger_error($user->lang['THEME_REFRESHED'] . adm_back_link($this->u_action));
  317. }
  318. }
  319. else
  320. {
  321. confirm_box(false, $user->lang['CONFIRM_THEME_REFRESH'], build_hidden_fields(array(
  322. 'i' => $id,
  323. 'mode' => $mode,
  324. 'action' => $action,
  325. 'id' => $style_id
  326. )));
  327. }
  328. break;
  329. }
  330. $this->frontend('theme', array('edit', 'details'), array('refresh', 'export', 'delete'));
  331. break;
  332. case 'imageset':
  333. switch ($action)
  334. {
  335. case 'refresh':
  336. $sql = 'SELECT *
  337. FROM ' . STYLES_IMAGESET_TABLE . "
  338. WHERE imageset_id = $style_id";
  339. $result = $db->sql_query($sql);
  340. $imageset_row = $db->sql_fetchrow($result);
  341. $db->sql_freeresult($result);
  342. if (!$imageset_row)
  343. {
  344. trigger_error($user->lang['NO_IMAGESET'] . adm_back_link($this->u_action), E_USER_WARNING);
  345. }
  346. if (confirm_box(true))
  347. {
  348. $sql_ary = array();
  349. $imageset_definitions = array();
  350. foreach ($this->imageset_keys as $topic => $key_array)
  351. {
  352. $imageset_definitions = array_merge($imageset_definitions, $key_array);
  353. }
  354. $cfg_data_imageset = parse_cfg_file("{$phpbb_root_path}styles/{$imageset_row['imageset_path']}/imageset/imageset.cfg");
  355. $db->sql_transaction('begin');
  356. $sql = 'DELETE FROM ' . STYLES_IMAGESET_DATA_TABLE . '
  357. WHERE imageset_id = ' . $style_id;
  358. $result = $db->sql_query($sql);
  359. foreach ($cfg_data_imageset as $image_name => $value)
  360. {
  361. if (strpos($value, '*') !== false)
  362. {
  363. if (substr($value, -1, 1) === '*')
  364. {
  365. list($image_filename, $image_height) = explode('*', $value);
  366. $image_width = 0;
  367. }
  368. else
  369. {
  370. list($image_filename, $image_height, $image_width) = explode('*', $value);
  371. }
  372. }
  373. else
  374. {
  375. $image_filename = $value;
  376. $image_height = $image_width = 0;
  377. }
  378. if (strpos($image_name, 'img_') === 0 && $image_filename)
  379. {
  380. $image_name = substr($image_name, 4);
  381. if (in_array($image_name, $imageset_definitions))
  382. {
  383. $sql_ary[] = array(
  384. 'image_name' => (string) $image_name,
  385. 'image_filename' => (string) $image_filename,
  386. 'image_height' => (int) $image_height,
  387. 'image_width' => (int) $image_width,
  388. 'imageset_id' => (int) $style_id,
  389. 'image_lang' => '',
  390. );
  391. }
  392. }
  393. }
  394. $sql = 'SELECT lang_dir
  395. FROM ' . LANG_TABLE;
  396. $result = $db->sql_query($sql);
  397. while ($row = $db->sql_fetchrow($result))
  398. {
  399. if (@file_exists("{$phpbb_root_path}styles/{$imageset_row['imageset_path']}/imageset/{$row['lang_dir']}/imageset.cfg"))
  400. {
  401. $cfg_data_imageset_data = parse_cfg_file("{$phpbb_root_path}styles/{$imageset_row['imageset_path']}/imageset/{$row['lang_dir']}/imageset.cfg");
  402. foreach ($cfg_data_imageset_data as $image_name => $value)
  403. {
  404. if (strpos($value, '*') !== false)
  405. {
  406. if (substr($value, -1, 1) === '*')
  407. {
  408. list($image_filename, $image_height) = explode('*', $value);
  409. $image_width = 0;
  410. }
  411. else
  412. {
  413. list($image_filename, $image_height, $image_width) = explode('*', $value);
  414. }
  415. }
  416. else
  417. {
  418. $image_filename = $value;
  419. $image_height = $image_width = 0;
  420. }
  421. if (strpos($image_name, 'img_') === 0 && $image_filename)
  422. {
  423. $image_name = substr($image_name, 4);
  424. if (in_array($image_name, $imageset_definitions))
  425. {
  426. $sql_ary[] = array(
  427. 'image_name' => (string) $image_name,
  428. 'image_filename' => (string) $image_filename,
  429. 'image_height' => (int) $image_height,
  430. 'image_width' => (int) $image_width,
  431. 'imageset_id' => (int) $style_id,
  432. 'image_lang' => (string) $row['lang_dir'],
  433. );
  434. }
  435. }
  436. }
  437. }
  438. }
  439. $db->sql_freeresult($result);
  440. $db->sql_multi_insert(STYLES_IMAGESET_DATA_TABLE, $sql_ary);
  441. $db->sql_transaction('commit');
  442. $cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE);
  443. $cache->destroy('imageset_site_logo_md5');
  444. add_log('admin', 'LOG_IMAGESET_REFRESHED', $imageset_row['imageset_name']);
  445. trigger_error($user->lang['IMAGESET_REFRESHED'] . adm_back_link($this->u_action));
  446. }
  447. else
  448. {
  449. confirm_box(false, $user->lang['CONFIRM_IMAGESET_REFRESH'], build_hidden_fields(array(
  450. 'i' => $id,
  451. 'mode' => $mode,
  452. 'action' => $action,
  453. 'id' => $style_id
  454. )));
  455. }
  456. break;
  457. }
  458. $this->frontend('imageset', array('edit', 'details'), array('refresh', 'export', 'delete'));
  459. break;
  460. }
  461. }
  462. /**
  463. * Build Frontend with supplied options
  464. */
  465. function frontend($mode, $options, $actions)
  466. {
  467. global $user, $template, $db, $config, $phpbb_root_path, $phpEx;
  468. $sql_from = '';
  469. $sql_sort = 'LOWER(' . $mode . '_name)';
  470. $style_count = array();
  471. switch ($mode)
  472. {
  473. case 'style':
  474. $sql_from = STYLES_TABLE;
  475. $sql_sort = 'style_active DESC, ' . $sql_sort;
  476. $sql = 'SELECT user_style, COUNT(user_style) AS style_count
  477. FROM ' . USERS_TABLE . '
  478. GROUP BY user_style';
  479. $result = $db->sql_query($sql);
  480. while ($row = $db->sql_fetchrow($result))
  481. {
  482. $style_count[$row['user_style']] = $row['style_count'];
  483. }
  484. $db->sql_freeresult($result);
  485. break;
  486. case 'template':
  487. $sql_from = STYLES_TEMPLATE_TABLE;
  488. break;
  489. case 'theme':
  490. $sql_from = STYLES_THEME_TABLE;
  491. break;
  492. case 'imageset':
  493. $sql_from = STYLES_IMAGESET_TABLE;
  494. break;
  495. default:
  496. trigger_error($user->lang['NO_MODE'] . adm_back_link($this->u_action), E_USER_WARNING);
  497. }
  498. $l_prefix = strtoupper($mode);
  499. $this->page_title = 'ACP_' . $l_prefix . 'S';
  500. $template->assign_vars(array(
  501. 'S_FRONTEND' => true,
  502. 'S_STYLE' => ($mode == 'style') ? true : false,
  503. 'L_TITLE' => $user->lang[$this->page_title],
  504. 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN'],
  505. 'L_NAME' => $user->lang[$l_prefix . '_NAME'],
  506. 'L_INSTALLED' => $user->lang['INSTALLED_' . $l_prefix],
  507. 'L_UNINSTALLED' => $user->lang['UNINSTALLED_' . $l_prefix],
  508. 'L_NO_UNINSTALLED' => $user->lang['NO_UNINSTALLED_' . $l_prefix],
  509. 'L_CREATE' => $user->lang['CREATE_' . $l_prefix],
  510. 'U_ACTION' => $this->u_action,
  511. )
  512. );
  513. $sql = "SELECT *
  514. FROM $sql_from
  515. ORDER BY $sql_sort ASC";
  516. $result = $db->sql_query($sql);
  517. $installed = array();
  518. $basis_options = '<option class="sep" value="">' . $user->lang['OPTIONAL_BASIS'] . '</option>';
  519. while ($row = $db->sql_fetchrow($result))
  520. {
  521. $installed[] = $row[$mode . '_name'];
  522. $basis_options .= '<option value="' . $row[$mode . '_id'] . '">' . $row[$mode . '_name'] . '</option>';
  523. $stylevis = ($mode == 'style' && !$row['style_active']) ? 'activate' : 'deactivate';
  524. $s_options = array();
  525. foreach ($options as $option)
  526. {
  527. $s_options[] = '<a href="' . $this->u_action . "&amp;action=$option&amp;id=" . $row[$mode . '_id'] . '">' . $user->lang[strtoupper($option)] . '</a>';
  528. }
  529. $s_actions = array();
  530. foreach ($actions as $option)
  531. {
  532. $s_actions[] = '<a href="' . $this->u_action . "&amp;action=$option&amp;id=" . $row[$mode . '_id'] . '">' . $user->lang[strtoupper($option)] . '</a>';
  533. }
  534. $template->assign_block_vars('installed', array(
  535. 'S_DEFAULT_STYLE' => ($mode == 'style' && $row['style_id'] == $config['default_style']) ? true : false,
  536. 'U_EDIT' => $this->u_action . '&amp;action=' . (($mode == 'style') ? 'details' : 'edit') . '&amp;id=' . $row[$mode . '_id'],
  537. 'U_STYLE_ACT_DEACT' => $this->u_action . '&amp;action=' . $stylevis . '&amp;id=' . $row[$mode . '_id'],
  538. 'L_STYLE_ACT_DEACT' => $user->lang['STYLE_' . strtoupper($stylevis)],
  539. 'S_OPTIONS' => implode(' | ', $s_options),
  540. 'S_ACTIONS' => implode(' | ', $s_actions),
  541. 'U_PREVIEW' => ($mode == 'style') ? append_sid("{$phpbb_root_path}index.$phpEx", "$mode=" . $row[$mode . '_id']) : '',
  542. 'NAME' => $row[$mode . '_name'],
  543. 'STYLE_COUNT' => ($mode == 'style' && isset($style_count[$row['style_id']])) ? $style_count[$row['style_id']] : 0,
  544. 'S_INACTIVE' => ($mode == 'style' && !$row['style_active']) ? true : false,
  545. )
  546. );
  547. }
  548. $db->sql_freeresult($result);
  549. // Grab uninstalled items
  550. $new_ary = $cfg = array();
  551. $dp = @opendir("{$phpbb_root_path}styles");
  552. if ($dp)
  553. {
  554. while (($file = readdir($dp)) !== false)
  555. {
  556. if ($file[0] == '.' || !is_dir($phpbb_root_path . 'styles/' . $file))
  557. {
  558. continue;
  559. }
  560. $subpath = ($mode != 'style') ? "$mode/" : '';
  561. if (file_exists("{$phpbb_root_path}styles/$file/$subpath$mode.cfg"))
  562. {
  563. if ($cfg = file("{$phpbb_root_path}styles/$file/$subpath$mode.cfg"))
  564. {
  565. $items = parse_cfg_file('', $cfg);
  566. $name = (isset($items['name'])) ? trim($items['name']) : false;
  567. if ($name && !in_array($name, $installed))
  568. {
  569. // The array key is used for sorting later on.
  570. // $file is appended because $name doesn't have to be unique.
  571. $new_ary[$name . $file] = array(
  572. 'path' => $file,
  573. 'name' => $name,
  574. 'copyright' => $items['copyright'],
  575. );
  576. }
  577. }
  578. }
  579. }
  580. closedir($dp);
  581. }
  582. unset($installed);
  583. if (sizeof($new_ary))
  584. {
  585. ksort($new_ary);
  586. foreach ($new_ary as $cfg)
  587. {
  588. $template->assign_block_vars('uninstalled', array(
  589. 'NAME' => $cfg['name'],
  590. 'COPYRIGHT' => $cfg['copyright'],
  591. 'U_INSTALL' => $this->u_action . '&amp;action=install&amp;path=' . urlencode($cfg['path']))
  592. );
  593. }
  594. }
  595. unset($new_ary);
  596. $template->assign_vars(array(
  597. 'S_BASIS_OPTIONS' => $basis_options)
  598. );
  599. }
  600. /**
  601. * Provides a template editor which allows saving changes to template files on the filesystem or in the database.
  602. *
  603. * @param int $template_id specifies which template set is being edited
  604. */
  605. function edit_template($template_id)
  606. {
  607. global $phpbb_root_path, $phpEx, $config, $db, $cache, $user, $template, $safe_mode;
  608. if (defined('PHPBB_DISABLE_ACP_EDITOR'))
  609. {
  610. trigger_error($user->lang['EDITOR_DISABLED'] . adm_back_link($this->u_action));
  611. }
  612. $this->page_title = 'EDIT_TEMPLATE';
  613. $filelist = $filelist_cats = array();
  614. $template_data = utf8_normalize_nfc(request_var('template_data', '', true));
  615. $template_data = htmlspecialchars_decode($template_data);
  616. $template_file = utf8_normalize_nfc(request_var('template_file', '', true));
  617. $text_rows = max(5, min(999, request_var('text_rows', 20)));
  618. $save_changes = (isset($_POST['save'])) ? true : false;
  619. // make sure template_file path doesn't go upwards
  620. $template_file = preg_replace('#\.{2,}#', '.', $template_file);
  621. // Retrieve some information about the template
  622. $sql = 'SELECT template_storedb, template_path, template_name
  623. FROM ' . STYLES_TEMPLATE_TABLE . "
  624. WHERE template_id = $template_id";
  625. $result = $db->sql_query($sql);
  626. $template_info = $db->sql_fetchrow($result);
  627. $db->sql_freeresult($result);
  628. if (!$template_info)
  629. {
  630. trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING);
  631. }
  632. if ($save_changes && !check_form_key('acp_styles'))
  633. {
  634. trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
  635. }
  636. else if (!$save_changes)
  637. {
  638. add_form_key('acp_styles');
  639. }
  640. // save changes to the template if the user submitted any
  641. if ($save_changes && $template_file)
  642. {
  643. // Get the filesystem location of the current file
  644. $file = "{$phpbb_root_path}styles/{$template_info['template_path']}/template/$template_file";
  645. $additional = '';
  646. // If the template is stored on the filesystem try to write the file else store it in the database
  647. if (!$safe_mode && !$template_info['template_storedb'] && file_exists($file) && phpbb_is_writable($file))
  648. {
  649. if (!($fp = @fopen($file, 'wb')))
  650. {
  651. // File exists and is writeable, but still not able to be written to
  652. trigger_error(sprintf($user->lang['TEMPLATE_FILE_NOT_WRITABLE'], htmlspecialchars($template_file)) . adm_back_link($this->u_action), E_USER_WARNING);
  653. }
  654. fwrite($fp, $template_data);
  655. fclose($fp);
  656. }
  657. else
  658. {
  659. $db->sql_transaction('begin');
  660. // If it's not stored in the db yet, then update the template setting and store all template files in the db
  661. if (!$template_info['template_storedb'])
  662. {
  663. if ($super = $this->get_super('template', $template_id))
  664. {
  665. $this->store_in_db('template', $super['template_id']);
  666. }
  667. else
  668. {
  669. $this->store_in_db('template', $template_id);
  670. }
  671. add_log('admin', 'LOG_TEMPLATE_EDIT_DETAILS', $template_info['template_name']);
  672. $additional .= '<br />' . $user->lang['EDIT_TEMPLATE_STORED_DB'];
  673. }
  674. // Update the template_data table entry for this template file
  675. $sql = 'UPDATE ' . STYLES_TEMPLATE_DATA_TABLE . "
  676. SET template_data = '" . $db->sql_escape($template_data) . "', template_mtime = " . time() . "
  677. WHERE template_id = $template_id
  678. AND template_filename = '" . $db->sql_escape($template_file) . "'";
  679. $db->sql_query($sql);
  680. $db->sql_transaction('commit');
  681. }
  682. // destroy the cached version of the template (filename without extension)
  683. $this->clear_template_cache($template_info, array(substr($template_file, 0, -5)));
  684. $cache->destroy('sql', STYLES_TABLE);
  685. add_log('admin', 'LOG_TEMPLATE_EDIT', $template_info['template_name'], $template_file);
  686. trigger_error($user->lang['TEMPLATE_FILE_UPDATED'] . $additional . adm_back_link($this->u_action . "&amp;action=edit&amp;id=$template_id&amp;text_rows=$text_rows&amp;template_file=$template_file"));
  687. }
  688. // Generate a category array containing template filenames
  689. if (!$template_info['template_storedb'])
  690. {
  691. $template_path = "{$phpbb_root_path}styles/{$template_info['template_path']}/template";
  692. $filelist = filelist($template_path, '', 'html');
  693. $filelist[''] = array_diff($filelist[''], array('bbcode.html'));
  694. if ($template_file)
  695. {
  696. if (!file_exists($template_path . "/$template_file") || !($template_data = file_get_contents($template_path . "/$template_file")))
  697. {
  698. trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING);
  699. }
  700. }
  701. }
  702. else
  703. {
  704. $sql = 'SELECT *
  705. FROM ' . STYLES_TEMPLATE_DATA_TABLE . "
  706. WHERE template_id = $template_id";
  707. $result = $db->sql_query($sql);
  708. $filelist = array('' => array());
  709. while ($row = $db->sql_fetchrow($result))
  710. {
  711. $file_info = pathinfo($row['template_filename']);
  712. if (($file_info['basename'] != 'bbcode') && ($file_info['extension'] == 'html'))
  713. {
  714. if (($file_info['dirname'] == '.') || empty($file_info['dirname']))
  715. {
  716. $filelist[''][] = $row['template_filename'];
  717. }
  718. else
  719. {
  720. $filelist[$file_info['dirname'] . '/'][] = $file_info['basename'];
  721. }
  722. }
  723. if ($row['template_filename'] == $template_file)
  724. {
  725. $template_data = $row['template_data'];
  726. }
  727. }
  728. $db->sql_freeresult($result);
  729. unset($file_info);
  730. }
  731. if (empty($filelist['']))
  732. {
  733. trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING);
  734. }
  735. // Now create the categories
  736. $filelist_cats[''] = array();
  737. foreach ($filelist as $pathfile => $file_ary)
  738. {
  739. // Use the directory name as category name
  740. if (!empty($pathfile))
  741. {
  742. $filelist_cats[$pathfile] = array();
  743. foreach ($file_ary as $file)
  744. {
  745. $filelist_cats[$pathfile][$pathfile . $file] = $file;
  746. }
  747. }
  748. // or if it's in the main category use the word before the first underscore to group files
  749. else
  750. {
  751. $cats = array();
  752. foreach ($file_ary as $file)
  753. {
  754. $cats[] = substr($file, 0, strpos($file, '_'));
  755. $filelist_cats[substr($file, 0, strpos($file, '_'))][$file] = $file;
  756. }
  757. $cats = array_values(array_unique($cats));
  758. // we don't need any single element categories so put them into the misc '' category
  759. for ($i = 0, $n = sizeof($cats); $i < $n; $i++)
  760. {
  761. if (sizeof($filelist_cats[$cats[$i]]) == 1 && $cats[$i] !== '')
  762. {
  763. $filelist_cats[''][key($filelist_cats[$cats[$i]])] = current($filelist_cats[$cats[$i]]);
  764. unset($filelist_cats[$cats[$i]]);
  765. }
  766. }
  767. unset($cats);
  768. }
  769. }
  770. unset($filelist);
  771. // Generate list of categorised template files
  772. $tpl_options = '';
  773. ksort($filelist_cats);
  774. foreach ($filelist_cats as $category => $tpl_ary)
  775. {
  776. ksort($tpl_ary);
  777. if (!empty($category))
  778. {
  779. $tpl_options .= '<option class="sep" value="">' . $category . '</option>';
  780. }
  781. foreach ($tpl_ary as $filename => $file)
  782. {
  783. $selected = ($template_file == $filename) ? ' selected="selected"' : '';
  784. $tpl_options .= '<option value="' . $filename . '"' . $selected . '>' . $file . '</option>';
  785. }
  786. }
  787. $template->assign_vars(array(
  788. 'S_EDIT_TEMPLATE' => true,
  789. 'S_HIDDEN_FIELDS' => build_hidden_fields(array('template_file' => $template_file)),
  790. 'S_TEMPLATES' => $tpl_options,
  791. 'U_ACTION' => $this->u_action . "&amp;action=edit&amp;id=$template_id&amp;text_rows=$text_rows",
  792. 'U_BACK' => $this->u_action,
  793. 'L_EDIT' => $user->lang['EDIT_TEMPLATE'],
  794. 'L_EDIT_EXPLAIN' => $user->lang['EDIT_TEMPLATE_EXPLAIN'],
  795. 'L_EDITOR' => $user->lang['TEMPLATE_EDITOR'],
  796. 'L_EDITOR_HEIGHT' => $user->lang['TEMPLATE_EDITOR_HEIGHT'],
  797. 'L_FILE' => $user->lang['TEMPLATE_FILE'],
  798. 'L_SELECT' => $user->lang['SELECT_TEMPLATE'],
  799. 'L_SELECTED' => $user->lang['SELECTED_TEMPLATE'],
  800. 'L_SELECTED_FILE' => $user->lang['SELECTED_TEMPLATE_FILE'],
  801. 'SELECTED_TEMPLATE' => $template_info['template_name'],
  802. 'TEMPLATE_FILE' => $template_file,
  803. 'TEMPLATE_DATA' => utf8_htmlspecialchars($template_data),
  804. 'TEXT_ROWS' => $text_rows)
  805. );
  806. }
  807. /**
  808. * Allows the admin to view cached versions of template files and clear single template cache files
  809. *
  810. * @param int $template_id specifies which template's cache is shown
  811. */
  812. function template_cache($template_id)
  813. {
  814. global $phpbb_root_path, $phpEx, $config, $db, $cache, $user, $template;
  815. $source = str_replace('/', '.', request_var('source', ''));
  816. $file_ary = array_diff(request_var('delete', array('')), array(''));
  817. $submit = isset($_POST['submit']) ? true : false;
  818. $sql = 'SELECT *
  819. FROM ' . STYLES_TEMPLATE_TABLE . "
  820. WHERE template_id = $template_id";
  821. $result = $db->sql_query($sql);
  822. $template_row = $db->sql_fetchrow($result);
  823. $db->sql_freeresult($result);
  824. if (!$template_row)
  825. {
  826. trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING);
  827. }
  828. // User wants to delete one or more files ...
  829. if ($submit && $file_ary)
  830. {
  831. $this->clear_template_cache($template_row, $file_ary);
  832. trigger_error($user->lang['TEMPLATE_CACHE_CLEARED'] . adm_back_link($this->u_action . "&amp;action=cache&amp;id=$template_id"));
  833. }
  834. $cache_prefix = 'tpl_' . str_replace('_', '-', $template_row['template_path']);
  835. // Someone wants to see the cached source ... so we'll highlight it,
  836. // add line numbers and indent it appropriately. This could be nasty
  837. // on larger source files ...
  838. if ($source && file_exists("{$phpbb_root_path}cache/{$cache_prefix}_$source.html.$phpEx"))
  839. {
  840. adm_page_header($user->lang['TEMPLATE_CACHE']);
  841. $template->set_filenames(array(
  842. 'body' => 'viewsource.html')
  843. );
  844. $template->assign_vars(array(
  845. 'FILENAME' => str_replace('.', '/', $source) . '.html')
  846. );
  847. $code = str_replace(array("\r\n", "\r"), array("\n", "\n"), file_get_contents("{$phpbb_root_path}cache/{$cache_prefix}_$source.html.$phpEx"));
  848. $conf = array('highlight.bg', 'highlight.comment', 'highlight.default', 'highlight.html', 'highlight.keyword', 'highlight.string');
  849. foreach ($conf as $ini_var)
  850. {
  851. @ini_set($ini_var, str_replace('highlight.', 'syntax', $ini_var));
  852. }
  853. $marker = 'MARKER' . time();
  854. $code = highlight_string(str_replace("\n", $marker, $code), true);
  855. $code = str_replace($marker, "\n", $code);
  856. $str_from = array('<span style="color: ', '<font color="syntax', '</font>', '<code>', '</code>','[', ']', '.', ':');
  857. $str_to = array('<span class="', '<span class="syntax', '</span>', '', '', '&#91;', '&#93;', '&#46;', '&#58;');
  858. $code = str_replace($str_from, $str_to, $code);
  859. $code = preg_replace('#^(<span class="[a-z_]+">)\n?(.*?)\n?(</span>)$#ism', '$1$2$3', $code);
  860. $code = substr($code, strlen('<span class="syntaxhtml">'));
  861. $code = substr($code, 0, -1 * strlen('</ span>'));
  862. $code = explode("\n", $code);
  863. foreach ($code as $key => $line)
  864. {
  865. $template->assign_block_vars('source', array(
  866. 'LINENUM' => $key + 1,
  867. 'LINE' => preg_replace('#([^ ;])&nbsp;([^ &])#', '$1 $2', $line))
  868. );
  869. unset($code[$key]);
  870. }
  871. adm_page_footer();
  872. }
  873. $filemtime = array();
  874. if ($template_row['template_storedb'])
  875. {
  876. $ids = array();
  877. if (isset($template_row['template_inherits_id']) && $template_row['template_inherits_id'])
  878. {
  879. $ids[] = $template_row['template_inherits_id'];
  880. }
  881. $ids[] = $template_row['template_id'];
  882. $filemtime = array();
  883. $file_template_db = array();
  884. foreach ($ids as $id)
  885. {
  886. $sql = 'SELECT template_filename, template_mtime
  887. FROM ' . STYLES_TEMPLATE_DATA_TABLE . "
  888. WHERE template_id = $id";
  889. $result = $db->sql_query($sql);
  890. while ($row = $db->sql_fetchrow($result))
  891. {
  892. $filemtime[$row['template_filename']] = $row['template_mtime'];
  893. $file_template_db[$row['template_filename']] = $id;
  894. }
  895. $db->sql_freeresult($result);
  896. }
  897. }
  898. // Get a list of cached template files and then retrieve additional information about them
  899. $file_ary = $this->template_cache_filelist($template_row['template_path']);
  900. foreach ($file_ary as $file)
  901. {
  902. $file = str_replace('/', '.', $file);
  903. // perform some dirty guessing to get the path right.
  904. // We assume that three dots in a row were '../'
  905. $tpl_file = str_replace('.', '/', $file);
  906. $tpl_file = str_replace('///', '../', $tpl_file);
  907. $filename = "{$cache_prefix}_$file.html.$phpEx";
  908. if (!file_exists("{$phpbb_root_path}cache/$filename"))
  909. {
  910. continue;
  911. }
  912. $file_tpl = "{$phpbb_root_path}styles/{$template_row['template_path']}/template/$tpl_file.html";
  913. $inherited = false;
  914. if (isset($template_row['template_inherits_id']) && $template_row['template_inherits_id'])
  915. {
  916. if (!$template_row['template_storedb'])
  917. {
  918. if (!file_exists($file_tpl))
  919. {
  920. $file_tpl = "{$phpbb_root_path}styles/{$template_row['template_inherit_path']}/template/$tpl_file.html";
  921. $inherited = true;
  922. }
  923. }
  924. else
  925. {
  926. if ($file_template_db[$file . '.html'] == $template_row['template_inherits_id'])
  927. {
  928. $file_tpl = "{$phpbb_root_path}styles/{$template_row['template_inherit_path']}/template/$tpl_file.html";
  929. $inherited = true;
  930. }
  931. }
  932. }
  933. // Correct the filename if it is stored in database and the file is in a subfolder.
  934. if ($template_row['template_storedb'])
  935. {
  936. $file = str_replace('.', '/', $file);
  937. }
  938. $template->assign_block_vars('file', array(
  939. 'U_VIEWSOURCE' => $this->u_action . "&amp;action=cache&amp;id=$template_id&amp;source=$file",
  940. 'CACHED' => $user->format_date(filemtime("{$phpbb_root_path}cache/$filename")),
  941. 'FILENAME' => $file,
  942. 'FILENAME_PATH' => $file_tpl,
  943. 'FILESIZE' => get_formatted_filesize(filesize("{$phpbb_root_path}cache/$filename")),
  944. 'MODIFIED' => $user->format_date((!$template_row['template_storedb']) ? filemtime($file_tpl) : $filemtime[$file . '.html']))
  945. );
  946. }
  947. unset($filemtime);
  948. $template->assign_vars(array(
  949. 'S_CACHE' => true,
  950. 'S_TEMPLATE' => true,
  951. 'U_ACTION' => $this->u_action . "&amp;action=cache&amp;id=$template_id",
  952. 'U_BACK' => $this->u_action)
  953. );
  954. }
  955. /**
  956. * Provides a css editor and a basic easier to use stylesheet editing tool for less experienced (or lazy) users
  957. *
  958. * @param int $theme_id specifies which theme is being edited
  959. */
  960. function edit_theme($theme_id)
  961. {
  962. global $phpbb_root_path, $phpEx, $config, $db, $cache, $user, $template, $safe_mode;
  963. $this->page_title = 'EDIT_THEME';
  964. $filelist = $filelist_cats = array();
  965. $theme_data = utf8_normalize_nfc(request_var('template_data', '', true));
  966. $theme_data = htmlspecialchars_decode($theme_data);
  967. $theme_file = utf8_normalize_nfc(request_var('template_file', '', true));
  968. $text_rows = max(5, min(999, request_var('text_rows', 20)));
  969. $save_changes = (isset($_POST['save'])) ? true : false;
  970. // make sure theme_file path doesn't go upwards
  971. $theme_file = str_replace('..', '.', $theme_file);
  972. // Retrieve some information about the theme
  973. $sql = 'SELECT theme_storedb, theme_path, theme_name, theme_data
  974. FROM ' . STYLES_THEME_TABLE . "
  975. WHERE theme_id = $theme_id";
  976. $result = $db->sql_query($sql);
  977. if (!($theme_info = $db->sql_fetchrow($result)))
  978. {
  979. trigger_error($user->lang['NO_THEME'] . adm_back_link($this->u_action), E_USER_WARNING);
  980. }
  981. $db->sql_freeresult($result);
  982. // save changes to the theme if the user submitted any
  983. if ($save_changes)
  984. {
  985. // Get the filesystem location of the current file
  986. $file = "{$phpbb_root_path}styles/{$theme_info['theme_path']}/theme/$theme_file";
  987. $additional = '';
  988. $message = $user->lang['THEME_UPDATED'];
  989. // If the theme is stored on the filesystem try to write the file else store it in the database
  990. if (!$safe_mode && !$theme_info['theme_storedb'] && file_exists($file) && phpbb_is_writable($file))
  991. {
  992. if (!($fp = @fopen($file, 'wb')))
  993. {
  994. trigger_error($user->lang['NO_THEME'] . adm_back_link($this->u_action), E_USER_WARNING);
  995. }
  996. fwrite($fp, $theme_data);
  997. fclose($fp);
  998. }
  999. else
  1000. {
  1001. // Write stylesheet to db
  1002. $sql_ary = array(
  1003. 'theme_mtime' => time(),
  1004. 'theme_storedb' => 1,
  1005. 'theme_data' => $this->db_theme_data($theme_info, $theme_data),
  1006. );
  1007. $sql = 'UPDATE ' . STYLES_THEME_TABLE . '
  1008. SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
  1009. WHERE theme_id = ' . $theme_id;
  1010. $db->sql_query($sql);
  1011. $cache->destroy('sql', STYLES_THEME_TABLE);
  1012. // notify the user if the theme was not stored in the db before his modification
  1013. if (!$theme_info['theme_storedb'])
  1014. {
  1015. add_log('admin', 'LOG_THEME_EDIT_DETAILS', $theme_info['theme_name']);
  1016. $message .= '<br />' . $user->lang['EDIT_THEME_STORED_DB'];
  1017. }
  1018. }
  1019. $cache->destroy('sql', STYLES_THEME_TABLE);
  1020. add_log('admin', (!$theme_info['theme_storedb']) ? 'LOG_THEME_EDIT_FILE' : 'LOG_THEME_EDIT', $theme_info['theme_name'], (!$theme_info['theme_storedb']) ? $theme_file : '');
  1021. trigger_error($message . adm_back_link($this->u_action . "&amp;action=edit&amp;id=$theme_id&amp;template_file=$theme_file&amp;text_rows=$text_rows"));
  1022. }
  1023. // Generate a category array containing theme filenames
  1024. if (!$theme_info['theme_storedb'])
  1025. {
  1026. $theme_path = "{$phpbb_root_path}styles/{$theme_info['theme_path']}/theme";
  1027. $filelist = filelist($theme_path, '', 'css');
  1028. if ($theme_file)
  1029. {
  1030. if (!file_exists($theme_path . "/$theme_file") || !($theme_data = file_get_contents($theme_path . "/$theme_file")))
  1031. {
  1032. trigger_error($user->lang['NO_THEME'] . adm_back_link($this->u_action), E_USER_WARNING);
  1033. }
  1034. }
  1035. }
  1036. else
  1037. {
  1038. $theme_data = &$theme_info['theme_data'];
  1039. }
  1040. // Now create the categories
  1041. $filelist_cats[''] = array();
  1042. foreach ($filelist as $pathfile => $file_ary)
  1043. {
  1044. // Use the directory name as category name
  1045. if (!empty($pathfile))
  1046. {
  1047. $filelist_cats[$pathfile] = array();
  1048. foreach ($file_ary as $file)
  1049. {
  1050. $filelist_cats[$pathfile][$pathfile . $file] = $file;
  1051. }
  1052. }
  1053. // or if it's in the main category use the word before the first underscore to group files
  1054. else
  1055. {
  1056. $cats = array();
  1057. foreach ($file_ary as $file)
  1058. {
  1059. $cats[] = substr($file, 0, strpos($file, '_'));
  1060. $filelist_cats[substr($file, 0, strpos($file, '_'))][$file] = $file;
  1061. }
  1062. $cats = array_values(array_unique($cats));
  1063. // we don't need any single element categories so put them into the misc '' category
  1064. for ($i = 0, $n = sizeof($cats); $i < $n; $i++)
  1065. {
  1066. if (sizeof($filelist_cats[$cats[$i]]) == 1 && $cats[$i] !== '')
  1067. {
  1068. $filelist_cats[''][key($filelist_cats[$cats[$i]])] = current($filelist_cats[$cats[$i]]);
  1069. unset($filelist_cats[$cats[$i]]);
  1070. }
  1071. }
  1072. unset($cats);
  1073. }
  1074. }
  1075. unset($filelist);
  1076. // Generate list of categorised theme files
  1077. $tpl_options = '';
  1078. ksort($filelist_cats);
  1079. foreach ($filelist_cats as $category => $tpl_ary)
  1080. {
  1081. ksort($tpl_ary);
  1082. if (!empty($category))
  1083. {
  1084. $tpl_options .= '<option class="sep" value="">' . $category . '</option>';
  1085. }
  1086. foreach ($tpl_ary as $filename => $file)
  1087. {
  1088. $selected = ($theme_file == $filename) ? ' selected="selected"' : '';
  1089. $tpl_options .= '<option value="' . $filename . '"' . $selected . '>' . $file . '</option>';
  1090. }
  1091. }
  1092. $template->assign_vars(array(
  1093. 'S_EDIT_THEME' => true,
  1094. 'S_HIDDEN_FIELDS' => build_hidden_fields(array('template_file' => $theme_file)),
  1095. 'S_THEME_IN_DB' => $theme_info['theme_storedb'],
  1096. 'S_TEMPLATES' => $tpl_options,
  1097. 'U_ACTION' => $this->u_action . "&amp;action=edit&amp;id=$theme_id&amp;text_rows=$text_rows",
  1098. 'U_BACK' => $this->u_action,
  1099. 'L_EDIT' => $user->lang['EDIT_THEME'],
  1100. 'L_EDIT_EXPLAIN' => $user->lang['EDIT_THEME_EXPLAIN'],
  1101. 'L_EDITOR' => $user->lang['THEME_EDITOR'],
  1102. 'L_EDITOR_HEIGHT' => $user->lang['THEME_EDITOR_HEIGHT'],
  1103. 'L_FILE' => $user->lang['THEME_FILE'],
  1104. 'L_SELECT' => $user->lang['SELECT_THEME'],
  1105. 'L_SELECTED' => $user->lang['SELECTED_THEME'],
  1106. 'L_SELECTED_FILE' => $user->lang['SELECTED_THEME_FILE'],
  1107. 'SELECTED_TEMPLATE' => $theme_info['theme_name'],
  1108. 'TEMPLATE_FILE' => $theme_file,
  1109. 'TEMPLATE_DATA' => utf8_htmlspecialchars($theme_data),
  1110. 'TEXT_ROWS' => $text_rows)
  1111. );
  1112. }
  1113. /**
  1114. * Edit imagesets
  1115. *
  1116. * @param int $imageset_id specifies which imageset is being edited
  1117. */
  1118. function edit_imageset($imageset_id)
  1119. {
  1120. global $db, $user, $phpbb_root_path, $cache, $template;
  1121. $this->page_title = 'EDIT_IMAGESET';
  1122. if (!$imageset_id)
  1123. {
  1124. trigger_error($user->lang['NO_IMAGESET'] . adm_back_link($this->u_action), E_USER_WARNING);
  1125. }
  1126. $update = (isset($_POST['update'])) ? true : false;
  1127. $imgname = request_var('imgname', 'site_logo');
  1128. $imgname = preg_replace('#[^a-z0-9\-+_]#i', '', $imgname);
  1129. $sql_extra = $imgnamelang = '';
  1130. $sql = 'SELECT imageset_path, imageset_name
  1131. FROM ' . STYLES_IMAGESET_TABLE . "
  1132. WHERE imageset_id = $imageset_id";
  1133. $result = $db->sql_query($sql);
  1134. $imageset_row = $db->sql_fetchrow($result);
  1135. $db->sql_freeresult($result);
  1136. if (!$imageset_row)
  1137. {
  1138. trigger_error($user->lang['NO_IMAGESET'] . adm_back_link($this->u_action), E_USER_WARNING);
  1139. }
  1140. $imageset_path = $imageset_row['imageset_path'];
  1141. $imageset_name = $imageset_row['imageset_name'];
  1142. if (strpos($imgname, '-') !== false)
  1143. {
  1144. list($imgname, $imgnamelang) = explode('-', $imgname);
  1145. $sql_extra = " AND image_lang IN ('" . $db->sql_escape($imgnamelang) . "', '')";
  1146. }
  1147. $sql = 'SELECT image_filename, image_width, image_height, image_lang, image_id
  1148. FROM ' . STYLES_IMAGESET_DATA_TABLE . "
  1149. WHERE imageset_id = $imageset_id
  1150. AND image_name = '" . $db->sql_escape($imgname) . "'$sql_extra";
  1151. $result = $db->sql_query($sql);
  1152. $imageset_data_row = $db->sql_fetchrow($result);
  1153. $db->sql_freeresult($result);
  1154. $image_filename = $imageset_data_row['image_filename'];
  1155. $image_width = $imageset_data_row['image_width'];
  1156. $image_height = $imageset_data_row['image_height'];
  1157. $image_lang = $imageset_data_row['image_lang'];
  1158. $image_id = $imageset_data_row['image_id'];
  1159. $imgsize = ($imageset_data_row['image_width'] && $imageset_data_row['image_height']) ? 1 : 0;
  1160. // Check to see whether the selected image exists in the table
  1161. $valid_name = ($update) ? false : true;
  1162. foreach ($this->imageset_keys as $category => $img_ary)
  1163. {
  1164. if (in_array($imgname, $img_ary))
  1165. {
  1166. $valid_name = true;
  1167. break;
  1168. }
  1169. }
  1170. if ($update && isset($_POST['imgpath']) && $valid_name)
  1171. {
  1172. // If imgwidth and imgheight are non-zero grab the actual size
  1173. // from the image itself ... we ignore width settings for the poll center image
  1174. $imgwidth = request_var('imgwidth', 0);
  1175. $imgheight = request_var('imgheight', 0);
  1176. $imgsize = request_var('imgsize', 0);
  1177. $imgpath = request_var('imgpath', '');
  1178. $imgpath = str_replace('..', '.', $imgpath);
  1179. // If no dimensions selected, we reset width and height to 0 ;)
  1180. if (!$imgsize)
  1181. {
  1182. $imgwidth = $imgheight = 0;
  1183. }
  1184. $imglang = '';
  1185. if ($imgpath && !file_exists("{$phpbb_root_path}styles/$imageset_path/imageset/$imgpath"))
  1186. {
  1187. trigger_error($user->lang['NO_IMAGE_ERROR'] . adm_back_link($this->u_action), E_USER_WARNING);
  1188. }
  1189. // Determine width/height. If dimensions included and no width/height given, we detect them automatically...
  1190. if ($imgsize && $imgpath)
  1191. {
  1192. if (!$imgwidth || !$imgheight)
  1193. {
  1194. list($imgwidth_file, $imgheight_file) = getimagesize("{$phpbb_root_path}styles/$imageset_path/imageset/$imgpath");
  1195. $imgwidth = ($imgwidth) ? $imgwidth : $imgwidth_file;
  1196. $imgheight = ($imgheight) ? $imgheight : $imgheight_file;
  1197. }
  1198. $imgwidth = ($imgname != 'poll_center') ? (int) $imgwidth : 0;
  1199. $imgheight = (int) $imgheight;
  1200. }
  1201. if (strpos($imgpath, '/') !== false)
  1202. {
  1203. list($imglang, $imgfilename) = explode('/', $imgpath);
  1204. }
  1205. else
  1206. {
  1207. $imgfilename = $imgpath;
  1208. }
  1209. $sql_ary = array(
  1210. 'image_filename' => (string) $imgfilename,
  1211. 'image_width' => (int) $imgwidth,
  1212. 'image_height' => (int) $imgheight,
  1213. 'image_lang' => (string) $imglang,
  1214. );
  1215. // already exists
  1216. if ($imageset_data_row)
  1217. {
  1218. $sql = 'UPDATE ' . STYLES_IMAGESET_DATA_TABLE . '
  1219. SET ' . $db->sql_build_array('UPDATE', $sql_ary) . "
  1220. WHERE image_id = $image_id";
  1221. $db->sql_query($sql);
  1222. }
  1223. // does not exist
  1224. else if (!$imageset_data_row)
  1225. {
  1226. $sql_ary['image_name'] = $imgname;
  1227. $sql_ary['imageset_id'] = (int) $imageset_id;
  1228. $db->sql_query('INSERT INTO ' . STYLES_IMAGESET_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
  1229. }
  1230. $cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE);
  1231. add_log('admin', 'LOG_IMAGESET_EDIT', $imageset_name);
  1232. $template->assign_var('SUCCESS', true);
  1233. $image_filename = $imgfilename;
  1234. $image_width = $imgwidth;
  1235. $image_height = $imgheight;
  1236. $image_lang = $imglang;
  1237. }
  1238. $imglang = '';
  1239. $imagesetlist = array('nolang' => array(), 'lang' => array());
  1240. $langs = array();
  1241. $dir = "{$phpbb_root_path}styles/$imageset_path/imageset";
  1242. $dp = @opendir($dir);
  1243. if ($dp)
  1244. {
  1245. while (($file = readdir($dp)) !== false)
  1246. {
  1247. if ($file[0] != '.' && strtoupper($file) != 'CVS' && !is_file($dir . '/' . $file) && !is_link($dir . '/' . $file))
  1248. {
  1249. $langs[] = $file;
  1250. }
  1251. else if (preg_match('#\.(?:gif|jpg|png)$#', $file))
  1252. {
  1253. $imagesetlist['nolang'][] = $file;
  1254. }
  1255. }
  1256. if ($sql_extra)
  1257. {
  1258. $dp2 = @opendir("$dir/$imgnamelang");
  1259. if ($dp2)
  1260. {
  1261. while (($file2 = readdir($dp2)) !== false)
  1262. {
  1263. if (preg_match('#\.(?:gif|jpg|png)$#', $file2))
  1264. {
  1265. $imagesetlist['lang'][] = "$imgnamelang/$file2";
  1266. }
  1267. }
  1268. closedir($dp2);
  1269. }
  1270. }
  1271. closedir($dp);
  1272. }
  1273. // Generate list of image options
  1274. $img_options = '';
  1275. foreach ($this->imageset_keys as $category => $img_ary)
  1276. {
  1277. $template->assign_block_vars('category', array(
  1278. 'NAME' => $user->lang['IMG_CAT_' . strtoupper($category)]
  1279. ));
  1280. foreach ($img_ary as $img)
  1281. {
  1282. if ($category == 'buttons')
  1283. {
  1284. foreach ($langs as $language)
  1285. {
  1286. $template->assign_block_vars('category.images', array(
  1287. 'SELECTED' => ($img == $imgname && $language == $imgnamelang),
  1288. 'VALUE' => $img . '-' . $language,
  1289. 'TEXT' => $user->lang['IMG_' . strtoupper($img)] . ' [ ' . $language . ' ]'
  1290. ));
  1291. }
  1292. }
  1293. else
  1294. {
  1295. $template->assign_block_vars('category.images', array(
  1296. 'SELECTED' => ($img == $imgname),
  1297. 'VALUE' => $img,
  1298. 'TEXT' => (($category == 'custom') ? $img : $user->lang['IMG_' . strtoupper($img)])
  1299. ));
  1300. }
  1301. }
  1302. }
  1303. // Make sure the list of possible images is sorted alphabetically
  1304. sort($imagesetlist['lang']);
  1305. sort($imagesetlist['nolang']);
  1306. $image_found = false;
  1307. $img_val = '';
  1308. foreach ($imagesetlist as $type => $img_ary)
  1309. {
  1310. if ($type !== 'lang' || $sql_extra)
  1311. {
  1312. $template->assign_block_vars('imagesetlist', array(
  1313. 'TYPE' => ($type == 'lang')
  1314. ));
  1315. }
  1316. foreach ($img_ary as $img)
  1317. {
  1318. $imgtext = preg_replace('/^([^\/]+\/)/', '', $img);
  1319. $selected = (!empty($imgname) && strpos($image_filename, $imgtext) !== false);
  1320. if ($selected)
  1321. {
  1322. $image_found = true;
  1323. $img_val = htmlspecialchars($img);
  1324. }
  1325. $template->assign_block_vars('imagesetlist.images', array(
  1326. 'SELECTED' => $selected,
  1327. 'TEXT' => $imgtext,
  1328. 'VALUE' => htmlspecialchars($img)
  1329. ));
  1330. }
  1331. }
  1332. $imgsize_bool = (!empty($imgname) && $image_width && $image_height) ? true : false;
  1333. $image_request = '../styles/' . $imageset_path . '/imageset/' . ($image_lang ? $imgnamelang . '/' : '') . $image_filename;
  1334. $template->assign_vars(array(
  1335. 'S_EDIT_IMAGESET' => true,
  1336. 'L_TITLE' => $user->lang[$this->page_title],
  1337. 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN'],
  1338. 'IMAGE_OPTIONS' => $img_options,
  1339. 'IMAGE_SIZE' => $image_width,
  1340. 'IMAGE_HEIGHT' => $image_height,
  1341. 'IMAGE_REQUEST' => (empty($image_filename)) ? 'images/no_image.png' : $image_request,
  1342. 'U_ACTION' => $this->u_action . "&amp;action=edit&amp;id=$imageset_id",
  1343. 'U_BACK' => $this->u_action,
  1344. 'NAME' => $imageset_name,
  1345. 'A_NAME' => addslashes($imageset_name),
  1346. 'PATH' => $imageset_path,
  1347. 'A_PATH' => addslashes($imageset_path),
  1348. 'ERROR' => !$valid_name,
  1349. 'IMG_SRC' => ($image_found) ? '../styles/' . $imageset_path . '/imageset/' . $img_val : 'images/no_image.png',
  1350. 'IMAGE_SELECT' => $image_found
  1351. ));
  1352. }
  1353. /**
  1354. * Remove style/template/theme/imageset
  1355. */
  1356. function remove($mode, $style_id)
  1357. {
  1358. global $db, $template, $user, $phpbb_root_path, $cache, $config;
  1359. $new_id = request_var('new_id', 0);
  1360. $update = (isset($_POST['update'])) ? true : false;
  1361. $sql_where = '';
  1362. switch ($mode)
  1363. {
  1364. case 'style':
  1365. $sql_from = STYLES_TABLE;
  1366. $sql_select = 'style_id, style_name, template_id, theme_id, imageset_id';
  1367. $sql_where = 'AND style_active = 1';
  1368. break;
  1369. case 'template':
  1370. $sql_from = STYLES_TEMPLATE_TABLE;
  1371. $sql_select = 'template_id, template_name, template_path, template_storedb';
  1372. break;
  1373. case 'theme':
  1374. $sql_from = STYLES_THEME_TABLE;
  1375. $sql_select = 'theme_id, theme_name, theme_path, theme_storedb';
  1376. break;
  1377. case 'imageset':
  1378. $sql_from = STYLES_IMAGESET_TABLE;
  1379. $sql_select = 'imageset_id, imageset_name, imageset_path';
  1380. break;
  1381. }
  1382. if ($mode === 'template' && ($conflicts = $this->check_inheritance($mode, $style_id)))
  1383. {
  1384. $l_type = strtoupper($mode);
  1385. $msg = $user->lang[$l_type . '_DELETE_DEPENDENT'];
  1386. foreach ($conflicts as $id => $values)
  1387. {
  1388. $msg .= '<br />' . $values['template_name'];
  1389. }
  1390. trigger_error($msg . adm_back_link($this->u_action), E_USER_WARNING);
  1391. }
  1392. $l_prefix = strtoupper($mode);
  1393. $sql = "SELECT $sql_select
  1394. FROM $sql_from
  1395. WHERE {$mode}_id = $style_id";
  1396. $result = $db->sql_query($sql);
  1397. $style_row = $db->sql_fetchrow($result);
  1398. $db->sql_freeresult($result);
  1399. if (!$style_row)
  1400. {
  1401. trigger_error($user->lang['NO_' . $l_prefix] . adm_back_link($this->u_action), E_USER_WARNING);
  1402. }
  1403. $s_only_component = $this->display_component_options($mode, $style_row[$mode . '_id'], $style_row);
  1404. if ($s_only_component)
  1405. {
  1406. trigger_error($user->lang['ONLY_' . $l_prefix] . adm_back_link($this->u_action), E_USER_WARNING);
  1407. }
  1408. if ($update)
  1409. {
  1410. if ($mode == 'style')
  1411. {
  1412. $sql = "DELETE FROM $sql_from
  1413. WHERE {$mode}_id = $style_id";
  1414. $db->sql_query($sql);
  1415. $sql = 'UPDATE ' . USERS_TABLE . "
  1416. SET user_style = $new_id
  1417. WHERE user_style = $style_id";
  1418. $db->sql_query($sql);
  1419. $sql = 'UPDATE ' . FORUMS_TABLE . "
  1420. SET forum_style = $new_id
  1421. WHERE forum_style = $style_id";
  1422. $db->sql_query($sql);
  1423. if ($style_id == $config['default_style'])
  1424. {
  1425. set_config('default_style', $new_id);
  1426. }
  1427. // Remove the components
  1428. $components = array('template', 'theme', 'imageset');
  1429. foreach ($components as $component)
  1430. {
  1431. $new_id = request_var('new_' . $component . '_id', 0);
  1432. $component_id = $style_row[$component . '_id'];
  1433. $this->remove_component($component, $component_id, $new_id, $style_id);
  1434. }
  1435. }
  1436. else
  1437. {
  1438. $this->remove_component($mode, $style_id, $new_id);
  1439. }
  1440. $cache->destroy('sql', STYLES_TABLE);
  1441. add_log('admin', 'LOG_' . $l_prefix . '_DELETE', $style_row[$mode . '_name']);
  1442. $message = ($mode != 'style') ? $l_prefix . '_DELETED_FS' : $l_prefix . '_DELETED';
  1443. trigger_error($user->lang[$message] . adm_back_link($this->u_action));
  1444. }
  1445. $this->page_title = 'DELETE_' . $l_prefix;
  1446. $template->assign_vars(array(
  1447. 'S_DELETE' => true,
  1448. 'L_TITLE' => $user->lang[$this->page_title],
  1449. 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN'],
  1450. 'L_NAME' => $user->lang[$l_prefix . '_NAME'],
  1451. 'L_REPLACE' => $user->lang['REPLACE_' . $l_prefix],
  1452. 'L_REPLACE_EXPLAIN' => $user->lang['REPLACE_' . $l_prefix . '_EXPLAIN'],
  1453. 'U_ACTION' => $this->u_action . "&amp;action=delete&amp;id=$style_id",
  1454. 'U_BACK' => $this->u_action,
  1455. 'NAME' => $style_row[$mode . '_name'],
  1456. )
  1457. );
  1458. if ($mode == 'style')
  1459. {
  1460. $template->assign_vars(array(
  1461. 'S_DELETE_STYLE' => true,
  1462. ));
  1463. }
  1464. }
  1465. /**
  1466. * Remove template/theme/imageset entry from the database
  1467. */
  1468. function remove_component($component, $component_id, $new_id, $style_id = false)
  1469. {
  1470. global $db;
  1471. if (($new_id == 0) || ($component === 'template' && ($conflicts = $this->check_inheritance($component, $component_id))))
  1472. {
  1473. // We can not delete the template, as the user wants to keep the component or an other template is inheriting from this one.
  1474. return;
  1475. }
  1476. $component_in_use = array();
  1477. if ($component != 'style')
  1478. {
  1479. $component_in_use = $this->component_in_use($component, $component_id, $style_id);
  1480. }
  1481. if (($new_id == -1) && !empty($component_in_use))
  1482. {
  1483. // We can not delete the component, as it is still in use
  1484. return;
  1485. }
  1486. if ($component == 'imageset')
  1487. {
  1488. $sql = 'DELETE FROM ' . STYLES_IMAGESET_DATA_TABLE . "
  1489. WHERE imageset_id = $component_id";
  1490. $db->sql_query($sql);
  1491. }
  1492. switch ($component)
  1493. {
  1494. case 'template':
  1495. $sql_from = STYLES_TEMPLATE_TABLE;
  1496. break;
  1497. case 'theme':
  1498. $sql_from = STYLES_THEME_TABLE;
  1499. break;
  1500. case 'imageset':
  1501. $sql_from = STYLES_IMAGESET_TABLE;;
  1502. break;
  1503. }
  1504. $sql = "DELETE FROM $sql_from
  1505. WHERE {$component}_id = $component_id";
  1506. $db->sql_query($sql);
  1507. $sql = 'UPDATE ' . STYLES_TABLE . "
  1508. SET {$component}_id = $new_id
  1509. WHERE {$component}_id = $component_id";
  1510. $db->sql_query($sql);
  1511. }
  1512. /**
  1513. * Display the options which can be used to replace a style/template/theme/imageset
  1514. *
  1515. * @return boolean Returns true if the component is the only component and can not be deleted.
  1516. */
  1517. function display_component_options($component, $component_id, $style_row = false, $style_id = false)
  1518. {
  1519. global $db, $template, $user;
  1520. $is_only_component = true;
  1521. $component_in_use = array();
  1522. if ($component != 'style')
  1523. {
  1524. $component_in_use = $this->component_in_use($component, $component_id, $style_id);
  1525. }
  1526. $sql_where = '';
  1527. switch ($component)
  1528. {
  1529. case 'style':
  1530. $sql_from = STYLES_TABLE;
  1531. $sql_where = 'WHERE style_active = 1';
  1532. break;
  1533. case 'template':
  1534. $sql_from = STYLES_TEMPLATE_TABLE;
  1535. $sql_where = 'WHERE template_inherits_id <> ' . $component_id;
  1536. break;
  1537. case 'theme':
  1538. $sql_from = STYLES_THEME_TABLE;
  1539. break;
  1540. case 'imageset':
  1541. $sql_from = STYLES_IMAGESET_TABLE;
  1542. break;
  1543. }
  1544. $s_options = '';
  1545. if (($component != 'style') && empty($component_in_use))
  1546. {
  1547. // If it is not in use, there must be another component
  1548. $is_only_component = false;
  1549. $sql = "SELECT {$component}_id, {$component}_name
  1550. FROM $sql_from
  1551. WHERE {$component}_id = {$component_id}";
  1552. $result = $db->sql_query($sql);
  1553. $row = $db->sql_fetchrow($result);
  1554. $db->sql_freeresult($result);
  1555. $s_options .= '<option value="-1" selected="selected">' . $user->lang['DELETE_' . strtoupper($component)] . '</option>';
  1556. $s_options .= '<option value="0">' . sprintf($user->lang['KEEP_' . strtoupper($component)], $row[$component . '_name']) . '</option>';
  1557. }
  1558. else
  1559. {
  1560. $sql = "SELECT {$component}_id, {$component}_name
  1561. FROM $sql_from
  1562. $sql_where
  1563. ORDER BY {$component}_name ASC";
  1564. $result = $db->sql_query($sql);
  1565. $s_keep_option = $s_options = '';
  1566. while ($row = $db->sql_fetchrow($result))
  1567. {
  1568. if ($row[$component . '_id'] != $component_id)
  1569. {
  1570. $is_only_component = false;
  1571. $s_options .= '<option value="' . $row[$component . '_id'] . '">' . sprintf($user->lang['REPLACE_WITH_OPTION'], $row[$component . '_name']) . '</option>';
  1572. }
  1573. else if ($component != 'style')
  1574. {
  1575. $s_keep_option = '<option value="0" selected="selected">' . sprintf($user->lang['KEEP_' . strtoupper($component)], $row[$component . '_name']) . '</option>';
  1576. }
  1577. }
  1578. $db->sql_freeresult($result);
  1579. $s_options = $s_keep_option . $s_options;
  1580. }
  1581. if (!$style_row)
  1582. {
  1583. $template->assign_var('S_REPLACE_' . strtoupper($component) . '_OPTIONS', $s_options);
  1584. }
  1585. else
  1586. {
  1587. $template->assign_var('S_REPLACE_OPTIONS', $s_options);
  1588. if ($component == 'style')
  1589. {
  1590. $components = array('template', 'theme', 'imageset');
  1591. foreach ($components as $component)
  1592. {
  1593. $this->display_component_options($component, $style_row[$component . '_id'], false, $component_id, true);
  1594. }
  1595. }
  1596. }
  1597. return $is_only_component;
  1598. }
  1599. /**
  1600. * Check whether the component is still used by another style or component
  1601. */
  1602. function component_in_use($component, $component_id, $style_id = false)
  1603. {
  1604. global $db;
  1605. $component_in_use = array();
  1606. if ($style_id)
  1607. {
  1608. $sql = 'SELECT style_id, style_name
  1609. FROM ' . STYLES_TABLE . "
  1610. WHERE {$component}_id = {$component_id}
  1611. AND style_id <> {$style_id}
  1612. ORDER BY style_name ASC";
  1613. }
  1614. else
  1615. {
  1616. $sql = 'SELECT style_id, style_name
  1617. FROM ' . STYLES_TABLE . "
  1618. WHERE {$component}_id = {$component_id}
  1619. ORDER BY style_name ASC";
  1620. }
  1621. $result = $db->sql_query($sql);
  1622. while ($row = $db->sql_fetchrow($result))
  1623. {
  1624. $component_in_use[] = $row['style_name'];
  1625. }
  1626. $db->sql_freeresult($result);
  1627. if ($component === 'template' && ($conflicts = $this->check_inheritance($component, $component_id)))
  1628. {
  1629. foreach ($conflicts as $temp_id => $conflict_data)
  1630. {
  1631. $component_in_use[] = $conflict_data['template_name'];
  1632. }
  1633. }
  1634. return $component_in_use;
  1635. }
  1636. /**
  1637. * Export style or style elements
  1638. */
  1639. function export($mode, $style_id)
  1640. {
  1641. global $db, $template, $user, $phpbb_root_path, $cache, $phpEx, $config;
  1642. $update = (isset($_POST['update'])) ? true : false;
  1643. $inc_template = request_var('inc_template', 0);
  1644. $inc_theme = request_var('inc_theme', 0);
  1645. $inc_imageset = request_var('inc_imageset', 0);
  1646. $store = request_var('store', 0);
  1647. $format = request_var('format', '');
  1648. $error = array();
  1649. $methods = array('tar');
  1650. $available_methods = array('tar.gz' => 'zlib', 'tar.bz2' => 'bz2', 'zip' => 'zlib');
  1651. foreach ($available_methods as $type => $module)
  1652. {
  1653. if (!@extension_loaded($module))
  1654. {
  1655. continue;
  1656. }
  1657. $methods[] = $type;
  1658. }
  1659. if (!in_array($format, $methods))
  1660. {
  1661. $format = 'tar';
  1662. }
  1663. switch ($mode)
  1664. {
  1665. case 'style':
  1666. if ($update && ($inc_template + $inc_theme + $inc_imageset) < 1)
  1667. {
  1668. $error[] = $user->lang['STYLE_ERR_MORE_ELEMENTS'];
  1669. }
  1670. $name = 'style_name';
  1671. $sql_select = 's.style_id, s.style_name, s.style_copyright';
  1672. $sql_select .= ($inc_template) ? ', t.*' : ', t.template_name';
  1673. $sql_select .= ($inc_theme) ? ', c.*' : ', c.theme_name';
  1674. $sql_select .= ($inc_imageset) ? ', i.*' : ', i.imageset_name';
  1675. $sql_from = STYLES_TABLE . ' s, ' . STYLES_TEMPLATE_TABLE . ' t, ' . STYLES_THEME_TABLE . ' c, ' . STYLES_IMAGESET_TABLE . ' i';
  1676. $sql_where = "s.style_id = $style_id AND t.template_id = s.template_id AND c.theme_id = s.theme_id AND i.imageset_id = s.imageset_id";
  1677. $l_prefix = 'STYLE';
  1678. break;
  1679. case 'template':
  1680. $name = 'template_name';
  1681. $sql_select = '*';
  1682. $sql_from = STYLES_TEMPLATE_TABLE;
  1683. $sql_where = "template_id = $style_id";
  1684. $l_prefix = 'TEMPLATE';
  1685. break;
  1686. case 'theme':
  1687. $name = 'theme_name';
  1688. $sql_select = '*';
  1689. $sql_from = STYLES_THEME_TABLE;
  1690. $sql_where = "theme_id = $style_id";
  1691. $l_prefix = 'THEME';
  1692. break;
  1693. case 'imageset':
  1694. $name = 'imageset_name';
  1695. $sql_select = '*';
  1696. $sql_from = STYLES_IMAGESET_TABLE;
  1697. $sql_where = "imageset_id = $style_id";
  1698. $l_prefix = 'IMAGESET';
  1699. break;
  1700. }
  1701. if ($update && !sizeof($error))
  1702. {
  1703. $sql = "SELECT $sql_select
  1704. FROM $sql_from
  1705. WHERE $sql_where";
  1706. $result = $db->sql_query($sql);
  1707. $style_row = $db->sql_fetchrow($result);
  1708. $db->sql_freeresult($result);
  1709. if (!$style_row)
  1710. {
  1711. trigger_error($user->lang['NO_' . $l_prefix] . adm_back_link($this->u_action), E_USER_WARNING);
  1712. }
  1713. $var_ary = array('style_id', 'style_name', 'style_copyright', 'template_id', 'template_name', 'template_path', 'template_copyright', 'template_storedb', 'template_inherits_id', 'bbcode_bitfield', 'theme_id', 'theme_name', 'theme_path', 'theme_copyright', 'theme_storedb', 'theme_mtime', 'theme_data', 'imageset_id', 'imageset_name', 'imageset_path', 'imageset_copyright');
  1714. foreach ($var_ary as $var)
  1715. {
  1716. if (!isset($style_row[$var]))
  1717. {
  1718. $style_row[$var] = '';
  1719. }
  1720. }
  1721. $files = $data = array();
  1722. if ($mode == 'style')
  1723. {
  1724. $style_cfg = str_replace(array('{MODE}', '{NAME}', '{COPYRIGHT}', '{VERSION}'), array($mode, $style_row['style_name'], $style_row['style_copyright'], $config['version']), $this->style_cfg);
  1725. $style_cfg .= (!$inc_template) ? "\nrequired_template = {$style_row['template_name']}" : '';
  1726. $style_cfg .= (!$inc_theme) ? "\nrequired_theme = {$style_row['theme_name']}" : '';
  1727. $style_cfg .= (!$inc_imageset) ? "\nrequired_imageset = {$style_row['imageset_name']}" : '';
  1728. $data[] = array(
  1729. 'src' => $style_cfg,
  1730. 'prefix' => 'style.cfg'
  1731. );
  1732. unset($style_cfg);
  1733. }
  1734. // Export template core code
  1735. if ($mode == 'template' || $inc_template)
  1736. {
  1737. $use_template_name = $style_row['template_name'];
  1738. // Add the inherit from variable, depending on it's use...
  1739. if ($style_row['template_inherits_id'])
  1740. {
  1741. // Get the template name
  1742. $sql = 'SELECT template_name
  1743. FROM ' . STYLES_TEMPLATE_TABLE . '
  1744. WHERE template_id = ' . (int) $style_row['template_inherits_id'];
  1745. $result = $db->sql_query($sql);
  1746. $use_template_name = (string) $db->sql_fetchfield('template_name');
  1747. $db->sql_freeresult($result);
  1748. }
  1749. $template_cfg = str_replace(array('{MODE}', '{NAME}', '{COPYRIGHT}', '{VERSION}', '{INHERIT_FROM}'), array($mode, $style_row['template_name'], $style_row['template_copyright'], $config['version'], $use_template_name), $this->template_cfg);
  1750. $template_cfg .= "\n\nbbcode_bitfield = {$style_row['bbcode_bitfield']}";
  1751. $data[] = array(
  1752. 'src' => $template_cfg,
  1753. 'prefix' => 'template/template.cfg'
  1754. );
  1755. // This is potentially nasty memory-wise ...
  1756. if (!$style_row['template_storedb'])
  1757. {
  1758. $files[] = array(
  1759. 'src' => "styles/{$style_row['template_path']}/template/",
  1760. 'prefix-' => "styles/{$style_row['template_path']}/",
  1761. 'prefix+' => false,
  1762. 'exclude' => 'template.cfg'
  1763. );
  1764. }
  1765. else
  1766. {
  1767. $sql = 'SELECT template_filename, template_data
  1768. FROM ' . STYLES_TEMPLATE_DATA_TABLE . "
  1769. WHERE template_id = {$style_row['template_id']}";
  1770. $result = $db->sql_query($sql);
  1771. while ($row = $db->sql_fetchrow($result))
  1772. {
  1773. $data[] = array(
  1774. 'src' => $row['template_data'],
  1775. 'prefix' => 'template/' . $row['template_filename']
  1776. );
  1777. }
  1778. $db->sql_freeresult($result);
  1779. }
  1780. unset($template_cfg);
  1781. }
  1782. // Export theme core code
  1783. if ($mode == 'theme' || $inc_theme)
  1784. {
  1785. $theme_cfg = str_replace(array('{MODE}', '{NAME}', '{COPYRIGHT}', '{VERSION}'), array($mode, $style_row['theme_name'], $style_row['theme_copyright'], $config['version']), $this->theme_cfg);
  1786. // Read old cfg file
  1787. $items = $cache->obtain_cfg_items($style_row);
  1788. $items = $items['theme'];
  1789. if (!isset($items['parse_css_file']))
  1790. {
  1791. $items['parse_css_file'] = 'off';
  1792. }
  1793. $theme_cfg = str_replace(array('{PARSE_CSS_FILE}'), array($items['parse_css_file']), $theme_cfg);
  1794. $files[] = array(
  1795. 'src' => "styles/{$style_row['theme_path']}/theme/",
  1796. 'prefix-' => "styles/{$style_row['theme_path']}/",
  1797. 'prefix+' => false,
  1798. 'exclude' => ($style_row['theme_storedb']) ? 'stylesheet.css,theme.cfg' : 'theme.cfg'
  1799. );
  1800. $data[] = array(
  1801. 'src' => $theme_cfg,
  1802. 'prefix' => 'theme/theme.cfg'
  1803. );
  1804. if ($style_row['theme_storedb'])
  1805. {
  1806. $data[] = array(
  1807. 'src' => $style_row['theme_data'],
  1808. 'prefix' => 'theme/stylesheet.css'
  1809. );
  1810. }
  1811. unset($items, $theme_cfg);
  1812. }
  1813. // Export imageset core code
  1814. if ($mode == 'imageset' || $inc_imageset)
  1815. {
  1816. $imageset_cfg = str_replace(array('{MODE}', '{NAME}', '{COPYRIGHT}', '{VERSION}'), array($mode, $style_row['imageset_name'], $style_row['imageset_copyright'], $config['version']), $this->imageset_cfg);
  1817. $imageset_main = array();
  1818. $sql = 'SELECT image_filename, image_name, image_height, image_width
  1819. FROM ' . STYLES_IMAGESET_DATA_TABLE . "
  1820. WHERE imageset_id = $style_id
  1821. AND image_lang = ''";
  1822. $result = $db->sql_query($sql);
  1823. while ($row = $db->sql_fetchrow($result))
  1824. {
  1825. $imageset_main[$row['image_name']] = $row['image_filename'] . ($row['image_height'] ? '*' . $row['image_height']: '') . ($row['image_width'] ? '*' . $row['image_width']: '');
  1826. }
  1827. $db->sql_freeresult($result);
  1828. foreach ($this->imageset_keys as $topic => $key_array)
  1829. {
  1830. foreach ($key_array as $key)
  1831. {
  1832. if (isset($imageset_main[$key]))
  1833. {
  1834. $imageset_cfg .= "\nimg_" . $key . ' = ' . str_replace("styles/{$style_row['imageset_path']}/imageset/", '{PATH}', $imageset_main[$key]);
  1835. }
  1836. }
  1837. }
  1838. $files[] = array(
  1839. 'src' => "styles/{$style_row['imageset_path']}/imageset/",
  1840. 'prefix-' => "styles/{$style_row['imageset_path']}/",
  1841. 'prefix+' => false,
  1842. 'exclude' => 'imageset.cfg'
  1843. );
  1844. $data[] = array(
  1845. 'src' => trim($imageset_cfg),
  1846. 'prefix' => 'imageset/imageset.cfg'
  1847. );
  1848. end($data);
  1849. $imageset_root = "{$phpbb_root_path}styles/{$style_row['imageset_path']}/imageset/";
  1850. if ($dh = @opendir($imageset_root))
  1851. {
  1852. while (($fname = readdir($dh)) !== false)
  1853. {
  1854. if ($fname[0] != '.' && $fname != 'CVS' && is_dir("$imageset_root$fname"))
  1855. {
  1856. $files[key($files)]['exclude'] .= ',' . $fname . '/imageset.cfg';
  1857. }
  1858. }
  1859. closedir($dh);
  1860. }
  1861. $imageset_lang = array();
  1862. $sql = 'SELECT image_filename, image_name, image_height, image_width, image_lang
  1863. FROM ' . STYLES_IMAGESET_DATA_TABLE . "
  1864. WHERE imageset_id = $style_id
  1865. AND image_lang <> ''";
  1866. $result = $db->sql_query($sql);
  1867. while ($row = $db->sql_fetchrow($result))
  1868. {
  1869. $imageset_lang[$row['image_lang']][$row['image_name']] = $row['image_filename'] . ($row['image_height'] ? '*' . $row['image_height']: '') . ($row['image_width'] ? '*' . $row['image_width']: '');
  1870. }
  1871. $db->sql_freeresult($result);
  1872. foreach ($imageset_lang as $lang => $imageset_localized)
  1873. {
  1874. $imageset_cfg = str_replace(array('{MODE}', '{NAME}', '{COPYRIGHT}', '{VERSION}'), array($mode, $style_row['imageset_name'], $style_row['imageset_copyright'], $config['version']), $this->imageset_cfg);
  1875. foreach ($this->imageset_keys as $topic => $key_array)
  1876. {
  1877. foreach ($key_array as $key)
  1878. {
  1879. if (isset($imageset_localized[$key]))
  1880. {
  1881. $imageset_cfg .= "\nimg_" . $key . ' = ' . str_replace("styles/{$style_row['imageset_path']}/imageset/", '{PATH}', $imageset_localized[$key]);
  1882. }
  1883. }
  1884. }
  1885. $data[] = array(
  1886. 'src' => trim($imageset_cfg),
  1887. 'prefix' => 'imageset/' . $lang . '/imageset.cfg'
  1888. );
  1889. }
  1890. unset($imageset_cfg);
  1891. }
  1892. switch ($format)
  1893. {
  1894. case 'tar':
  1895. $ext = '.tar';
  1896. break;
  1897. case 'zip':
  1898. $ext = '.zip';
  1899. break;
  1900. case 'tar.gz':
  1901. $ext = '.tar.gz';
  1902. break;
  1903. case 'tar.bz2':
  1904. $ext = '.tar.bz2';
  1905. break;
  1906. default:
  1907. $error[] = $user->lang[$l_prefix . '_ERR_ARCHIVE'];
  1908. }
  1909. if (!sizeof($error))
  1910. {
  1911. include($phpbb_root_path . 'includes/functions_compress.' . $phpEx);
  1912. if ($mode == 'style')
  1913. {
  1914. $path = preg_replace('#[^\w-]+#', '_', $style_row['style_name']);
  1915. }
  1916. else
  1917. {
  1918. $path = $style_row[$mode . '_path'];
  1919. }
  1920. if ($format == 'zip')
  1921. {
  1922. $compress = new compress_zip('w', $phpbb_root_path . "store/$path$ext");
  1923. }
  1924. else
  1925. {
  1926. $compress = new compress_tar('w', $phpbb_root_path . "store/$path$ext", $ext);
  1927. }
  1928. if (sizeof($files))
  1929. {
  1930. foreach ($files as $file_ary)
  1931. {
  1932. $compress->add_file($file_ary['src'], $file_ary['prefix-'], $file_ary['prefix+'], $file_ary['exclude']);
  1933. }
  1934. }
  1935. if (sizeof($data))
  1936. {
  1937. foreach ($data as $data_ary)
  1938. {
  1939. $compress->add_data($data_ary['src'], $data_ary['prefix']);
  1940. }
  1941. }
  1942. $compress->close();
  1943. add_log('admin', 'LOG_' . $l_prefix . '_EXPORT', $style_row[$mode . '_name']);
  1944. if (!$store)
  1945. {
  1946. $compress->download($path);
  1947. @unlink("{$phpbb_root_path}store/$path$ext");
  1948. exit;
  1949. }
  1950. trigger_error(sprintf($user->lang[$l_prefix . '_EXPORTED'], "store/$path$ext") . adm_back_link($this->u_action));
  1951. }
  1952. }
  1953. $sql = "SELECT {$mode}_id, {$mode}_name
  1954. FROM " . (($mode == 'style') ? STYLES_TABLE : $sql_from) . "
  1955. WHERE {$mode}_id = $style_id";
  1956. $result = $db->sql_query($sql);
  1957. $style_row = $db->sql_fetchrow($result);
  1958. $db->sql_freeresult($result);
  1959. if (!$style_row)
  1960. {
  1961. trigger_error($user->lang['NO_' . $l_prefix] . adm_back_link($this->u_action), E_USER_WARNING);
  1962. }
  1963. $this->page_title = $l_prefix . '_EXPORT';
  1964. $format_buttons = '';
  1965. foreach ($methods as $method)
  1966. {
  1967. $format_buttons .= '<label><input type="radio"' . ((!$format_buttons) ? ' id="format"' : '') . ' class="radio" value="' . $method . '" name="format"' . (($method == $format) ? ' checked="checked"' : '') . ' /> ' . $method . '</label>';
  1968. }
  1969. $template->assign_vars(array(
  1970. 'S_EXPORT' => true,
  1971. 'S_ERROR_MSG' => (sizeof($error)) ? true : false,
  1972. 'S_STYLE' => ($mode == 'style') ? true : false,
  1973. 'L_TITLE' => $user->lang[$this->page_title],
  1974. 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN'],
  1975. 'L_NAME' => $user->lang[$l_prefix . '_NAME'],
  1976. 'U_ACTION' => $this->u_action . '&amp;action=export&amp;id=' . $style_id,
  1977. 'U_BACK' => $this->u_action,
  1978. 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '',
  1979. 'NAME' => $style_row[$mode . '_name'],
  1980. 'FORMAT_BUTTONS' => $format_buttons)
  1981. );
  1982. }
  1983. /**
  1984. * Display details
  1985. */
  1986. function details($mode, $style_id)
  1987. {
  1988. global $template, $db, $config, $user, $safe_mode, $cache, $phpbb_root_path;
  1989. $update = (isset($_POST['update'])) ? true : false;
  1990. $l_type = strtoupper($mode);
  1991. $error = array();
  1992. $element_ary = array('template' => STYLES_TEMPLATE_TABLE, 'theme' => STYLES_THEME_TABLE, 'imageset' => STYLES_IMAGESET_TABLE);
  1993. switch ($mode)
  1994. {
  1995. case 'style':
  1996. $sql_from = STYLES_TABLE;
  1997. break;
  1998. case 'template':
  1999. $sql_from = STYLES_TEMPLATE_TABLE;
  2000. break;
  2001. case 'theme':
  2002. $sql_from = STYLES_THEME_TABLE;
  2003. break;
  2004. case 'imageset':
  2005. $sql_from = STYLES_IMAGESET_TABLE;
  2006. break;
  2007. }
  2008. $sql = "SELECT *
  2009. FROM $sql_from
  2010. WHERE {$mode}_id = $style_id";
  2011. $result = $db->sql_query($sql);
  2012. $style_row = $db->sql_fetchrow($result);
  2013. $db->sql_freeresult($result);
  2014. if (!$style_row)
  2015. {
  2016. trigger_error($user->lang['NO_' . $l_type] . adm_back_link($this->u_action), E_USER_WARNING);
  2017. }
  2018. $style_row['style_default'] = ($mode == 'style' && $config['default_style'] == $style_id) ? 1 : 0;
  2019. if ($update)
  2020. {
  2021. $name = utf8_normalize_nfc(request_var('name', '', true));
  2022. $copyright = utf8_normalize_nfc(request_var('copyright', '', true));
  2023. $template_id = request_var('template_id', 0);
  2024. $theme_id = request_var('theme_id', 0);
  2025. $imageset_id = request_var('imageset_id', 0);
  2026. $style_active = request_var('style_active', 0);
  2027. $style_default = request_var('style_default', 0);
  2028. $store_db = request_var('store_db', 0);
  2029. // If the admin selected the style to be the default style, but forgot to activate it... we will do it for him
  2030. if ($style_default)
  2031. {
  2032. $style_active = 1;
  2033. }
  2034. $sql = "SELECT {$mode}_id, {$mode}_name
  2035. FROM $sql_from
  2036. WHERE {$mode}_id <> $style_id
  2037. AND LOWER({$mode}_name) = '" . $db->sql_escape(strtolower($name)) . "'";
  2038. $result = $db->sql_query($sql);
  2039. $conflict = $db->sql_fetchrow($result);
  2040. $db->sql_freeresult($result);
  2041. if ($mode == 'style' && (!$template_id || !$theme_id || !$imageset_id))
  2042. {
  2043. $error[] = $user->lang['STYLE_ERR_NO_IDS'];
  2044. }
  2045. if ($mode == 'style' && $style_row['style_active'] && !$style_active && $config['default_style'] == $style_id)
  2046. {
  2047. $error[] = $user->lang['DEACTIVATE_DEFAULT'];
  2048. }
  2049. if (!$name || $conflict)
  2050. {
  2051. $error[] = $user->lang[$l_type . '_ERR_STYLE_NAME'];
  2052. }
  2053. if ($mode === 'theme' || $mode === 'template')
  2054. {
  2055. // a rather elaborate check we have to do here once to avoid trouble later
  2056. $check = "{$phpbb_root_path}styles/" . $style_row["{$mode}_path"] . (($mode === 'theme') ? '/theme/stylesheet.css' : '/template');
  2057. if (($style_row["{$mode}_storedb"] != $store_db) && !$store_db && ($safe_mode || !phpbb_is_writable($check)))
  2058. {
  2059. $error[] = $user->lang['EDIT_' . strtoupper($mode) . '_STORED_DB'];
  2060. $store_db = 1;
  2061. }
  2062. // themes which have to be parsed have to go into db
  2063. if ($mode == 'theme')
  2064. {
  2065. $cfg = parse_cfg_file("{$phpbb_root_path}styles/" . $style_row["{$mode}_path"] . "/theme/theme.cfg");
  2066. if (isset($cfg['parse_css_file']) && $cfg['parse_css_file'] && !$store_db)
  2067. {
  2068. $error[] = $user->lang['EDIT_THEME_STORE_PARSED'];
  2069. $store_db = 1;
  2070. }
  2071. }
  2072. }
  2073. if (!sizeof($error))
  2074. {
  2075. // Check length settings
  2076. if (utf8_strlen($name) > 30)
  2077. {
  2078. $error[] = $user->lang[$l_type . '_ERR_NAME_LONG'];
  2079. }
  2080. if (utf8_strlen($copyright) > 60)
  2081. {
  2082. $error[] = $user->lang[$l_type . '_ERR_COPY_LONG'];
  2083. }
  2084. }
  2085. }
  2086. if ($update && sizeof($error))
  2087. {
  2088. $style_row = array_merge($style_row, array(
  2089. 'template_id' => $template_id,
  2090. 'theme_id' => $theme_id,
  2091. 'imageset_id' => $imageset_id,
  2092. 'style_active' => $style_active,
  2093. $mode . '_storedb' => $store_db,
  2094. $mode . '_name' => $name,
  2095. $mode . '_copyright' => $copyright)
  2096. );
  2097. }
  2098. // User has submitted form and no errors have occurred
  2099. if ($update && !sizeof($error))
  2100. {
  2101. $sql_ary = array(
  2102. $mode . '_name' => $name,
  2103. $mode . '_copyright' => $copyright
  2104. );
  2105. switch ($mode)
  2106. {
  2107. case 'style':
  2108. $sql_ary += array(
  2109. 'template_id' => (int) $template_id,
  2110. 'theme_id' => (int) $theme_id,
  2111. 'imageset_id' => (int) $imageset_id,
  2112. 'style_active' => (int) $style_active,
  2113. );
  2114. break;
  2115. case 'imageset':
  2116. break;
  2117. case 'theme':
  2118. if ($style_row['theme_storedb'] != $store_db)
  2119. {
  2120. $theme_data = '';
  2121. if (!$style_row['theme_storedb'])
  2122. {
  2123. $theme_data = $this->db_theme_data($style_row);
  2124. }
  2125. else if (!$store_db && !$safe_mode && phpbb_is_writable("{$phpbb_root_path}styles/{$style_row['theme_path']}/theme/stylesheet.css"))
  2126. {
  2127. $store_db = 1;
  2128. $theme_data = $style_row['theme_data'];
  2129. if ($fp = @fopen("{$phpbb_root_path}styles/{$style_row['theme_path']}/theme/stylesheet.css", 'wb'))
  2130. {
  2131. $store_db = (@fwrite($fp, str_replace("styles/{$style_row['theme_path']}/theme/", './', $theme_data))) ? 0 : 1;
  2132. }
  2133. fclose($fp);
  2134. }
  2135. $sql_ary += array(
  2136. 'theme_mtime' => ($store_db) ? filemtime("{$phpbb_root_path}styles/{$style_row['theme_path']}/theme/stylesheet.css") : 0,
  2137. 'theme_storedb' => $store_db,
  2138. 'theme_data' => ($store_db) ? $theme_data : '',
  2139. );
  2140. }
  2141. break;
  2142. case 'template':
  2143. if ($style_row['template_storedb'] != $store_db)
  2144. {
  2145. if ($super = $this->get_super($mode, $style_row['template_id']))
  2146. {
  2147. $error[] = (sprintf($user->lang["{$l_type}_INHERITS"], $super['template_name']));
  2148. $sql_ary = array();
  2149. }
  2150. else
  2151. {
  2152. if (!$store_db && !$safe_mode && phpbb_is_writable("{$phpbb_root_path}styles/{$style_row['template_path']}/template"))
  2153. {
  2154. $err = $this->store_in_fs('template', $style_row['template_id']);
  2155. if ($err)
  2156. {
  2157. $error += $err;
  2158. }
  2159. }
  2160. else if ($store_db)
  2161. {
  2162. $this->store_in_db('template', $style_row['template_id']);
  2163. }
  2164. else
  2165. {
  2166. // We no longer store within the db, but are also not able to update the file structure
  2167. // Since the admin want to switch this, we adhere to his decision. But we also need to remove the cache
  2168. $sql = 'DELETE FROM ' . STYLES_TEMPLATE_DATA_TABLE . "
  2169. WHERE template_id = $style_id";
  2170. $db->sql_query($sql);
  2171. }
  2172. $sql_ary += array(
  2173. 'template_storedb' => $store_db,
  2174. );
  2175. }
  2176. }
  2177. break;
  2178. }
  2179. if (sizeof($sql_ary))
  2180. {
  2181. $sql = "UPDATE $sql_from
  2182. SET " . $db->sql_build_array('UPDATE', $sql_ary) . "
  2183. WHERE {$mode}_id = $style_id";
  2184. $db->sql_query($sql);
  2185. // Making this the default style?
  2186. if ($mode == 'style' && $style_default)
  2187. {
  2188. set_config('default_style', $style_id);
  2189. }
  2190. }
  2191. $cache->destroy('sql', STYLES_TABLE);
  2192. add_log('admin', 'LOG_' . $l_type . '_EDIT_DETAILS', $name);
  2193. if (sizeof($error))
  2194. {
  2195. trigger_error(implode('<br />', $error) . adm_back_link($this->u_action), E_USER_WARNING);
  2196. }
  2197. else
  2198. {
  2199. trigger_error($user->lang[$l_type . '_DETAILS_UPDATED'] . adm_back_link($this->u_action));
  2200. }
  2201. }
  2202. if ($mode == 'style')
  2203. {
  2204. foreach ($element_ary as $element => $table)
  2205. {
  2206. $sql = "SELECT {$element}_id, {$element}_name
  2207. FROM $table
  2208. ORDER BY {$element}_id ASC";
  2209. $result = $db->sql_query($sql);
  2210. ${$element . '_options'} = '';
  2211. while ($row = $db->sql_fetchrow($result))
  2212. {
  2213. $selected = ($row[$element . '_id'] == $style_row[$element . '_id']) ? ' selected="selected"' : '';
  2214. ${$element . '_options'} .= '<option value="' . $row[$element . '_id'] . '"' . $selected . '>' . $row[$element . '_name'] . '</option>';
  2215. }
  2216. $db->sql_freeresult($result);
  2217. }
  2218. }
  2219. if ($mode == 'template')
  2220. {
  2221. $super = array();
  2222. if (isset($style_row[$mode . '_inherits_id']) && $style_row['template_inherits_id'])
  2223. {
  2224. $super = $this->get_super($mode, $style_row['template_id']);
  2225. }
  2226. }
  2227. $this->page_title = 'EDIT_DETAILS_' . $l_type;
  2228. $template->assign_vars(array(
  2229. 'S_DETAILS' => true,
  2230. 'S_ERROR_MSG' => (sizeof($error)) ? true : false,
  2231. 'S_STYLE' => ($mode == 'style') ? true : false,
  2232. 'S_TEMPLATE' => ($mode == 'template') ? true : false,
  2233. 'S_THEME' => ($mode == 'theme') ? true : false,
  2234. 'S_IMAGESET' => ($mode == 'imageset') ? true : false,
  2235. 'S_STORE_DB' => (isset($style_row[$mode . '_storedb'])) ? $style_row[$mode . '_storedb'] : 0,
  2236. 'S_STORE_DB_DISABLED' => (isset($style_row[$mode . '_inherits_id'])) ? $style_row[$mode . '_inherits_id'] : 0,
  2237. 'S_STYLE_ACTIVE' => (isset($style_row['style_active'])) ? $style_row['style_active'] : 0,
  2238. 'S_STYLE_DEFAULT' => (isset($style_row['style_default'])) ? $style_row['style_default'] : 0,
  2239. 'S_SUPERTEMPLATE' => (isset($style_row[$mode . '_inherits_id']) && $style_row[$mode . '_inherits_id']) ? $super['template_name'] : 0,
  2240. 'S_TEMPLATE_OPTIONS' => ($mode == 'style') ? $template_options : '',
  2241. 'S_THEME_OPTIONS' => ($mode == 'style') ? $theme_options : '',
  2242. 'S_IMAGESET_OPTIONS' => ($mode == 'style') ? $imageset_options : '',
  2243. 'U_ACTION' => $this->u_action . '&amp;action=details&amp;id=' . $style_id,
  2244. 'U_BACK' => $this->u_action,
  2245. 'L_TITLE' => $user->lang[$this->page_title],
  2246. 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN'],
  2247. 'L_NAME' => $user->lang[$l_type . '_NAME'],
  2248. 'L_LOCATION' => ($mode == 'template' || $mode == 'theme') ? $user->lang[$l_type . '_LOCATION'] : '',
  2249. 'L_LOCATION_EXPLAIN' => ($mode == 'template' || $mode == 'theme') ? $user->lang[$l_type . '_LOCATION_EXPLAIN'] : '',
  2250. 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '',
  2251. 'NAME' => $style_row[$mode . '_name'],
  2252. 'COPYRIGHT' => $style_row[$mode . '_copyright'],
  2253. )
  2254. );
  2255. }
  2256. /**
  2257. * Load css file contents
  2258. */
  2259. function load_css_file($path, $filename)
  2260. {
  2261. global $phpbb_root_path;
  2262. $file = "{$phpbb_root_path}styles/$path/theme/$filename";
  2263. if (file_exists($file) && ($content = file_get_contents($file)))
  2264. {
  2265. $content = trim($content);
  2266. }
  2267. else
  2268. {
  2269. $content = '';
  2270. }
  2271. if (defined('DEBUG'))
  2272. {
  2273. $content = "/* BEGIN @include $filename */ \n $content \n /* END @include $filename */ \n";
  2274. }
  2275. return $content;
  2276. }
  2277. /**
  2278. * Returns a string containing the value that should be used for the theme_data column in the theme database table.
  2279. * Includes contents of files loaded via @import
  2280. *
  2281. * @param array $theme_row is an associative array containing the theme's current database entry
  2282. * @param mixed $stylesheet can either be the new content for the stylesheet or false to load from the standard file
  2283. * @param string $root_path should only be used in case you want to use a different root path than "{$phpbb_root_path}styles/{$theme_row['theme_path']}"
  2284. *
  2285. * @return string Stylesheet data for theme_data column in the theme table
  2286. */
  2287. function db_theme_data($theme_row, $stylesheet = false, $root_path = '')
  2288. {
  2289. global $phpbb_root_path;
  2290. if (!$root_path)
  2291. {
  2292. $root_path = $phpbb_root_path . 'styles/' . $theme_row['theme_path'];
  2293. }
  2294. if (!$stylesheet)
  2295. {
  2296. $stylesheet = '';
  2297. if (file_exists($root_path . '/theme/stylesheet.css'))
  2298. {
  2299. $stylesheet = file_get_contents($root_path . '/theme/stylesheet.css');
  2300. }
  2301. }
  2302. // Match CSS imports
  2303. $matches = array();
  2304. preg_match_all('/@import url\((["\'])(.*)\1\);/i', $stylesheet, $matches);
  2305. // remove commented stylesheets (very simple parser, allows only whitespace
  2306. // around an @import statement)
  2307. preg_match_all('#/\*\s*@import url\((["\'])(.*)\1\);\s\*/#i', $stylesheet, $commented);
  2308. $matches[2] = array_diff($matches[2], $commented[2]);
  2309. if (sizeof($matches))
  2310. {
  2311. foreach ($matches[0] as $idx => $match)
  2312. {
  2313. if (isset($matches[2][$idx]))
  2314. {
  2315. $stylesheet = str_replace($match, acp_styles::load_css_file($theme_row['theme_path'], $matches[2][$idx]), $stylesheet);
  2316. }
  2317. }
  2318. }
  2319. // adjust paths
  2320. return str_replace('./', 'styles/' . $theme_row['theme_path'] . '/theme/', $stylesheet);
  2321. }
  2322. /**
  2323. * Store template files into db
  2324. */
  2325. function store_templates($mode, $style_id, $template_path, $filelist)
  2326. {
  2327. global $phpbb_root_path, $phpEx, $db;
  2328. $template_path = $template_path . '/template/';
  2329. $includes = array();
  2330. foreach ($filelist as $pathfile => $file_ary)
  2331. {
  2332. foreach ($file_ary as $file)
  2333. {
  2334. if (!($fp = @fopen("{$phpbb_root_path}styles/$template_path$pathfile$file", 'r')))
  2335. {
  2336. trigger_error("Could not open {$phpbb_root_path}styles/$template_path$pathfile$file", E_USER_ERROR);
  2337. }
  2338. $filesize = filesize("{$phpbb_root_path}styles/$template_path$pathfile$file");
  2339. if ($filesize)
  2340. {
  2341. $template_data = fread($fp, $filesize);
  2342. }
  2343. fclose($fp);
  2344. if (!$filesize)
  2345. {
  2346. // File is empty
  2347. continue;
  2348. }
  2349. if (preg_match_all('#<!-- INCLUDE (.*?\.html) -->#is', $template_data, $matches))
  2350. {
  2351. foreach ($matches[1] as $match)
  2352. {
  2353. $includes[trim($match)][] = $file;
  2354. }
  2355. }
  2356. }
  2357. }
  2358. foreach ($filelist as $pathfile => $file_ary)
  2359. {
  2360. foreach ($file_ary as $file)
  2361. {
  2362. // Skip index.
  2363. if (strpos($file, 'index.') === 0)
  2364. {
  2365. continue;
  2366. }
  2367. // We could do this using extended inserts ... but that could be one
  2368. // heck of a lot of data ...
  2369. $sql_ary = array(
  2370. 'template_id' => (int) $style_id,
  2371. 'template_filename' => "$pathfile$file",
  2372. 'template_included' => (isset($includes[$file])) ? implode(':', $includes[$file]) . ':' : '',
  2373. 'template_mtime' => (int) filemtime("{$phpbb_root_path}styles/$template_path$pathfile$file"),
  2374. 'template_data' => (string) file_get_contents("{$phpbb_root_path}styles/$template_path$pathfile$file"),
  2375. );
  2376. if ($mode == 'insert')
  2377. {
  2378. $sql = 'INSERT INTO ' . STYLES_TEMPLATE_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
  2379. }
  2380. else
  2381. {
  2382. $sql = 'UPDATE ' . STYLES_TEMPLATE_DATA_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . "
  2383. WHERE template_id = $style_id
  2384. AND template_filename = '" . $db->sql_escape("$pathfile$file") . "'";
  2385. }
  2386. $db->sql_query($sql);
  2387. }
  2388. }
  2389. }
  2390. /**
  2391. * Returns an array containing all template filenames for one template that are currently cached.
  2392. *
  2393. * @param string $template_path contains the name of the template's folder in /styles/
  2394. *
  2395. * @return array of filenames that exist in /styles/$template_path/template/ (without extension!)
  2396. */
  2397. function template_cache_filelist($template_path)
  2398. {
  2399. global $phpbb_root_path, $phpEx, $user;
  2400. $cache_prefix = 'tpl_' . str_replace('_', '-', $template_path);
  2401. if (!($dp = @opendir("{$phpbb_root_path}cache")))
  2402. {
  2403. trigger_error($user->lang['TEMPLATE_ERR_CACHE_READ'] . adm_back_link($this->u_action), E_USER_WARNING);
  2404. }
  2405. $file_ary = array();
  2406. while ($file = readdir($dp))
  2407. {
  2408. if ($file[0] == '.')
  2409. {
  2410. continue;
  2411. }
  2412. if (is_file($phpbb_root_path . 'cache/' . $file) && (strpos($file, $cache_prefix) === 0))
  2413. {
  2414. $file_ary[] = str_replace('.', '/', preg_replace('#^' . preg_quote($cache_prefix, '#') . '_(.*?)\.html\.' . $phpEx . '$#i', '\1', $file));
  2415. }
  2416. }
  2417. closedir($dp);
  2418. return $file_ary;
  2419. }
  2420. /**
  2421. * Destroys cached versions of template files
  2422. *
  2423. * @param array $template_row contains the template's row in the STYLES_TEMPLATE_TABLE database table
  2424. * @param mixed $file_ary is optional and may contain an array of template file names which should be refreshed in the cache.
  2425. * The file names should be the original template file names and not the cache file names.
  2426. */
  2427. function clear_template_cache($template_row, $file_ary = false)
  2428. {
  2429. global $phpbb_root_path, $phpEx, $user;
  2430. $cache_prefix = 'tpl_' . str_replace('_', '-', $template_row['template_path']);
  2431. if (!$file_ary || !is_array($file_ary))
  2432. {
  2433. $file_ary = $this->template_cache_filelist($template_row['template_path']);
  2434. $log_file_list = $user->lang['ALL_FILES'];
  2435. }
  2436. else
  2437. {
  2438. $log_file_list = implode(', ', $file_ary);
  2439. }
  2440. foreach ($file_ary as $file)
  2441. {
  2442. $file = str_replace('/', '.', $file);
  2443. $file = "{$phpbb_root_path}cache/{$cache_prefix}_$file.html.$phpEx";
  2444. if (file_exists($file) && is_file($file))
  2445. {
  2446. @unlink($file);
  2447. }
  2448. }
  2449. unset($file_ary);
  2450. add_log('admin', 'LOG_TEMPLATE_CACHE_CLEARED', $template_row['template_name'], $log_file_list);
  2451. }
  2452. /**
  2453. * Install Style/Template/Theme/Imageset
  2454. */
  2455. function install($mode)
  2456. {
  2457. global $phpbb_root_path, $phpEx, $config, $db, $cache, $user, $template;
  2458. $l_type = strtoupper($mode);
  2459. $error = $installcfg = $style_row = array();
  2460. $root_path = $cfg_file = '';
  2461. $element_ary = array('template' => STYLES_TEMPLATE_TABLE, 'theme' => STYLES_THEME_TABLE, 'imageset' => STYLES_IMAGESET_TABLE);
  2462. $install_path = request_var('path', '');
  2463. $update = (isset($_POST['update'])) ? true : false;
  2464. // Installing, obtain cfg file contents
  2465. if ($install_path)
  2466. {
  2467. $root_path = $phpbb_root_path . 'styles/' . $install_path . '/';
  2468. $cfg_file = ($mode == 'style') ? "$root_path$mode.cfg" : "$root_path$mode/$mode.cfg";
  2469. if (!file_exists($cfg_file))
  2470. {
  2471. $error[] = $user->lang[$l_type . '_ERR_NOT_' . $l_type];
  2472. }
  2473. else
  2474. {
  2475. $installcfg = parse_cfg_file($cfg_file);
  2476. }
  2477. }
  2478. // Installing
  2479. if (sizeof($installcfg))
  2480. {
  2481. $name = $installcfg['name'];
  2482. $copyright = $installcfg['copyright'];
  2483. $version = $installcfg['version'];
  2484. $style_row = array(
  2485. $mode . '_id' => 0,
  2486. $mode . '_name' => '',
  2487. $mode . '_copyright' => ''
  2488. );
  2489. switch ($mode)
  2490. {
  2491. case 'style':
  2492. $style_row = array(
  2493. 'style_id' => 0,
  2494. 'style_name' => $installcfg['name'],
  2495. 'style_copyright' => $installcfg['copyright']
  2496. );
  2497. $reqd_template = (isset($installcfg['required_template'])) ? $installcfg['required_template'] : false;
  2498. $reqd_theme = (isset($installcfg['required_theme'])) ? $installcfg['required_theme'] : false;
  2499. $reqd_imageset = (isset($installcfg['required_imageset'])) ? $installcfg['required_imageset'] : false;
  2500. // Check to see if each element is already installed, if it is grab the id
  2501. foreach ($element_ary as $element => $table)
  2502. {
  2503. $style_row = array_merge($style_row, array(
  2504. $element . '_id' => 0,
  2505. $element . '_name' => '',
  2506. $element . '_copyright' => '')
  2507. );
  2508. $this->test_installed($element, $error, (${'reqd_' . $element}) ? $phpbb_root_path . 'styles/' . $reqd_template . '/' : $root_path, ${'reqd_' . $element}, $style_row[$element . '_id'], $style_row[$element . '_name'], $style_row[$element . '_copyright']);
  2509. if (!$style_row[$element . '_name'])
  2510. {
  2511. $style_row[$element . '_name'] = $reqd_template;
  2512. }
  2513. // Merge other information to installcfg... if present
  2514. $cfg_file = $phpbb_root_path . 'styles/' . $install_path . '/' . $element . '/' . $element . '.cfg';
  2515. if (file_exists($cfg_file))
  2516. {
  2517. $cfg_contents = parse_cfg_file($cfg_file);
  2518. // Merge only specific things. We may need them later.
  2519. foreach (array('inherit_from', 'parse_css_file') as $key)
  2520. {
  2521. if (!empty($cfg_contents[$key]) && !isset($installcfg[$key]))
  2522. {
  2523. $installcfg[$key] = $cfg_contents[$key];
  2524. }
  2525. }
  2526. }
  2527. }
  2528. break;
  2529. case 'template':
  2530. $this->test_installed('template', $error, $root_path, false, $style_row['template_id'], $style_row['template_name'], $style_row['template_copyright']);
  2531. break;
  2532. case 'theme':
  2533. $this->test_installed('theme', $error, $root_path, false, $style_row['theme_id'], $style_row['theme_name'], $style_row['theme_copyright']);
  2534. break;
  2535. case 'imageset':
  2536. $this->test_installed('imageset', $error, $root_path, false, $style_row['imageset_id'], $style_row['imageset_name'], $style_row['imageset_copyright']);
  2537. break;
  2538. }
  2539. }
  2540. else
  2541. {
  2542. trigger_error($user->lang['NO_' . $l_type] . adm_back_link($this->u_action), E_USER_WARNING);
  2543. }
  2544. $style_row['store_db'] = request_var('store_db', 0);
  2545. $style_row['style_active'] = request_var('style_active', 1);
  2546. $style_row['style_default'] = request_var('style_default', 0);
  2547. // User has submitted form and no errors have occurred
  2548. if ($update && !sizeof($error))
  2549. {
  2550. if ($mode == 'style')
  2551. {
  2552. foreach ($element_ary as $element => $table)
  2553. {
  2554. ${$element . '_root_path'} = (${'reqd_' . $element}) ? $phpbb_root_path . 'styles/' . ${'reqd_' . $element} . '/' : false;
  2555. ${$element . '_path'} = (${'reqd_' . $element}) ? ${'reqd_' . $element} : false;
  2556. }
  2557. $this->install_style($error, 'install', $root_path, $style_row['style_id'], $style_row['style_name'], $install_path, $style_row['style_copyright'], $style_row['style_active'], $style_row['style_default'], $style_row, $template_root_path, $template_path, $theme_root_path, $theme_path, $imageset_root_path, $imageset_path);
  2558. }
  2559. else
  2560. {
  2561. $style_row['store_db'] = $this->install_element($mode, $error, 'install', $root_path, $style_row[$mode . '_id'], $style_row[$mode . '_name'], $install_path, $style_row[$mode . '_copyright'], $style_row['store_db']);
  2562. }
  2563. if (!sizeof($error))
  2564. {
  2565. $cache->destroy('sql', STYLES_TABLE);
  2566. $message = ($style_row['store_db']) ? '_ADDED_DB' : '_ADDED';
  2567. trigger_error($user->lang[$l_type . $message] . adm_back_link($this->u_action));
  2568. }
  2569. }
  2570. $this->page_title = 'INSTALL_' . $l_type;
  2571. $template->assign_vars(array(
  2572. 'S_DETAILS' => true,
  2573. 'S_INSTALL' => true,
  2574. 'S_ERROR_MSG' => (sizeof($error)) ? true : false,
  2575. 'S_LOCATION' => (isset($installcfg['inherit_from']) && $installcfg['inherit_from']) ? false : true,
  2576. 'S_STYLE' => ($mode == 'style') ? true : false,
  2577. 'S_TEMPLATE' => ($mode == 'template') ? true : false,
  2578. 'S_SUPERTEMPLATE' => (isset($installcfg['inherit_from'])) ? $installcfg['inherit_from'] : '',
  2579. 'S_THEME' => ($mode == 'theme') ? true : false,
  2580. 'S_STORE_DB' => (isset($style_row[$mode . '_storedb'])) ? $style_row[$mode . '_storedb'] : 0,
  2581. 'S_STYLE_ACTIVE' => (isset($style_row['style_active'])) ? $style_row['style_active'] : 0,
  2582. 'S_STYLE_DEFAULT' => (isset($style_row['style_default'])) ? $style_row['style_default'] : 0,
  2583. 'U_ACTION' => $this->u_action . "&amp;action=install&amp;path=" . urlencode($install_path),
  2584. 'U_BACK' => $this->u_action,
  2585. 'L_TITLE' => $user->lang[$this->page_title],
  2586. 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN'],
  2587. 'L_NAME' => $user->lang[$l_type . '_NAME'],
  2588. 'L_LOCATION' => ($mode == 'template' || $mode == 'theme') ? $user->lang[$l_type . '_LOCATION'] : '',
  2589. 'L_LOCATION_EXPLAIN' => ($mode == 'template' || $mode == 'theme') ? $user->lang[$l_type . '_LOCATION_EXPLAIN'] : '',
  2590. 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '',
  2591. 'NAME' => $style_row[$mode . '_name'],
  2592. 'COPYRIGHT' => $style_row[$mode . '_copyright'],
  2593. 'TEMPLATE_NAME' => ($mode == 'style') ? $style_row['template_name'] : '',
  2594. 'THEME_NAME' => ($mode == 'style') ? $style_row['theme_name'] : '',
  2595. 'IMAGESET_NAME' => ($mode == 'style') ? $style_row['imageset_name'] : '')
  2596. );
  2597. }
  2598. /**
  2599. * Add new style
  2600. */
  2601. function add($mode)
  2602. {
  2603. global $phpbb_root_path, $phpEx, $config, $db, $cache, $user, $template;
  2604. $l_type = strtoupper($mode);
  2605. $element_ary = array('template' => STYLES_TEMPLATE_TABLE, 'theme' => STYLES_THEME_TABLE, 'imageset' => STYLES_IMAGESET_TABLE);
  2606. $error = array();
  2607. $style_row = array(
  2608. $mode . '_name' => utf8_normalize_nfc(request_var('name', '', true)),
  2609. $mode . '_copyright' => utf8_normalize_nfc(request_var('copyright', '', true)),
  2610. 'template_id' => 0,
  2611. 'theme_id' => 0,
  2612. 'imageset_id' => 0,
  2613. 'store_db' => request_var('store_db', 0),
  2614. 'style_active' => request_var('style_active', 1),
  2615. 'style_default' => request_var('style_default', 0),
  2616. );
  2617. $basis = request_var('basis', 0);
  2618. $update = (isset($_POST['update'])) ? true : false;
  2619. if ($basis)
  2620. {
  2621. switch ($mode)
  2622. {
  2623. case 'style':
  2624. $sql_select = 'template_id, theme_id, imageset_id';
  2625. $sql_from = STYLES_TABLE;
  2626. break;
  2627. case 'template':
  2628. $sql_select = 'template_id';
  2629. $sql_from = STYLES_TEMPLATE_TABLE;
  2630. break;
  2631. case 'theme':
  2632. $sql_select = 'theme_id';
  2633. $sql_from = STYLES_THEME_TABLE;
  2634. break;
  2635. case 'imageset':
  2636. $sql_select = 'imageset_id';
  2637. $sql_from = STYLES_IMAGESET_TABLE;
  2638. break;
  2639. }
  2640. $sql = "SELECT $sql_select
  2641. FROM $sql_from
  2642. WHERE {$mode}_id = $basis";
  2643. $result = $db->sql_query($sql);
  2644. $row = $db->sql_fetchrow($result);
  2645. $db->sql_freeresult($result);
  2646. if (!$row)
  2647. {
  2648. $error[] = $user->lang['NO_' . $l_type];
  2649. }
  2650. if (!sizeof($error))
  2651. {
  2652. $style_row['template_id'] = (isset($row['template_id'])) ? $row['template_id'] : $style_row['template_id'];
  2653. $style_row['theme_id'] = (isset($row['theme_id'])) ? $row['theme_id'] : $style_row['theme_id'];
  2654. $style_row['imageset_id'] = (isset($row['imageset_id'])) ? $row['imageset_id'] : $style_row['imageset_id'];
  2655. }
  2656. }
  2657. if ($update)
  2658. {
  2659. $style_row['template_id'] = request_var('template_id', $style_row['template_id']);
  2660. $style_row['theme_id'] = request_var('theme_id', $style_row['theme_id']);
  2661. $style_row['imageset_id'] = request_var('imageset_id', $style_row['imageset_id']);
  2662. if ($mode == 'style' && (!$style_row['template_id'] || !$style_row['theme_id'] || !$style_row['imageset_id']))
  2663. {
  2664. $error[] = $user->lang['STYLE_ERR_NO_IDS'];
  2665. }
  2666. }
  2667. // User has submitted form and no errors have occurred
  2668. if ($update && !sizeof($error))
  2669. {
  2670. if ($mode == 'style')
  2671. {
  2672. $style_row['style_id'] = 0;
  2673. $this->install_style($error, 'add', '', $style_row['style_id'], $style_row['style_name'], '', $style_row['style_copyright'], $style_row['style_active'], $style_row['style_default'], $style_row);
  2674. }
  2675. if (!sizeof($error))
  2676. {
  2677. $cache->destroy('sql', STYLES_TABLE);
  2678. $message = ($style_row['store_db']) ? '_ADDED_DB' : '_ADDED';
  2679. trigger_error($user->lang[$l_type . $message] . adm_back_link($this->u_action));
  2680. }
  2681. }
  2682. if ($mode == 'style')
  2683. {
  2684. foreach ($element_ary as $element => $table)
  2685. {
  2686. $sql = "SELECT {$element}_id, {$element}_name
  2687. FROM $table
  2688. ORDER BY {$element}_id ASC";
  2689. $result = $db->sql_query($sql);
  2690. ${$element . '_options'} = '';
  2691. while ($row = $db->sql_fetchrow($result))
  2692. {
  2693. $selected = ($row[$element . '_id'] == $style_row[$element . '_id']) ? ' selected="selected"' : '';
  2694. ${$element . '_options'} .= '<option value="' . $row[$element . '_id'] . '"' . $selected . '>' . $row[$element . '_name'] . '</option>';
  2695. }
  2696. $db->sql_freeresult($result);
  2697. }
  2698. }
  2699. $this->page_title = 'ADD_' . $l_type;
  2700. $template->assign_vars(array(
  2701. 'S_DETAILS' => true,
  2702. 'S_ADD' => true,
  2703. 'S_ERROR_MSG' => (sizeof($error)) ? true : false,
  2704. 'S_STYLE' => ($mode == 'style') ? true : false,
  2705. 'S_TEMPLATE' => ($mode == 'template') ? true : false,
  2706. 'S_THEME' => ($mode == 'theme') ? true : false,
  2707. 'S_BASIS' => ($basis) ? true : false,
  2708. 'S_STORE_DB' => (isset($style_row['storedb'])) ? $style_row['storedb'] : 0,
  2709. 'S_STYLE_ACTIVE' => (isset($style_row['style_active'])) ? $style_row['style_active'] : 0,
  2710. 'S_STYLE_DEFAULT' => (isset($style_row['style_default'])) ? $style_row['style_default'] : 0,
  2711. 'S_TEMPLATE_OPTIONS' => ($mode == 'style') ? $template_options : '',
  2712. 'S_THEME_OPTIONS' => ($mode == 'style') ? $theme_options : '',
  2713. 'S_IMAGESET_OPTIONS' => ($mode == 'style') ? $imageset_options : '',
  2714. 'U_ACTION' => $this->u_action . '&amp;action=add&amp;basis=' . $basis,
  2715. 'U_BACK' => $this->u_action,
  2716. 'L_TITLE' => $user->lang[$this->page_title],
  2717. 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN'],
  2718. 'L_NAME' => $user->lang[$l_type . '_NAME'],
  2719. 'L_LOCATION' => ($mode == 'template' || $mode == 'theme') ? $user->lang[$l_type . '_LOCATION'] : '',
  2720. 'L_LOCATION_EXPLAIN' => ($mode == 'template' || $mode == 'theme') ? $user->lang[$l_type . '_LOCATION_EXPLAIN'] : '',
  2721. 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '',
  2722. 'NAME' => $style_row[$mode . '_name'],
  2723. 'COPYRIGHT' => $style_row[$mode . '_copyright'])
  2724. );
  2725. }
  2726. /**
  2727. $reqd_template = (isset($installcfg['required_template'])) ? $installcfg['required_template'] : false;
  2728. $reqd_theme = (isset($installcfg['required_theme'])) ? $installcfg['required_theme'] : false;
  2729. $reqd_imageset = (isset($installcfg['required_imageset'])) ? $installcfg['required_imageset'] : false;
  2730. // Check to see if each element is already installed, if it is grab the id
  2731. foreach ($element_ary as $element => $table)
  2732. {
  2733. $style_row = array_merge($style_row, array(
  2734. $element . '_id' => 0,
  2735. $element . '_name' => '',
  2736. $element . '_copyright' => '')
  2737. );
  2738. $this->test_installed($element, $error, $root_path, ${'reqd_' . $element}, $style_row[$element . '_id'], $style_row[$element . '_name'], $style_row[$element . '_copyright']);
  2739. * Is this element installed? If not, grab its cfg details
  2740. */
  2741. function test_installed($element, &$error, $root_path, $reqd_name, &$id, &$name, &$copyright)
  2742. {
  2743. global $db, $user;
  2744. switch ($element)
  2745. {
  2746. case 'template':
  2747. $sql_from = STYLES_TEMPLATE_TABLE;
  2748. break;
  2749. case 'theme':
  2750. $sql_from = STYLES_THEME_TABLE;
  2751. break;
  2752. case 'imageset':
  2753. $sql_from = STYLES_IMAGESET_TABLE;
  2754. break;
  2755. }
  2756. $l_element = strtoupper($element);
  2757. $chk_name = ($reqd_name !== false) ? $reqd_name : $name;
  2758. $sql = "SELECT {$element}_id, {$element}_name
  2759. FROM $sql_from
  2760. WHERE {$element}_name = '" . $db->sql_escape($chk_name) . "'";
  2761. $result = $db->sql_query($sql);
  2762. if ($row = $db->sql_fetchrow($result))
  2763. {
  2764. $name = $row[$element . '_name'];
  2765. $id = $row[$element . '_id'];
  2766. }
  2767. else
  2768. {
  2769. if (!($cfg = @file("$root_path$element/$element.cfg")))
  2770. {
  2771. $error[] = sprintf($user->lang['REQUIRES_' . $l_element], $reqd_name);
  2772. return false;
  2773. }
  2774. $cfg = parse_cfg_file("$root_path$element/$element.cfg", $cfg);
  2775. $name = $cfg['name'];
  2776. $copyright = $cfg['copyright'];
  2777. $id = 0;
  2778. unset($cfg);
  2779. }
  2780. $db->sql_freeresult($result);
  2781. }
  2782. /**
  2783. * Install/Add style
  2784. */
  2785. function install_style(&$error, $action, $root_path, &$id, $name, $path, $copyright, $active, $default, &$style_row, $template_root_path = false, $template_path = false, $theme_root_path = false, $theme_path = false, $imageset_root_path = false, $imageset_path = false)
  2786. {
  2787. global $config, $db, $user;
  2788. $element_ary = array('template', 'theme', 'imageset');
  2789. if (!$name)
  2790. {
  2791. $error[] = $user->lang['STYLE_ERR_STYLE_NAME'];
  2792. }
  2793. // Check length settings
  2794. if (utf8_strlen($name) > 30)
  2795. {
  2796. $error[] = $user->lang['STYLE_ERR_NAME_LONG'];
  2797. }
  2798. if (utf8_strlen($copyright) > 60)
  2799. {
  2800. $error[] = $user->lang['STYLE_ERR_COPY_LONG'];
  2801. }
  2802. // Check if the name already exist
  2803. $sql = 'SELECT style_id
  2804. FROM ' . STYLES_TABLE . "
  2805. WHERE style_name = '" . $db->sql_escape($name) . "'";
  2806. $result = $db->sql_query($sql);
  2807. $row = $db->sql_fetchrow($result);
  2808. $db->sql_freeresult($result);
  2809. if ($row)
  2810. {
  2811. $error[] = $user->lang['STYLE_ERR_NAME_EXIST'];
  2812. }
  2813. if (sizeof($error))
  2814. {
  2815. return false;
  2816. }
  2817. foreach ($element_ary as $element)
  2818. {
  2819. // Zero id value ... need to install element ... run usual checks
  2820. // and do the install if necessary
  2821. if (!$style_row[$element . '_id'])
  2822. {
  2823. $this->install_element($element, $error, $action, (${$element . '_root_path'}) ? ${$element . '_root_path'} : $root_path, $style_row[$element . '_id'], $style_row[$element . '_name'], (${$element . '_path'}) ? ${$element . '_path'} : $path, $style_row[$element . '_copyright']);
  2824. }
  2825. }
  2826. if (!$style_row['template_id'] || !$style_row['theme_id'] || !$style_row['imageset_id'])
  2827. {
  2828. $error[] = $user->lang['STYLE_ERR_NO_IDS'];
  2829. }
  2830. if (sizeof($error))
  2831. {
  2832. return false;
  2833. }
  2834. $db->sql_transaction('begin');
  2835. $sql_ary = array(
  2836. 'style_name' => $name,
  2837. 'style_copyright' => $copyright,
  2838. 'style_active' => (int) $active,
  2839. 'template_id' => (int) $style_row['template_id'],
  2840. 'theme_id' => (int) $style_row['theme_id'],
  2841. 'imageset_id' => (int) $style_row['imageset_id'],
  2842. );
  2843. $sql = 'INSERT INTO ' . STYLES_TABLE . '
  2844. ' . $db->sql_build_array('INSERT', $sql_ary);
  2845. $db->sql_query($sql);
  2846. $id = $db->sql_nextid();
  2847. if ($default)
  2848. {
  2849. $sql = 'UPDATE ' . USERS_TABLE . "
  2850. SET user_style = $id
  2851. WHERE user_style = " . $config['default_style'];
  2852. $db->sql_query($sql);
  2853. set_config('default_style', $id);
  2854. }
  2855. $db->sql_transaction('commit');
  2856. add_log('admin', 'LOG_STYLE_ADD', $name);
  2857. }
  2858. /**
  2859. * Install/add an element, doing various checks as we go
  2860. */
  2861. function install_element($mode, &$error, $action, $root_path, &$id, $name, $path, $copyright, $store_db = 0)
  2862. {
  2863. global $phpbb_root_path, $db, $user;
  2864. // we parse the cfg here (again)
  2865. $cfg_data = parse_cfg_file("$root_path$mode/$mode.cfg");
  2866. switch ($mode)
  2867. {
  2868. case 'template':
  2869. $sql_from = STYLES_TEMPLATE_TABLE;
  2870. break;
  2871. case 'theme':
  2872. $sql_from = STYLES_THEME_TABLE;
  2873. break;
  2874. case 'imageset':
  2875. $sql_from = STYLES_IMAGESET_TABLE;
  2876. break;
  2877. }
  2878. $l_type = strtoupper($mode);
  2879. if (!$name)
  2880. {
  2881. $error[] = $user->lang[$l_type . '_ERR_STYLE_NAME'];
  2882. }
  2883. // Check length settings
  2884. if (utf8_strlen($name) > 30)
  2885. {
  2886. $error[] = $user->lang[$l_type . '_ERR_NAME_LONG'];
  2887. }
  2888. if (utf8_strlen($copyright) > 60)
  2889. {
  2890. $error[] = $user->lang[$l_type . '_ERR_COPY_LONG'];
  2891. }
  2892. // Check if the name already exist
  2893. $sql = "SELECT {$mode}_id
  2894. FROM $sql_from
  2895. WHERE {$mode}_name = '" . $db->sql_escape($name) . "'";
  2896. $result = $db->sql_query($sql);
  2897. $row = $db->sql_fetchrow($result);
  2898. $db->sql_freeresult($result);
  2899. if ($row)
  2900. {
  2901. // If it exist, we just use the style on installation
  2902. if ($action == 'install')
  2903. {
  2904. $id = $row[$mode . '_id'];
  2905. return false;
  2906. }
  2907. $error[] = $user->lang[$l_type . '_ERR_NAME_EXIST'];
  2908. }
  2909. if (isset($cfg_data['inherit_from']) && $cfg_data['inherit_from'])
  2910. {
  2911. if ($mode === 'template')
  2912. {
  2913. $select_bf = ', bbcode_bitfield';
  2914. }
  2915. else
  2916. {
  2917. $select_bf = '';
  2918. }
  2919. $sql = "SELECT {$mode}_id, {$mode}_name, {$mode}_path, {$mode}_storedb $select_bf
  2920. FROM $sql_from
  2921. WHERE {$mode}_name = '" . $db->sql_escape($cfg_data['inherit_from']) . "'
  2922. AND {$mode}_inherits_id = 0";
  2923. $result = $db->sql_query($sql);
  2924. $row = $db->sql_fetchrow($result);
  2925. $db->sql_freeresult($result);
  2926. if (!$row)
  2927. {
  2928. $error[] = sprintf($user->lang[$l_type . '_ERR_REQUIRED_OR_INCOMPLETE'], $cfg_data['inherit_from']);
  2929. }
  2930. else
  2931. {
  2932. $inherit_id = $row["{$mode}_id"];
  2933. $inherit_path = $row["{$mode}_path"];
  2934. $inherit_bf = ($mode === 'template') ? $row["bbcode_bitfield"] : false;
  2935. $cfg_data['store_db'] = $row["{$mode}_storedb"];
  2936. $store_db = $row["{$mode}_storedb"];
  2937. }
  2938. }
  2939. else
  2940. {
  2941. $inherit_id = 0;
  2942. $inherit_path = '';
  2943. $inherit_bf = false;
  2944. }
  2945. if (sizeof($error))
  2946. {
  2947. return false;
  2948. }
  2949. $sql_ary = array(
  2950. $mode . '_name' => $name,
  2951. $mode . '_copyright' => $copyright,
  2952. $mode . '_path' => $path,
  2953. );
  2954. switch ($mode)
  2955. {
  2956. case 'template':
  2957. // We check if the template author defined a different bitfield
  2958. if (!empty($cfg_data['template_bitfield']))
  2959. {
  2960. $sql_ary['bbcode_bitfield'] = $cfg_data['template_bitfield'];
  2961. }
  2962. else if ($inherit_bf)
  2963. {
  2964. $sql_ary['bbcode_bitfield'] = $inherit_bf;
  2965. }
  2966. else
  2967. {
  2968. $sql_ary['bbcode_bitfield'] = TEMPLATE_BITFIELD;
  2969. }
  2970. // We set a pre-defined bitfield here which we may use further in 3.2
  2971. $sql_ary += array(
  2972. 'template_storedb' => $store_db,
  2973. );
  2974. if (isset($cfg_data['inherit_from']) && $cfg_data['inherit_from'])
  2975. {
  2976. $sql_ary += array(
  2977. 'template_inherits_id' => $inherit_id,
  2978. 'template_inherit_path' => $inherit_path,
  2979. );
  2980. }
  2981. break;
  2982. case 'theme':
  2983. // We are only interested in the theme configuration for now
  2984. if (isset($cfg_data['parse_css_file']) && $cfg_data['parse_css_file'])
  2985. {
  2986. $store_db = 1;
  2987. }
  2988. $sql_ary += array(
  2989. 'theme_storedb' => $store_db,
  2990. 'theme_data' => ($store_db) ? $this->db_theme_data($sql_ary, false, $root_path) : '',
  2991. 'theme_mtime' => (int) filemtime("{$phpbb_root_path}styles/$path/theme/stylesheet.css")
  2992. );
  2993. break;
  2994. // all the heavy lifting is done later
  2995. case 'imageset':
  2996. break;
  2997. }
  2998. $db->sql_transaction('begin');
  2999. $sql = "INSERT INTO $sql_from
  3000. " . $db->sql_build_array('INSERT', $sql_ary);
  3001. $db->sql_query($sql);
  3002. $id = $db->sql_nextid();
  3003. if ($mode == 'template' && $store_db)
  3004. {
  3005. $filelist = filelist("{$root_path}template", '', 'html');
  3006. $this->store_templates('insert', $id, $path, $filelist);
  3007. }
  3008. else if ($mode == 'imageset')
  3009. {
  3010. $cfg_data = parse_cfg_file("$root_path$mode/imageset.cfg");
  3011. $imageset_definitions = array();
  3012. foreach ($this->imageset_keys as $topic => $key_array)
  3013. {
  3014. $imageset_definitions = array_merge($imageset_definitions, $key_array);
  3015. }
  3016. foreach ($cfg_data as $key => $value)
  3017. {
  3018. if (strpos($value, '*') !== false)
  3019. {
  3020. if (substr($value, -1, 1) === '*')
  3021. {
  3022. list($image_filename, $image_height) = explode('*', $value);
  3023. $image_width = 0;
  3024. }
  3025. else
  3026. {
  3027. list($image_filename, $image_height, $image_width) = explode('*', $value);
  3028. }
  3029. }
  3030. else
  3031. {
  3032. $image_filename = $value;
  3033. $image_height = $image_width = 0;
  3034. }
  3035. if (strpos($key, 'img_') === 0 && $image_filename)
  3036. {
  3037. $key = substr($key, 4);
  3038. if (in_array($key, $imageset_definitions))
  3039. {
  3040. $sql_ary = array(
  3041. 'image_name' => $key,
  3042. 'image_filename' => str_replace('{PATH}', "styles/$path/imageset/", trim($image_filename)),
  3043. 'image_height' => (int) $image_height,
  3044. 'image_width' => (int) $image_width,
  3045. 'imageset_id' => (int) $id,
  3046. 'image_lang' => '',
  3047. );
  3048. $db->sql_query('INSERT INTO ' . STYLES_IMAGESET_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
  3049. }
  3050. }
  3051. }
  3052. unset($cfg_data);
  3053. $sql = 'SELECT lang_dir
  3054. FROM ' . LANG_TABLE;
  3055. $result = $db->sql_query($sql);
  3056. while ($row = $db->sql_fetchrow($result))
  3057. {
  3058. if (@file_exists("$root_path$mode/{$row['lang_dir']}/imageset.cfg"))
  3059. {
  3060. $cfg_data_imageset_data = parse_cfg_file("$root_path$mode/{$row['lang_dir']}/imageset.cfg");
  3061. foreach ($cfg_data_imageset_data as $image_name => $value)
  3062. {
  3063. if (strpos($value, '*') !== false)
  3064. {
  3065. if (substr($value, -1, 1) === '*')
  3066. {
  3067. list($image_filename, $image_height) = explode('*', $value);
  3068. $image_width = 0;
  3069. }
  3070. else
  3071. {
  3072. list($image_filename, $image_height, $image_width) = explode('*', $value);
  3073. }
  3074. }
  3075. else
  3076. {
  3077. $image_filename = $value;
  3078. $image_height = $image_width = 0;
  3079. }
  3080. if (strpos($image_name, 'img_') === 0 && $image_filename)
  3081. {
  3082. $image_name = substr($image_name, 4);
  3083. if (in_array($image_name, $imageset_definitions))
  3084. {
  3085. $sql_ary = array(
  3086. 'image_name' => $image_name,
  3087. 'image_filename' => $image_filename,
  3088. 'image_height' => (int) $image_height,
  3089. 'image_width' => (int) $image_width,
  3090. 'imageset_id' => (int) $id,
  3091. 'image_lang' => $row['lang_dir'],
  3092. );
  3093. $db->sql_query('INSERT INTO ' . STYLES_IMAGESET_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
  3094. }
  3095. }
  3096. }
  3097. unset($cfg_data_imageset_data);
  3098. }
  3099. }
  3100. $db->sql_freeresult($result);
  3101. }
  3102. $db->sql_transaction('commit');
  3103. $log = ($store_db) ? 'LOG_' . $l_type . '_ADD_DB' : 'LOG_' . $l_type . '_ADD_FS';
  3104. add_log('admin', $log, $name);
  3105. // Return store_db in case it had to be altered
  3106. return $store_db;
  3107. }
  3108. /**
  3109. * Checks downwards dependencies
  3110. *
  3111. * @access public
  3112. * @param string $mode The element type to check - only template is supported
  3113. * @param int $id The template id
  3114. * @returns false if no component inherits, array with name, path and id for each subtemplate otherwise
  3115. */
  3116. function check_inheritance($mode, $id)
  3117. {
  3118. global $db;
  3119. $l_type = strtoupper($mode);
  3120. switch ($mode)
  3121. {
  3122. case 'template':
  3123. $sql_from = STYLES_TEMPLATE_TABLE;
  3124. break;
  3125. case 'theme':
  3126. $sql_from = STYLES_THEME_TABLE;
  3127. break;
  3128. case 'imageset':
  3129. $sql_from = STYLES_IMAGESET_TABLE;
  3130. break;
  3131. }
  3132. $sql = "SELECT {$mode}_id, {$mode}_name, {$mode}_path
  3133. FROM $sql_from
  3134. WHERE {$mode}_inherits_id = " . (int) $id;
  3135. $result = $db->sql_query($sql);
  3136. $names = array();
  3137. while ($row = $db->sql_fetchrow($result))
  3138. {
  3139. $names[$row["{$mode}_id"]] = array(
  3140. "{$mode}_id" => $row["{$mode}_id"],
  3141. "{$mode}_name" => $row["{$mode}_name"],
  3142. "{$mode}_path" => $row["{$mode}_path"],
  3143. );
  3144. }
  3145. $db->sql_freeresult($result);
  3146. if (sizeof($names))
  3147. {
  3148. return $names;
  3149. }
  3150. else
  3151. {
  3152. return false;
  3153. }
  3154. }
  3155. /**
  3156. * Checks upwards dependencies
  3157. *
  3158. * @access public
  3159. * @param string $mode The element type to check - only template is supported
  3160. * @param int $id The template id
  3161. * @returns false if the component does not inherit, array with name, path and id otherwise
  3162. */
  3163. function get_super($mode, $id)
  3164. {
  3165. global $db;
  3166. $l_type = strtoupper($mode);
  3167. switch ($mode)
  3168. {
  3169. case 'template':
  3170. $sql_from = STYLES_TEMPLATE_TABLE;
  3171. break;
  3172. case 'theme':
  3173. $sql_from = STYLES_THEME_TABLE;
  3174. break;
  3175. case 'imageset':
  3176. $sql_from = STYLES_IMAGESET_TABLE;
  3177. break;
  3178. }
  3179. $sql = "SELECT {$mode}_inherits_id
  3180. FROM $sql_from
  3181. WHERE {$mode}_id = " . (int) $id;
  3182. $result = $db->sql_query_limit($sql, 1);
  3183. if ($row = $db->sql_fetchrow($result))
  3184. {
  3185. $db->sql_freeresult($result);
  3186. }
  3187. else
  3188. {
  3189. return false;
  3190. }
  3191. $super_id = $row["{$mode}_inherits_id"];
  3192. $sql = "SELECT {$mode}_id, {$mode}_name, {$mode}_path
  3193. FROM $sql_from
  3194. WHERE {$mode}_id = " . (int) $super_id;
  3195. $result = $db->sql_query_limit($sql, 1);
  3196. if ($row = $db->sql_fetchrow($result))
  3197. {
  3198. $db->sql_freeresult($result);
  3199. return $row;
  3200. }
  3201. return false;
  3202. }
  3203. /**
  3204. * Moves a template set and its subtemplates to the database
  3205. *
  3206. * @access public
  3207. * @param string $mode The component to move - only template is supported
  3208. * @param int $id The template id
  3209. */
  3210. function store_in_db($mode, $id)
  3211. {
  3212. global $db, $user;
  3213. $error = array();
  3214. $l_type = strtoupper($mode);
  3215. if ($super = $this->get_super($mode, $id))
  3216. {
  3217. $error[] = (sprintf($user->lang["{$l_type}_INHERITS"], $super['template_name']));
  3218. return $error;
  3219. }
  3220. $sql = "SELECT {$mode}_id, {$mode}_name, {$mode}_path
  3221. FROM " . STYLES_TEMPLATE_TABLE . '
  3222. WHERE template_id = ' . (int) $id;
  3223. $result = $db->sql_query_limit($sql, 1);
  3224. if ($row = $db->sql_fetchrow($result))
  3225. {
  3226. $db->sql_freeresult($result);
  3227. $subs = $this->check_inheritance($mode, $id);
  3228. $this->_store_in_db($mode, $id, $row["{$mode}_path"]);
  3229. if ($subs && sizeof($subs))
  3230. {
  3231. foreach ($subs as $sub_id => $sub)
  3232. {
  3233. if ($err = $this->_store_in_db($mode, $sub["{$mode}_id"], $sub["{$mode}_path"]))
  3234. {
  3235. $error[] = $err;
  3236. }
  3237. }
  3238. }
  3239. }
  3240. if (sizeof($error))
  3241. {
  3242. return $error;
  3243. }
  3244. return false;
  3245. }
  3246. /**
  3247. * Moves a template set to the database
  3248. *
  3249. * @access private
  3250. * @param string $mode The component to move - only template is supported
  3251. * @param int $id The template id
  3252. * @param string $path TThe path to the template files
  3253. */
  3254. function _store_in_db($mode, $id, $path)
  3255. {
  3256. global $phpbb_root_path, $db;
  3257. $filelist = filelist("{$phpbb_root_path}styles/{$path}/template", '', 'html');
  3258. $this->store_templates('insert', $id, $path, $filelist);
  3259. // Okay, we do the query here -shouldn't be triggered often.
  3260. $sql = 'UPDATE ' . STYLES_TEMPLATE_TABLE . '
  3261. SET template_storedb = 1
  3262. WHERE template_id = ' . $id;
  3263. $db->sql_query($sql);
  3264. }
  3265. /**
  3266. * Moves a template set and its subtemplates to the filesystem
  3267. *
  3268. * @access public
  3269. * @param string $mode The component to move - only template is supported
  3270. * @param int $id The template id
  3271. */
  3272. function store_in_fs($mode, $id)
  3273. {
  3274. global $db, $user;
  3275. $error = array();
  3276. $l_type = strtoupper($mode);
  3277. if ($super = $this->get_super($mode, $id))
  3278. {
  3279. $error[] = (sprintf($user->lang["{$l_type}_INHERITS"], $super['template_name']));
  3280. return($error);
  3281. }
  3282. $sql = "SELECT {$mode}_id, {$mode}_name, {$mode}_path
  3283. FROM " . STYLES_TEMPLATE_TABLE . '
  3284. WHERE template_id = ' . (int) $id;
  3285. $result = $db->sql_query_limit($sql, 1);
  3286. if ($row = $db->sql_fetchrow($result))
  3287. {
  3288. $db->sql_freeresult($result);
  3289. if (!sizeof($error))
  3290. {
  3291. $subs = $this->check_inheritance($mode, $id);
  3292. $this->_store_in_fs($mode, $id, $row["{$mode}_path"]);
  3293. if ($subs && sizeof($subs))
  3294. {
  3295. foreach ($subs as $sub_id => $sub)
  3296. {
  3297. $this->_store_in_fs($mode, $sub["{$mode}_id"], $sub["{$mode}_path"]);
  3298. }
  3299. }
  3300. }
  3301. if (sizeof($error))
  3302. {
  3303. $this->store_in_db($id, $mode);
  3304. return $error;
  3305. }
  3306. }
  3307. return false;
  3308. }
  3309. /**
  3310. * Moves a template set to the filesystem
  3311. *
  3312. * @access private
  3313. * @param string $mode The component to move - only template is supported
  3314. * @param int $id The template id
  3315. * @param string $path The path to the template
  3316. */
  3317. function _store_in_fs($mode, $id, $path)
  3318. {
  3319. global $phpbb_root_path, $db, $user, $safe_mode;
  3320. $store_db = 0;
  3321. $error = array();
  3322. if (!$safe_mode && phpbb_is_writable("{$phpbb_root_path}styles/{$path}/template"))
  3323. {
  3324. $sql = 'SELECT *
  3325. FROM ' . STYLES_TEMPLATE_DATA_TABLE . "
  3326. WHERE template_id = $id";
  3327. $result = $db->sql_query($sql);
  3328. while ($row = $db->sql_fetchrow($result))
  3329. {
  3330. if (!($fp = @fopen("{$phpbb_root_path}styles/{$path}/template/" . $row['template_filename'], 'wb')))
  3331. {
  3332. $store_db = 1;
  3333. $error[] = $user->lang['EDIT_TEMPLATE_STORED_DB'];
  3334. break;
  3335. }
  3336. fwrite($fp, $row['template_data']);
  3337. fclose($fp);
  3338. }
  3339. $db->sql_freeresult($result);
  3340. if (!$store_db)
  3341. {
  3342. $sql = 'DELETE FROM ' . STYLES_TEMPLATE_DATA_TABLE . "
  3343. WHERE template_id = $id";
  3344. $db->sql_query($sql);
  3345. }
  3346. }
  3347. if (sizeof($error))
  3348. {
  3349. return $error;
  3350. }
  3351. $sql = 'UPDATE ' . STYLES_TEMPLATE_TABLE . '
  3352. SET template_storedb = 0
  3353. WHERE template_id = ' . $id;
  3354. $db->sql_query($sql);
  3355. return false;
  3356. }
  3357. }
  3358. ?>