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

/station/forum/includes/acp/acp_styles.php

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