Yoshi2889 /
SMF2.1
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * This file concerns itself almost completely with theme administration. |
||
| 5 | * Its tasks include changing theme settings, installing and removing |
||
| 6 | * themes, choosing the current theme, and editing themes. |
||
| 7 | * |
||
| 8 | * @todo Update this for the new package manager? |
||
| 9 | * |
||
| 10 | * Creating and distributing theme packages: |
||
| 11 | * There isn't that much required to package and distribute your own themes... |
||
| 12 | * just do the following: |
||
| 13 | * - create a theme_info.xml file, with the root element theme-info. |
||
| 14 | * - its name should go in a name element, just like description. |
||
| 15 | * - your name should go in author. (email in the email attribute.) |
||
| 16 | * - any support website for the theme should be in website. |
||
| 17 | * - layers and templates (non-default) should go in those elements ;). |
||
| 18 | * - if the images dir isn't images, specify in the images element. |
||
| 19 | * - any extra rows for themes should go in extra, serialized. (as in array(variable => value).) |
||
| 20 | * - tar and gzip the directory - and you're done! |
||
| 21 | * - please include any special license in a license.txt file. |
||
| 22 | * |
||
| 23 | * Simple Machines Forum (SMF) |
||
| 24 | * |
||
| 25 | * @package SMF |
||
| 26 | * @author Simple Machines http://www.simplemachines.org |
||
| 27 | * @copyright 2019 Simple Machines and individual contributors |
||
| 28 | * @license http://www.simplemachines.org/about/smf/license.php BSD |
||
| 29 | * |
||
| 30 | * @version 2.1 RC2 |
||
| 31 | */ |
||
| 32 | |||
| 33 | if (!defined('SMF')) |
||
| 34 | die('No direct access...'); |
||
| 35 | |||
| 36 | /** |
||
| 37 | * Subaction handler - manages the action and delegates control to the proper |
||
| 38 | * sub-action. |
||
| 39 | * It loads both the Themes and Settings language files. |
||
| 40 | * Checks the session by GET or POST to verify the sent data. |
||
| 41 | * Requires the user not be a guest. (@todo what?) |
||
| 42 | * Accessed via ?action=admin;area=theme. |
||
| 43 | */ |
||
| 44 | function ThemesMain() |
||
| 45 | { |
||
| 46 | global $txt, $context, $sourcedir; |
||
| 47 | |||
| 48 | // Load the important language files... |
||
| 49 | loadLanguage('Themes'); |
||
| 50 | loadLanguage('Settings'); |
||
| 51 | loadLanguage('Drafts'); |
||
| 52 | |||
| 53 | // No funny business - guests only. |
||
| 54 | is_not_guest(); |
||
| 55 | |||
| 56 | require_once($sourcedir . '/Subs-Themes.php'); |
||
| 57 | |||
| 58 | // Default the page title to Theme Administration by default. |
||
| 59 | $context['page_title'] = $txt['themeadmin_title']; |
||
| 60 | |||
| 61 | // Theme administration, removal, choice, or installation... |
||
| 62 | $subActions = array( |
||
| 63 | 'admin' => 'ThemeAdmin', |
||
| 64 | 'list' => 'ThemeList', |
||
| 65 | 'reset' => 'SetThemeOptions', |
||
| 66 | 'options' => 'SetThemeOptions', |
||
| 67 | 'install' => 'ThemeInstall', |
||
| 68 | 'remove' => 'RemoveTheme', |
||
| 69 | 'pick' => 'PickTheme', |
||
| 70 | 'edit' => 'EditTheme', |
||
| 71 | 'enable' => 'EnableTheme', |
||
| 72 | 'copy' => 'CopyTemplate', |
||
| 73 | ); |
||
| 74 | |||
| 75 | // @todo Layout Settings? huh? |
||
| 76 | if (!empty($context['admin_menu_name'])) |
||
| 77 | { |
||
| 78 | $context[$context['admin_menu_name']]['tab_data'] = array( |
||
| 79 | 'title' => $txt['themeadmin_title'], |
||
| 80 | 'help' => 'themes', |
||
| 81 | 'description' => $txt['themeadmin_description'], |
||
| 82 | 'tabs' => array( |
||
| 83 | 'admin' => array( |
||
| 84 | 'description' => $txt['themeadmin_admin_desc'], |
||
| 85 | ), |
||
| 86 | 'list' => array( |
||
| 87 | 'description' => $txt['themeadmin_list_desc'], |
||
| 88 | ), |
||
| 89 | 'reset' => array( |
||
| 90 | 'description' => $txt['themeadmin_reset_desc'], |
||
| 91 | ), |
||
| 92 | 'edit' => array( |
||
| 93 | 'description' => $txt['themeadmin_edit_desc'], |
||
| 94 | ), |
||
| 95 | ), |
||
| 96 | ); |
||
| 97 | } |
||
| 98 | |||
| 99 | // CRUD $subActions as needed. |
||
| 100 | call_integration_hook('integrate_manage_themes', array(&$subActions)); |
||
| 101 | |||
| 102 | // Whatever you decide to do, clean the minify cache. |
||
| 103 | cache_put_data('minimized_css', null); |
||
| 104 | |||
| 105 | // Follow the sa or just go to administration. |
||
| 106 | if (isset($_GET['sa']) && !empty($subActions[$_GET['sa']])) |
||
| 107 | call_helper($subActions[$_GET['sa']]); |
||
| 108 | |||
| 109 | else |
||
| 110 | call_helper($subActions['admin']); |
||
| 111 | } |
||
| 112 | |||
| 113 | /** |
||
| 114 | * This function allows administration of themes and their settings, |
||
| 115 | * as well as global theme settings. |
||
| 116 | * - sets the settings theme_allow, theme_guests, and knownThemes. |
||
| 117 | * - requires the admin_forum permission. |
||
| 118 | * - accessed with ?action=admin;area=theme;sa=admin. |
||
| 119 | * |
||
| 120 | * @uses Themes template |
||
| 121 | * @uses Admin language file |
||
| 122 | */ |
||
| 123 | function ThemeAdmin() |
||
| 124 | { |
||
| 125 | global $context, $boarddir; |
||
| 126 | |||
| 127 | // Are handling any settings? |
||
| 128 | if (isset($_POST['save'])) |
||
| 129 | { |
||
| 130 | checkSession(); |
||
| 131 | validateToken('admin-tm'); |
||
| 132 | |||
| 133 | if (isset($_POST['options']['known_themes'])) |
||
| 134 | foreach ($_POST['options']['known_themes'] as $key => $id) |
||
| 135 | $_POST['options']['known_themes'][$key] = (int) $id; |
||
| 136 | |||
| 137 | else |
||
| 138 | fatal_lang_error('themes_none_selectable', false); |
||
| 139 | |||
| 140 | if (!in_array($_POST['options']['theme_guests'], $_POST['options']['known_themes'])) |
||
| 141 | fatal_lang_error('themes_default_selectable', false); |
||
| 142 | |||
| 143 | // Commit the new settings. |
||
| 144 | updateSettings(array( |
||
| 145 | 'theme_allow' => $_POST['options']['theme_allow'], |
||
| 146 | 'theme_guests' => $_POST['options']['theme_guests'], |
||
| 147 | 'knownThemes' => implode(',', $_POST['options']['known_themes']), |
||
| 148 | )); |
||
| 149 | if ((int) $_POST['theme_reset'] == 0 || in_array($_POST['theme_reset'], $_POST['options']['known_themes'])) |
||
| 150 | updateMemberData(null, array('id_theme' => (int) $_POST['theme_reset'])); |
||
| 151 | |||
| 152 | redirectexit('action=admin;area=theme;' . $context['session_var'] . '=' . $context['session_id'] . ';sa=admin'); |
||
| 153 | } |
||
| 154 | |||
| 155 | loadLanguage('Admin'); |
||
| 156 | isAllowedTo('admin_forum'); |
||
| 157 | loadTemplate('Themes'); |
||
| 158 | |||
| 159 | // List all enabled themes. |
||
| 160 | get_all_themes(true); |
||
| 161 | |||
| 162 | // Can we create a new theme? |
||
| 163 | $context['can_create_new'] = is_writable($boarddir . '/Themes'); |
||
| 164 | $context['new_theme_dir'] = substr(realpath($boarddir . '/Themes/default'), 0, -7); |
||
| 165 | |||
| 166 | // Look for a non existent theme directory. (ie theme87.) |
||
| 167 | $theme_dir = $boarddir . '/Themes/theme'; |
||
| 168 | $i = 1; |
||
| 169 | while (file_exists($theme_dir . $i)) |
||
| 170 | $i++; |
||
| 171 | |||
| 172 | $context['new_theme_name'] = 'theme' . $i; |
||
| 173 | |||
| 174 | // A bunch of tokens for a bunch of forms. |
||
| 175 | createToken('admin-tm'); |
||
| 176 | createToken('admin-t-file'); |
||
| 177 | createToken('admin-t-copy'); |
||
| 178 | createToken('admin-t-dir'); |
||
| 179 | } |
||
| 180 | |||
| 181 | /** |
||
| 182 | * This function lists the available themes and provides an interface to reset |
||
| 183 | * the paths of all the installed themes. |
||
| 184 | */ |
||
| 185 | function ThemeList() |
||
| 186 | { |
||
| 187 | global $context, $boarddir, $boardurl, $smcFunc; |
||
| 188 | |||
| 189 | loadLanguage('Admin'); |
||
| 190 | isAllowedTo('admin_forum'); |
||
| 191 | |||
| 192 | if (isset($_REQUEST['th'])) |
||
| 193 | return SetThemeSettings(); |
||
| 194 | |||
| 195 | if (isset($_POST['save'])) |
||
| 196 | { |
||
| 197 | checkSession(); |
||
| 198 | validateToken('admin-tl'); |
||
| 199 | |||
| 200 | // Calling the almighty power of global vars! |
||
| 201 | get_installed_themes(); |
||
| 202 | |||
| 203 | $setValues = array(); |
||
| 204 | foreach ($context['themes'] as $id => $theme) |
||
| 205 | { |
||
| 206 | if (file_exists($_POST['reset_dir'] . '/' . basename($theme['theme_dir']))) |
||
| 207 | { |
||
| 208 | $setValues[] = array($id, 0, 'theme_dir', realpath($_POST['reset_dir'] . '/' . basename($theme['theme_dir']))); |
||
| 209 | $setValues[] = array($id, 0, 'theme_url', $_POST['reset_url'] . '/' . basename($theme['theme_dir'])); |
||
| 210 | $setValues[] = array($id, 0, 'images_url', $_POST['reset_url'] . '/' . basename($theme['theme_dir']) . '/' . basename($theme['images_url'])); |
||
| 211 | } |
||
| 212 | |||
| 213 | if (isset($theme['base_theme_dir']) && file_exists($_POST['reset_dir'] . '/' . basename($theme['base_theme_dir']))) |
||
| 214 | { |
||
| 215 | $setValues[] = array($id, 0, 'base_theme_dir', realpath($_POST['reset_dir'] . '/' . basename($theme['base_theme_dir']))); |
||
| 216 | $setValues[] = array($id, 0, 'base_theme_url', $_POST['reset_url'] . '/' . basename($theme['base_theme_dir'])); |
||
| 217 | $setValues[] = array($id, 0, 'base_images_url', $_POST['reset_url'] . '/' . basename($theme['base_theme_dir']) . '/' . basename($theme['base_images_url'])); |
||
| 218 | } |
||
| 219 | |||
| 220 | cache_put_data('theme_settings-' . $id, null, 90); |
||
| 221 | } |
||
| 222 | |||
| 223 | if (!empty($setValues)) |
||
| 224 | { |
||
| 225 | $smcFunc['db_insert']('replace', |
||
| 226 | '{db_prefix}themes', |
||
| 227 | array('id_theme' => 'int', 'id_member' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), |
||
| 228 | $setValues, |
||
| 229 | array('id_theme', 'variable', 'id_member') |
||
| 230 | ); |
||
| 231 | } |
||
| 232 | |||
| 233 | redirectexit('action=admin;area=theme;sa=list;' . $context['session_var'] . '=' . $context['session_id']); |
||
| 234 | } |
||
| 235 | |||
| 236 | loadTemplate('Themes'); |
||
| 237 | |||
| 238 | // Get all installed themes. |
||
| 239 | get_installed_themes(); |
||
| 240 | |||
| 241 | $context['reset_dir'] = realpath($boarddir . '/Themes'); |
||
| 242 | $context['reset_url'] = $boardurl . '/Themes'; |
||
| 243 | |||
| 244 | $context['sub_template'] = 'list_themes'; |
||
| 245 | createToken('admin-tl'); |
||
| 246 | createToken('admin-tr', 'request'); |
||
| 247 | createToken('admin-tre', 'request'); |
||
| 248 | } |
||
| 249 | |||
| 250 | /** |
||
| 251 | * Administrative global settings. |
||
| 252 | */ |
||
| 253 | function SetThemeOptions() |
||
| 254 | { |
||
| 255 | global $txt, $context, $settings, $modSettings, $smcFunc; |
||
| 256 | |||
| 257 | $_GET['th'] = isset($_GET['th']) ? (int) $_GET['th'] : (isset($_GET['id']) ? (int) $_GET['id'] : 0); |
||
| 258 | |||
| 259 | isAllowedTo('admin_forum'); |
||
| 260 | |||
| 261 | if (empty($_GET['th']) && empty($_GET['id'])) |
||
| 262 | { |
||
| 263 | $request = $smcFunc['db_query']('', ' |
||
| 264 | SELECT id_theme, variable, value |
||
| 265 | FROM {db_prefix}themes |
||
| 266 | WHERE variable IN ({string:name}, {string:theme_dir}) |
||
| 267 | AND id_member = {int:no_member}', |
||
| 268 | array( |
||
| 269 | 'no_member' => 0, |
||
| 270 | 'name' => 'name', |
||
| 271 | 'theme_dir' => 'theme_dir', |
||
| 272 | ) |
||
| 273 | ); |
||
| 274 | $context['themes'] = array(); |
||
| 275 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 276 | { |
||
| 277 | if (!isset($context['themes'][$row['id_theme']])) |
||
| 278 | $context['themes'][$row['id_theme']] = array( |
||
| 279 | 'id' => $row['id_theme'], |
||
| 280 | 'num_default_options' => 0, |
||
| 281 | 'num_members' => 0, |
||
| 282 | ); |
||
| 283 | $context['themes'][$row['id_theme']][$row['variable']] = $row['value']; |
||
| 284 | } |
||
| 285 | $smcFunc['db_free_result']($request); |
||
| 286 | |||
| 287 | $request = $smcFunc['db_query']('', ' |
||
| 288 | SELECT id_theme, COUNT(*) AS value |
||
| 289 | FROM {db_prefix}themes |
||
| 290 | WHERE id_member = {int:guest_member} |
||
| 291 | GROUP BY id_theme', |
||
| 292 | array( |
||
| 293 | 'guest_member' => -1, |
||
| 294 | ) |
||
| 295 | ); |
||
| 296 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 297 | $context['themes'][$row['id_theme']]['num_default_options'] = $row['value']; |
||
| 298 | $smcFunc['db_free_result']($request); |
||
| 299 | |||
| 300 | // Need to make sure we don't do custom fields. |
||
| 301 | $request = $smcFunc['db_query']('', ' |
||
| 302 | SELECT col_name |
||
| 303 | FROM {db_prefix}custom_fields', |
||
| 304 | array( |
||
| 305 | ) |
||
| 306 | ); |
||
| 307 | $customFields = array(); |
||
| 308 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 309 | $customFields[] = $row['col_name']; |
||
| 310 | $smcFunc['db_free_result']($request); |
||
| 311 | $customFieldsQuery = empty($customFields) ? '' : ('AND variable NOT IN ({array_string:custom_fields})'); |
||
| 312 | |||
| 313 | $request = $smcFunc['db_query']('themes_count', ' |
||
| 314 | SELECT COUNT(DISTINCT id_member) AS value, id_theme |
||
| 315 | FROM {db_prefix}themes |
||
| 316 | WHERE id_member > {int:no_member} |
||
| 317 | ' . $customFieldsQuery . ' |
||
| 318 | GROUP BY id_theme', |
||
| 319 | array( |
||
| 320 | 'no_member' => 0, |
||
| 321 | 'custom_fields' => empty($customFields) ? array() : $customFields, |
||
| 322 | ) |
||
| 323 | ); |
||
| 324 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 325 | $context['themes'][$row['id_theme']]['num_members'] = $row['value']; |
||
| 326 | $smcFunc['db_free_result']($request); |
||
| 327 | |||
| 328 | // There has to be a Settings template! |
||
| 329 | foreach ($context['themes'] as $k => $v) |
||
| 330 | if (empty($v['theme_dir']) || (!file_exists($v['theme_dir'] . '/Settings.template.php') && empty($v['num_members']))) |
||
| 331 | unset($context['themes'][$k]); |
||
| 332 | |||
| 333 | loadTemplate('Themes'); |
||
| 334 | $context['sub_template'] = 'reset_list'; |
||
| 335 | |||
| 336 | createToken('admin-stor', 'request'); |
||
| 337 | return; |
||
| 338 | } |
||
| 339 | |||
| 340 | // Submit? |
||
| 341 | if (isset($_POST['submit']) && empty($_POST['who'])) |
||
| 342 | { |
||
| 343 | checkSession(); |
||
| 344 | validateToken('admin-sto'); |
||
| 345 | |||
| 346 | if (empty($_POST['options'])) |
||
| 347 | $_POST['options'] = array(); |
||
| 348 | if (empty($_POST['default_options'])) |
||
| 349 | $_POST['default_options'] = array(); |
||
| 350 | |||
| 351 | // Set up the sql query. |
||
| 352 | $setValues = array(); |
||
| 353 | |||
| 354 | foreach ($_POST['options'] as $opt => $val) |
||
| 355 | $setValues[] = array(-1, $_GET['th'], $opt, is_array($val) ? implode(',', $val) : $val); |
||
| 356 | |||
| 357 | $old_settings = array(); |
||
| 358 | foreach ($_POST['default_options'] as $opt => $val) |
||
| 359 | { |
||
| 360 | $old_settings[] = $opt; |
||
| 361 | |||
| 362 | $setValues[] = array(-1, 1, $opt, is_array($val) ? implode(',', $val) : $val); |
||
| 363 | } |
||
| 364 | |||
| 365 | // If we're actually inserting something.. |
||
| 366 | if (!empty($setValues)) |
||
| 367 | { |
||
| 368 | // Are there options in non-default themes set that should be cleared? |
||
| 369 | if (!empty($old_settings)) |
||
| 370 | $smcFunc['db_query']('', ' |
||
| 371 | DELETE FROM {db_prefix}themes |
||
| 372 | WHERE id_theme != {int:default_theme} |
||
| 373 | AND id_member = {int:guest_member} |
||
| 374 | AND variable IN ({array_string:old_settings})', |
||
| 375 | array( |
||
| 376 | 'default_theme' => 1, |
||
| 377 | 'guest_member' => -1, |
||
| 378 | 'old_settings' => $old_settings, |
||
| 379 | ) |
||
| 380 | ); |
||
| 381 | |||
| 382 | $smcFunc['db_insert']('replace', |
||
| 383 | '{db_prefix}themes', |
||
| 384 | array('id_member' => 'int', 'id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), |
||
| 385 | $setValues, |
||
| 386 | array('id_theme', 'variable', 'id_member') |
||
| 387 | ); |
||
| 388 | } |
||
| 389 | |||
| 390 | cache_put_data('theme_settings-' . $_GET['th'], null, 90); |
||
| 391 | cache_put_data('theme_settings-1', null, 90); |
||
| 392 | |||
| 393 | redirectexit('action=admin;area=theme;' . $context['session_var'] . '=' . $context['session_id'] . ';sa=reset'); |
||
| 394 | } |
||
| 395 | elseif (isset($_POST['submit']) && $_POST['who'] == 1) |
||
| 396 | { |
||
| 397 | checkSession(); |
||
| 398 | validateToken('admin-sto'); |
||
| 399 | |||
| 400 | $_POST['options'] = empty($_POST['options']) ? array() : $_POST['options']; |
||
| 401 | $_POST['options_master'] = empty($_POST['options_master']) ? array() : $_POST['options_master']; |
||
| 402 | $_POST['default_options'] = empty($_POST['default_options']) ? array() : $_POST['default_options']; |
||
| 403 | $_POST['default_options_master'] = empty($_POST['default_options_master']) ? array() : $_POST['default_options_master']; |
||
| 404 | |||
| 405 | $old_settings = array(); |
||
| 406 | foreach ($_POST['default_options'] as $opt => $val) |
||
| 407 | { |
||
| 408 | if ($_POST['default_options_master'][$opt] == 0) |
||
| 409 | continue; |
||
| 410 | elseif ($_POST['default_options_master'][$opt] == 1) |
||
| 411 | { |
||
| 412 | // Delete then insert for ease of database compatibility! |
||
| 413 | $smcFunc['db_query']('substring', ' |
||
| 414 | DELETE FROM {db_prefix}themes |
||
| 415 | WHERE id_theme = {int:default_theme} |
||
| 416 | AND id_member != {int:no_member} |
||
| 417 | AND variable = SUBSTRING({string:option}, 1, 255)', |
||
| 418 | array( |
||
| 419 | 'default_theme' => 1, |
||
| 420 | 'no_member' => 0, |
||
| 421 | 'option' => $opt, |
||
| 422 | ) |
||
| 423 | ); |
||
| 424 | $smcFunc['db_query']('substring', ' |
||
| 425 | INSERT INTO {db_prefix}themes |
||
| 426 | (id_member, id_theme, variable, value) |
||
| 427 | SELECT id_member, 1, SUBSTRING({string:option}, 1, 255), SUBSTRING({string:value}, 1, 65534) |
||
| 428 | FROM {db_prefix}members', |
||
| 429 | array( |
||
| 430 | 'option' => $opt, |
||
| 431 | 'value' => (is_array($val) ? implode(',', $val) : $val), |
||
| 432 | ) |
||
| 433 | ); |
||
| 434 | |||
| 435 | $old_settings[] = $opt; |
||
| 436 | } |
||
| 437 | elseif ($_POST['default_options_master'][$opt] == 2) |
||
| 438 | { |
||
| 439 | $smcFunc['db_query']('', ' |
||
| 440 | DELETE FROM {db_prefix}themes |
||
| 441 | WHERE variable = {string:option_name} |
||
| 442 | AND id_member > {int:no_member}', |
||
| 443 | array( |
||
| 444 | 'no_member' => 0, |
||
| 445 | 'option_name' => $opt, |
||
| 446 | ) |
||
| 447 | ); |
||
| 448 | } |
||
| 449 | } |
||
| 450 | |||
| 451 | // Delete options from other themes. |
||
| 452 | if (!empty($old_settings)) |
||
| 453 | $smcFunc['db_query']('', ' |
||
| 454 | DELETE FROM {db_prefix}themes |
||
| 455 | WHERE id_theme != {int:default_theme} |
||
| 456 | AND id_member > {int:no_member} |
||
| 457 | AND variable IN ({array_string:old_settings})', |
||
| 458 | array( |
||
| 459 | 'default_theme' => 1, |
||
| 460 | 'no_member' => 0, |
||
| 461 | 'old_settings' => $old_settings, |
||
| 462 | ) |
||
| 463 | ); |
||
| 464 | |||
| 465 | foreach ($_POST['options'] as $opt => $val) |
||
| 466 | { |
||
| 467 | if ($_POST['options_master'][$opt] == 0) |
||
| 468 | continue; |
||
| 469 | elseif ($_POST['options_master'][$opt] == 1) |
||
| 470 | { |
||
| 471 | // Delete then insert for ease of database compatibility - again! |
||
| 472 | $smcFunc['db_query']('substring', ' |
||
| 473 | DELETE FROM {db_prefix}themes |
||
| 474 | WHERE id_theme = {int:current_theme} |
||
| 475 | AND id_member != {int:no_member} |
||
| 476 | AND variable = SUBSTRING({string:option}, 1, 255)', |
||
| 477 | array( |
||
| 478 | 'current_theme' => $_GET['th'], |
||
| 479 | 'no_member' => 0, |
||
| 480 | 'option' => $opt, |
||
| 481 | ) |
||
| 482 | ); |
||
| 483 | $smcFunc['db_query']('substring', ' |
||
| 484 | INSERT INTO {db_prefix}themes |
||
| 485 | (id_member, id_theme, variable, value) |
||
| 486 | SELECT id_member, {int:current_theme}, SUBSTRING({string:option}, 1, 255), SUBSTRING({string:value}, 1, 65534) |
||
| 487 | FROM {db_prefix}members', |
||
| 488 | array( |
||
| 489 | 'current_theme' => $_GET['th'], |
||
| 490 | 'option' => $opt, |
||
| 491 | 'value' => (is_array($val) ? implode(',', $val) : $val), |
||
| 492 | ) |
||
| 493 | ); |
||
| 494 | } |
||
| 495 | elseif ($_POST['options_master'][$opt] == 2) |
||
| 496 | { |
||
| 497 | $smcFunc['db_query']('', ' |
||
| 498 | DELETE FROM {db_prefix}themes |
||
| 499 | WHERE variable = {string:option} |
||
| 500 | AND id_member > {int:no_member} |
||
| 501 | AND id_theme = {int:current_theme}', |
||
| 502 | array( |
||
| 503 | 'no_member' => 0, |
||
| 504 | 'current_theme' => $_GET['th'], |
||
| 505 | 'option' => $opt, |
||
| 506 | ) |
||
| 507 | ); |
||
| 508 | } |
||
| 509 | } |
||
| 510 | |||
| 511 | redirectexit('action=admin;area=theme;' . $context['session_var'] . '=' . $context['session_id'] . ';sa=reset'); |
||
| 512 | } |
||
| 513 | elseif (!empty($_GET['who']) && $_GET['who'] == 2) |
||
| 514 | { |
||
| 515 | checkSession('get'); |
||
| 516 | validateToken('admin-stor', 'request'); |
||
| 517 | |||
| 518 | // Don't delete custom fields!! |
||
| 519 | if ($_GET['th'] == 1) |
||
| 520 | { |
||
| 521 | $request = $smcFunc['db_query']('', ' |
||
| 522 | SELECT col_name |
||
| 523 | FROM {db_prefix}custom_fields', |
||
| 524 | array( |
||
| 525 | ) |
||
| 526 | ); |
||
| 527 | $customFields = array(); |
||
| 528 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 529 | $customFields[] = $row['col_name']; |
||
| 530 | $smcFunc['db_free_result']($request); |
||
| 531 | } |
||
| 532 | $customFieldsQuery = empty($customFields) ? '' : ('AND variable NOT IN ({array_string:custom_fields})'); |
||
| 533 | |||
| 534 | $smcFunc['db_query']('', ' |
||
| 535 | DELETE FROM {db_prefix}themes |
||
| 536 | WHERE id_member > {int:no_member} |
||
| 537 | AND id_theme = {int:current_theme} |
||
| 538 | ' . $customFieldsQuery, |
||
| 539 | array( |
||
| 540 | 'no_member' => 0, |
||
| 541 | 'current_theme' => $_GET['th'], |
||
| 542 | 'custom_fields' => empty($customFields) ? array() : $customFields, |
||
| 543 | ) |
||
| 544 | ); |
||
| 545 | |||
| 546 | redirectexit('action=admin;area=theme;' . $context['session_var'] . '=' . $context['session_id'] . ';sa=reset'); |
||
| 547 | } |
||
| 548 | |||
| 549 | $old_id = $settings['theme_id']; |
||
| 550 | $old_settings = $settings; |
||
| 551 | |||
| 552 | loadTheme($_GET['th'], false); |
||
| 553 | |||
| 554 | loadLanguage('Profile'); |
||
| 555 | // @todo Should we just move these options so they are no longer theme dependant? |
||
| 556 | loadLanguage('PersonalMessage'); |
||
| 557 | |||
| 558 | // Let the theme take care of the settings. |
||
| 559 | loadTemplate('Settings'); |
||
| 560 | loadSubTemplate('options'); |
||
| 561 | |||
| 562 | // Let mods hook into the theme options. |
||
| 563 | call_integration_hook('integrate_theme_options'); |
||
| 564 | |||
| 565 | $context['sub_template'] = 'set_options'; |
||
| 566 | $context['page_title'] = $txt['theme_settings']; |
||
| 567 | |||
| 568 | $context['options'] = $context['theme_options']; |
||
| 569 | $context['theme_settings'] = $settings; |
||
| 570 | |||
| 571 | if (empty($_REQUEST['who'])) |
||
| 572 | { |
||
| 573 | $request = $smcFunc['db_query']('', ' |
||
| 574 | SELECT variable, value |
||
| 575 | FROM {db_prefix}themes |
||
| 576 | WHERE id_theme IN (1, {int:current_theme}) |
||
| 577 | AND id_member = {int:guest_member}', |
||
| 578 | array( |
||
| 579 | 'current_theme' => $_GET['th'], |
||
| 580 | 'guest_member' => -1, |
||
| 581 | ) |
||
| 582 | ); |
||
| 583 | $context['theme_options'] = array(); |
||
| 584 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 585 | $context['theme_options'][$row['variable']] = $row['value']; |
||
| 586 | $smcFunc['db_free_result']($request); |
||
| 587 | |||
| 588 | $context['theme_options_reset'] = false; |
||
| 589 | } |
||
| 590 | else |
||
| 591 | { |
||
| 592 | $context['theme_options'] = array(); |
||
| 593 | $context['theme_options_reset'] = true; |
||
| 594 | } |
||
| 595 | |||
| 596 | foreach ($context['options'] as $i => $setting) |
||
| 597 | { |
||
| 598 | // Just skip separators |
||
| 599 | if (!is_array($setting)) |
||
| 600 | continue; |
||
| 601 | |||
| 602 | // Is this disabled? |
||
| 603 | if (isset($setting['enabled']) && $setting['enabled'] === false) |
||
| 604 | { |
||
| 605 | unset($context['options'][$i]); |
||
| 606 | continue; |
||
| 607 | } |
||
| 608 | |||
| 609 | if (!isset($setting['type']) || $setting['type'] == 'bool') |
||
| 610 | $context['options'][$i]['type'] = 'checkbox'; |
||
| 611 | elseif ($setting['type'] == 'int' || $setting['type'] == 'integer') |
||
| 612 | $context['options'][$i]['type'] = 'number'; |
||
| 613 | elseif ($setting['type'] == 'string') |
||
| 614 | $context['options'][$i]['type'] = 'text'; |
||
| 615 | |||
| 616 | if (isset($setting['options'])) |
||
| 617 | $context['options'][$i]['type'] = 'list'; |
||
| 618 | |||
| 619 | $context['options'][$i]['value'] = !isset($context['theme_options'][$setting['id']]) ? '' : $context['theme_options'][$setting['id']]; |
||
| 620 | } |
||
| 621 | |||
| 622 | // Restore the existing theme. |
||
| 623 | loadTheme($old_id, false); |
||
| 624 | $settings = $old_settings; |
||
| 625 | |||
| 626 | loadTemplate('Themes'); |
||
| 627 | createToken('admin-sto'); |
||
| 628 | } |
||
| 629 | |||
| 630 | /** |
||
| 631 | * Administrative global settings. |
||
| 632 | * - saves and requests global theme settings. ($settings) |
||
| 633 | * - loads the Admin language file. |
||
| 634 | * - calls ThemeAdmin() if no theme is specified. (the theme center.) |
||
| 635 | * - requires admin_forum permission. |
||
| 636 | * - accessed with ?action=admin;area=theme;sa=list&th=xx. |
||
| 637 | */ |
||
| 638 | function SetThemeSettings() |
||
| 639 | { |
||
| 640 | global $txt, $context, $settings, $modSettings, $smcFunc; |
||
| 641 | |||
| 642 | if (empty($_GET['th']) && empty($_GET['id'])) |
||
| 643 | return ThemeAdmin(); |
||
| 644 | |||
| 645 | $_GET['th'] = isset($_GET['th']) ? (int) $_GET['th'] : (int) $_GET['id']; |
||
| 646 | |||
| 647 | // Select the best fitting tab. |
||
| 648 | $context[$context['admin_menu_name']]['current_subsection'] = 'list'; |
||
| 649 | |||
| 650 | loadLanguage('Admin'); |
||
| 651 | isAllowedTo('admin_forum'); |
||
| 652 | |||
| 653 | // Validate inputs/user. |
||
| 654 | if (empty($_GET['th'])) |
||
| 655 | fatal_lang_error('no_theme', false); |
||
| 656 | |||
| 657 | // Fetch the smiley sets... |
||
| 658 | $sets = explode(',', 'none,' . $modSettings['smiley_sets_known']); |
||
| 659 | $set_names = explode("\n", $txt['smileys_none'] . "\n" . $modSettings['smiley_sets_names']); |
||
| 660 | $context['smiley_sets'] = array( |
||
| 661 | '' => $txt['smileys_no_default'] |
||
| 662 | ); |
||
| 663 | foreach ($sets as $i => $set) |
||
| 664 | $context['smiley_sets'][$set] = $smcFunc['htmlspecialchars']($set_names[$i]); |
||
| 665 | |||
| 666 | $old_id = $settings['theme_id']; |
||
| 667 | $old_settings = $settings; |
||
| 668 | |||
| 669 | loadTheme($_GET['th'], false); |
||
| 670 | |||
| 671 | // Sadly we really do need to init the template. |
||
| 672 | loadSubTemplate('init', 'ignore'); |
||
| 673 | |||
| 674 | // Also load the actual themes language file - in case of special settings. |
||
| 675 | loadLanguage('Settings', '', true, true); |
||
| 676 | |||
| 677 | // And the custom language strings... |
||
| 678 | loadLanguage('ThemeStrings', '', false, true); |
||
| 679 | |||
| 680 | // Let the theme take care of the settings. |
||
| 681 | loadTemplate('Settings'); |
||
| 682 | loadSubTemplate('settings'); |
||
| 683 | |||
| 684 | // Load the variants separately... |
||
| 685 | $settings['theme_variants'] = array(); |
||
| 686 | if (file_exists($settings['theme_dir'] . '/index.template.php')) |
||
| 687 | { |
||
| 688 | $file_contents = implode('', file($settings['theme_dir'] . '/index.template.php')); |
||
| 689 | if (preg_match('~\$settings\[\'theme_variants\'\]\s*=(.+?);~', $file_contents, $matches)) |
||
| 690 | eval('global $settings;' . $matches[0]); |
||
| 691 | } |
||
| 692 | |||
| 693 | // Let mods hook into the theme settings. |
||
| 694 | call_integration_hook('integrate_theme_settings'); |
||
| 695 | |||
| 696 | // Submitting! |
||
| 697 | if (isset($_POST['save'])) |
||
| 698 | { |
||
| 699 | checkSession(); |
||
| 700 | validateToken('admin-sts'); |
||
| 701 | |||
| 702 | if (empty($_POST['options'])) |
||
| 703 | $_POST['options'] = array(); |
||
| 704 | if (empty($_POST['default_options'])) |
||
| 705 | $_POST['default_options'] = array(); |
||
| 706 | |||
| 707 | // Make sure items are cast correctly. |
||
| 708 | foreach ($context['theme_settings'] as $item) |
||
| 709 | { |
||
| 710 | // Disregard this item if this is just a separator. |
||
| 711 | if (!is_array($item)) |
||
| 712 | continue; |
||
| 713 | |||
| 714 | foreach (array('options', 'default_options') as $option) |
||
| 715 | { |
||
| 716 | if (!isset($_POST[$option][$item['id']])) |
||
| 717 | continue; |
||
| 718 | // Checkbox. |
||
| 719 | elseif (empty($item['type'])) |
||
| 720 | $_POST[$option][$item['id']] = $_POST[$option][$item['id']] ? 1 : 0; |
||
| 721 | // Number |
||
| 722 | elseif ($item['type'] == 'number') |
||
| 723 | $_POST[$option][$item['id']] = (int) $_POST[$option][$item['id']]; |
||
| 724 | } |
||
| 725 | } |
||
| 726 | |||
| 727 | // Set up the sql query. |
||
| 728 | $inserts = array(); |
||
| 729 | foreach ($_POST['options'] as $opt => $val) |
||
| 730 | $inserts[] = array(0, $_GET['th'], $opt, is_array($val) ? implode(',', $val) : $val); |
||
| 731 | foreach ($_POST['default_options'] as $opt => $val) |
||
| 732 | $inserts[] = array(0, 1, $opt, is_array($val) ? implode(',', $val) : $val); |
||
| 733 | // If we're actually inserting something.. |
||
| 734 | if (!empty($inserts)) |
||
| 735 | { |
||
| 736 | $smcFunc['db_insert']('replace', |
||
| 737 | '{db_prefix}themes', |
||
| 738 | array('id_member' => 'int', 'id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), |
||
| 739 | $inserts, |
||
| 740 | array('id_member', 'id_theme', 'variable') |
||
| 741 | ); |
||
| 742 | } |
||
| 743 | |||
| 744 | cache_put_data('theme_settings-' . $_GET['th'], null, 90); |
||
| 745 | cache_put_data('theme_settings-1', null, 90); |
||
| 746 | |||
| 747 | // Invalidate the cache. |
||
| 748 | updateSettings(array('settings_updated' => time())); |
||
| 749 | |||
| 750 | redirectexit('action=admin;area=theme;sa=list;th=' . $_GET['th'] . ';' . $context['session_var'] . '=' . $context['session_id']); |
||
| 751 | } |
||
| 752 | |||
| 753 | $context['sub_template'] = 'set_settings'; |
||
| 754 | $context['page_title'] = $txt['theme_settings']; |
||
| 755 | |||
| 756 | foreach ($settings as $setting => $dummy) |
||
| 757 | { |
||
| 758 | if (!in_array($setting, array('theme_url', 'theme_dir', 'images_url', 'template_dirs'))) |
||
| 759 | $settings[$setting] = htmlspecialchars__recursive($settings[$setting]); |
||
| 760 | } |
||
| 761 | |||
| 762 | $context['settings'] = $context['theme_settings']; |
||
| 763 | $context['theme_settings'] = $settings; |
||
| 764 | |||
| 765 | foreach ($context['settings'] as $i => $setting) |
||
| 766 | { |
||
| 767 | // Separators are dummies, so leave them alone. |
||
| 768 | if (!is_array($setting)) |
||
| 769 | continue; |
||
| 770 | |||
| 771 | if (!isset($setting['type']) || $setting['type'] == 'bool') |
||
| 772 | $context['settings'][$i]['type'] = 'checkbox'; |
||
| 773 | elseif ($setting['type'] == 'int' || $setting['type'] == 'integer') |
||
| 774 | $context['settings'][$i]['type'] = 'number'; |
||
| 775 | elseif ($setting['type'] == 'string') |
||
| 776 | $context['settings'][$i]['type'] = 'text'; |
||
| 777 | |||
| 778 | if (isset($setting['options'])) |
||
| 779 | $context['settings'][$i]['type'] = 'list'; |
||
| 780 | |||
| 781 | $context['settings'][$i]['value'] = !isset($settings[$setting['id']]) ? '' : $settings[$setting['id']]; |
||
| 782 | } |
||
| 783 | |||
| 784 | // Do we support variants? |
||
| 785 | if (!empty($settings['theme_variants'])) |
||
| 786 | { |
||
| 787 | $context['theme_variants'] = array(); |
||
| 788 | foreach ($settings['theme_variants'] as $variant) |
||
| 789 | { |
||
| 790 | // Have any text, old chap? |
||
| 791 | $context['theme_variants'][$variant] = array( |
||
| 792 | 'label' => isset($txt['variant_' . $variant]) ? $txt['variant_' . $variant] : $variant, |
||
| 793 | 'thumbnail' => !file_exists($settings['theme_dir'] . '/images/thumbnail.png') || file_exists($settings['theme_dir'] . '/images/thumbnail_' . $variant . '.png') ? $settings['images_url'] . '/thumbnail_' . $variant . '.png' : ($settings['images_url'] . '/thumbnail.png'), |
||
| 794 | ); |
||
| 795 | } |
||
| 796 | $context['default_variant'] = !empty($settings['default_variant']) && isset($context['theme_variants'][$settings['default_variant']]) ? $settings['default_variant'] : $settings['theme_variants'][0]; |
||
| 797 | } |
||
| 798 | |||
| 799 | // Restore the current theme. |
||
| 800 | loadTheme($old_id, false); |
||
| 801 | |||
| 802 | // Reinit just incase. |
||
| 803 | loadSubTemplate('init', 'ignore'); |
||
| 804 | |||
| 805 | $settings = $old_settings; |
||
| 806 | |||
| 807 | loadTemplate('Themes'); |
||
| 808 | |||
| 809 | // We like Kenny better than Token. |
||
| 810 | createToken('admin-sts'); |
||
| 811 | } |
||
| 812 | |||
| 813 | /** |
||
| 814 | * Remove a theme from the database. |
||
| 815 | * - removes an installed theme. |
||
| 816 | * - requires an administrator. |
||
| 817 | * - accessed with ?action=admin;area=theme;sa=remove. |
||
| 818 | */ |
||
| 819 | function RemoveTheme() |
||
| 820 | { |
||
| 821 | global $context; |
||
| 822 | |||
| 823 | checkSession('get'); |
||
| 824 | |||
| 825 | isAllowedTo('admin_forum'); |
||
| 826 | validateToken('admin-tr', 'request'); |
||
| 827 | |||
| 828 | // The theme's ID must be an integer. |
||
| 829 | $themeID = isset($_GET['th']) ? (int) $_GET['th'] : (int) $_GET['id']; |
||
| 830 | |||
| 831 | // You can't delete the default theme! |
||
| 832 | if ($themeID == 1) |
||
| 833 | fatal_lang_error('no_access', false); |
||
| 834 | |||
| 835 | $theme_info = get_single_theme($themeID); |
||
| 836 | |||
| 837 | // Remove it from the DB. |
||
| 838 | remove_theme($themeID); |
||
| 839 | |||
| 840 | // And remove all its files and folders too. |
||
| 841 | if (!empty($theme_info) && !empty($theme_info['theme_dir'])) |
||
| 842 | remove_dir($theme_info['theme_dir']); |
||
| 843 | |||
| 844 | // Go back to the list page. |
||
| 845 | redirectexit('action=admin;area=theme;sa=list;' . $context['session_var'] . '=' . $context['session_id'] . ';done=removing'); |
||
| 846 | } |
||
| 847 | |||
| 848 | /** |
||
| 849 | * Handles enabling/disabling a theme from the admin center |
||
| 850 | */ |
||
| 851 | function EnableTheme() |
||
| 852 | { |
||
| 853 | global $modSettings, $context; |
||
| 854 | |||
| 855 | checkSession('get'); |
||
| 856 | |||
| 857 | isAllowedTo('admin_forum'); |
||
| 858 | validateToken('admin-tre', 'request'); |
||
| 859 | |||
| 860 | // The theme's ID must be an string. |
||
| 861 | $themeID = isset($_GET['th']) ? (string) trim($_GET['th']) : (string) trim($_GET['id']); |
||
| 862 | |||
| 863 | // Get the current list. |
||
| 864 | $enableThemes = explode(',', $modSettings['enableThemes']); |
||
| 865 | |||
| 866 | // Are we disabling it? |
||
| 867 | if (isset($_GET['disabled'])) |
||
| 868 | $enableThemes = array_diff($enableThemes, array($themeID)); |
||
| 869 | |||
| 870 | // Nope? then enable it! |
||
| 871 | else |
||
| 872 | $enableThemes[] = (string) $themeID; |
||
| 873 | |||
| 874 | // Update the setting. |
||
| 875 | $enableThemes = strtr(implode(',', $enableThemes), array(',,' => ',')); |
||
| 876 | updateSettings(array('enableThemes' => $enableThemes)); |
||
| 877 | |||
| 878 | // Done! |
||
| 879 | redirectexit('action=admin;area=theme;sa=list;' . $context['session_var'] . '=' . $context['session_id'] . ';done=' . (isset($_GET['disabled']) ? 'disabling' : 'enabling')); |
||
| 880 | } |
||
| 881 | |||
| 882 | /** |
||
| 883 | * Determines if a user can change their theme. |
||
| 884 | * |
||
| 885 | * @param int $id_member |
||
| 886 | * @param int $id_theme |
||
| 887 | * |
||
| 888 | * @return bool |
||
| 889 | */ |
||
| 890 | function canPickTheme($id_member, $id_theme) |
||
| 891 | { |
||
| 892 | global $modSettings, $user_info; |
||
| 893 | |||
| 894 | return |
||
| 895 | allowedTo($user_info['id'] == $id_member ? 'profile_extra_own' : 'profile_extra_any') |
||
| 896 | && ($id_theme == 0 || (allowedTo('admin_forum') || in_array($id_theme, explode(',', $modSettings['knownThemes']))) && in_array($id_theme, explode(',', $modSettings['enableThemes']))) |
||
| 897 | && (!empty($modSettings['theme_allow']) || allowedTo('admin_forum')); |
||
| 898 | } |
||
| 899 | |||
| 900 | /** |
||
| 901 | * Choose a theme from a list. |
||
| 902 | * allows a user to pick a new theme with an interface. |
||
| 903 | * - uses the Themes template. (pick sub template.) |
||
| 904 | * - accessed with ?action=theme;sa=pick. |
||
| 905 | */ |
||
| 906 | function PickTheme() |
||
| 907 | { |
||
| 908 | global $txt, $context, $modSettings, $user_info, $language, $smcFunc, $settings, $scripturl; |
||
| 909 | |||
| 910 | loadLanguage('Profile'); |
||
| 911 | loadTemplate('Themes'); |
||
| 912 | |||
| 913 | // Build the link tree. |
||
| 914 | $context['linktree'][] = array( |
||
| 915 | 'url' => $scripturl . '?action=theme;sa=pick;u=' . (!empty($_REQUEST['u']) ? (int) $_REQUEST['u'] : 0), |
||
| 916 | 'name' => $txt['theme_pick'], |
||
| 917 | ); |
||
| 918 | $context['default_theme_id'] = $modSettings['theme_default']; |
||
| 919 | $_SESSION['id_theme'] = 0; |
||
| 920 | if (!isset($_REQUEST['u'])) |
||
| 921 | $_REQUEST['u'] = $user_info['id']; |
||
| 922 | |||
| 923 | // Have we made a decision, or are we just browsing? |
||
| 924 | if (isset($_POST['save'])) |
||
| 925 | { |
||
| 926 | checkSession(); |
||
| 927 | validateToken('pick-th'); |
||
| 928 | |||
| 929 | $id_theme = (int) key($_POST['save']); |
||
| 930 | if (isset($_POST['vrt'][$id_theme])) |
||
| 931 | $variant = $_POST['vrt'][$id_theme]; |
||
| 932 | |||
| 933 | if (canPickTheme((int) $_REQUEST['u'], $id_theme)) |
||
| 934 | { |
||
| 935 | // An identifier of zero means that the user wants the forum default theme. |
||
| 936 | updateMemberData((int) $_REQUEST['u'], array('id_theme' => $id_theme)); |
||
| 937 | |||
| 938 | if (!empty($variant)) |
||
| 939 | { |
||
| 940 | // Set the identifier to the forum default. |
||
| 941 | if (isset($id_theme) && $id_theme == 0) |
||
| 942 | $id_theme = $modSettings['theme_guests']; |
||
| 943 | |||
| 944 | $smcFunc['db_insert']('replace', |
||
| 945 | '{db_prefix}themes', |
||
| 946 | array('id_theme' => 'int', 'id_member' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), |
||
| 947 | array($id_theme, (int) $_REQUEST['u'], 'theme_variant', $variant), |
||
| 948 | array('id_theme', 'id_member', 'variable') |
||
| 949 | ); |
||
| 950 | cache_put_data('theme_settings-' . $id_theme . ':' . (int) $_REQUEST['u'], null, 90); |
||
| 951 | |||
| 952 | if ($user_info['id'] == $_REQUEST['u']) |
||
| 953 | $_SESSION['id_variant'] = 0; |
||
| 954 | } |
||
| 955 | |||
| 956 | redirectexit('action=profile;u=' . (int) $_REQUEST['u'] . ';area=theme'); |
||
| 957 | } |
||
| 958 | } |
||
| 959 | |||
| 960 | // Figure out who the member of the minute is, and what theme they've chosen. |
||
| 961 | if (!isset($_REQUEST['u']) || !allowedTo('admin_forum')) |
||
| 962 | { |
||
| 963 | $context['current_member'] = $user_info['id']; |
||
| 964 | $context['current_theme'] = $user_info['theme']; |
||
| 965 | } |
||
| 966 | else |
||
| 967 | { |
||
| 968 | $context['current_member'] = (int) $_REQUEST['u']; |
||
| 969 | |||
| 970 | $request = $smcFunc['db_query']('', ' |
||
| 971 | SELECT id_theme |
||
| 972 | FROM {db_prefix}members |
||
| 973 | WHERE id_member = {int:current_member} |
||
| 974 | LIMIT 1', |
||
| 975 | array( |
||
| 976 | 'current_member' => $context['current_member'], |
||
| 977 | ) |
||
| 978 | ); |
||
| 979 | list ($context['current_theme']) = $smcFunc['db_fetch_row']($request); |
||
| 980 | $smcFunc['db_free_result']($request); |
||
| 981 | } |
||
| 982 | |||
| 983 | // Get the theme name and descriptions. |
||
| 984 | $context['available_themes'] = array(); |
||
| 985 | if (!empty($modSettings['knownThemes'])) |
||
| 986 | { |
||
| 987 | $request = $smcFunc['db_query']('', ' |
||
| 988 | SELECT id_theme, variable, value |
||
| 989 | FROM {db_prefix}themes |
||
| 990 | WHERE variable IN ({literal:name}, {literal:theme_url}, {literal:theme_dir}, {literal:images_url}, {literal:disable_user_variant})' . (!allowedTo('admin_forum') ? ' |
||
| 991 | AND id_theme IN ({array_int:known_themes})' : '') . ' |
||
| 992 | AND id_theme != {int:default_theme} |
||
| 993 | AND id_member = {int:no_member} |
||
| 994 | AND id_theme IN ({array_int:enable_themes})', |
||
| 995 | array( |
||
| 996 | 'default_theme' => 0, |
||
| 997 | 'no_member' => 0, |
||
| 998 | 'known_themes' => explode(',', $modSettings['knownThemes']), |
||
| 999 | 'enable_themes' => explode(',', $modSettings['enableThemes']), |
||
| 1000 | ) |
||
| 1001 | ); |
||
| 1002 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1003 | { |
||
| 1004 | if (!isset($context['available_themes'][$row['id_theme']])) |
||
| 1005 | $context['available_themes'][$row['id_theme']] = array( |
||
| 1006 | 'id' => $row['id_theme'], |
||
| 1007 | 'selected' => $context['current_theme'] == $row['id_theme'], |
||
| 1008 | 'num_users' => 0 |
||
| 1009 | ); |
||
| 1010 | $context['available_themes'][$row['id_theme']][$row['variable']] = $row['value']; |
||
| 1011 | } |
||
| 1012 | $smcFunc['db_free_result']($request); |
||
| 1013 | } |
||
| 1014 | |||
| 1015 | // Okay, this is a complicated problem: the default theme is 1, but they aren't allowed to access 1! |
||
| 1016 | if (!isset($context['available_themes'][$modSettings['theme_guests']])) |
||
| 1017 | { |
||
| 1018 | $context['available_themes'][0] = array( |
||
| 1019 | 'num_users' => 0 |
||
| 1020 | ); |
||
| 1021 | $guest_theme = 0; |
||
| 1022 | } |
||
| 1023 | else |
||
| 1024 | $guest_theme = $modSettings['theme_guests']; |
||
| 1025 | |||
| 1026 | $request = $smcFunc['db_query']('', ' |
||
| 1027 | SELECT id_theme, COUNT(*) AS the_count |
||
| 1028 | FROM {db_prefix}members |
||
| 1029 | GROUP BY id_theme |
||
| 1030 | ORDER BY id_theme DESC', |
||
| 1031 | array( |
||
| 1032 | ) |
||
| 1033 | ); |
||
| 1034 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1035 | { |
||
| 1036 | // Figure out which theme it is they are REALLY using. |
||
| 1037 | if (!empty($modSettings['knownThemes']) && !in_array($row['id_theme'], explode(',', $modSettings['knownThemes']))) |
||
| 1038 | $row['id_theme'] = $guest_theme; |
||
| 1039 | elseif (empty($modSettings['theme_allow'])) |
||
| 1040 | $row['id_theme'] = $guest_theme; |
||
| 1041 | |||
| 1042 | if (isset($context['available_themes'][$row['id_theme']])) |
||
| 1043 | $context['available_themes'][$row['id_theme']]['num_users'] += $row['the_count']; |
||
| 1044 | else |
||
| 1045 | $context['available_themes'][$guest_theme]['num_users'] += $row['the_count']; |
||
| 1046 | } |
||
| 1047 | $smcFunc['db_free_result']($request); |
||
| 1048 | |||
| 1049 | // Get any member variant preferences. |
||
| 1050 | $variant_preferences = array(); |
||
| 1051 | if ($context['current_member'] > 0) |
||
| 1052 | { |
||
| 1053 | $request = $smcFunc['db_query']('', ' |
||
| 1054 | SELECT id_theme, value |
||
| 1055 | FROM {db_prefix}themes |
||
| 1056 | WHERE variable = {string:theme_variant} |
||
| 1057 | AND id_member IN ({array_int:id_member}) |
||
| 1058 | ORDER BY id_member ASC', |
||
| 1059 | array( |
||
| 1060 | 'theme_variant' => 'theme_variant', |
||
| 1061 | 'id_member' => isset($_REQUEST['sa']) && $_REQUEST['sa'] == 'pick' ? array(-1, $context['current_member']) : array(-1), |
||
| 1062 | ) |
||
| 1063 | ); |
||
| 1064 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1065 | $variant_preferences[$row['id_theme']] = $row['value']; |
||
| 1066 | $smcFunc['db_free_result']($request); |
||
| 1067 | } |
||
| 1068 | |||
| 1069 | // Save the setting first. |
||
| 1070 | $current_images_url = $settings['images_url']; |
||
| 1071 | $current_theme_variants = !empty($settings['theme_variants']) ? $settings['theme_variants'] : array(); |
||
| 1072 | |||
| 1073 | foreach ($context['available_themes'] as $id_theme => $theme_data) |
||
| 1074 | { |
||
| 1075 | // Don't try to load the forum or board default theme's data... it doesn't have any! |
||
| 1076 | if ($id_theme == 0) |
||
| 1077 | continue; |
||
| 1078 | |||
| 1079 | // The thumbnail needs the correct path. |
||
| 1080 | $settings['images_url'] = &$theme_data['images_url']; |
||
| 1081 | |||
| 1082 | if (file_exists($theme_data['theme_dir'] . '/languages/Settings.' . $user_info['language'] . '.php')) |
||
| 1083 | include($theme_data['theme_dir'] . '/languages/Settings.' . $user_info['language'] . '.php'); |
||
| 1084 | elseif (file_exists($theme_data['theme_dir'] . '/languages/Settings.' . $language . '.php')) |
||
| 1085 | include($theme_data['theme_dir'] . '/languages/Settings.' . $language . '.php'); |
||
| 1086 | else |
||
| 1087 | { |
||
| 1088 | $txt['theme_thumbnail_href'] = $theme_data['images_url'] . '/thumbnail.png'; |
||
| 1089 | $txt['theme_description'] = ''; |
||
| 1090 | } |
||
| 1091 | |||
| 1092 | $context['available_themes'][$id_theme]['thumbnail_href'] = $txt['theme_thumbnail_href']; |
||
| 1093 | $context['available_themes'][$id_theme]['description'] = $txt['theme_description']; |
||
| 1094 | |||
| 1095 | // Are there any variants? |
||
| 1096 | $context['available_themes'][$id_theme]['variants'] = array(); |
||
| 1097 | if (file_exists($theme_data['theme_dir'] . '/index.template.php') && (empty($theme_data['disable_user_variant']) || allowedTo('admin_forum'))) |
||
| 1098 | { |
||
| 1099 | $file_contents = implode('', file($theme_data['theme_dir'] . '/index.template.php')); |
||
| 1100 | if (preg_match('~\$settings\[\'theme_variants\'\]\s*=(.+?);~', $file_contents, $matches)) |
||
| 1101 | { |
||
| 1102 | $settings['theme_variants'] = array(); |
||
| 1103 | |||
| 1104 | // Fill settings up. |
||
| 1105 | eval('global $settings;' . $matches[0]); |
||
| 1106 | |||
| 1107 | if (!empty($settings['theme_variants'])) |
||
| 1108 | { |
||
| 1109 | loadLanguage('Settings'); |
||
| 1110 | |||
| 1111 | foreach ($settings['theme_variants'] as $variant) |
||
| 1112 | $context['available_themes'][$id_theme]['variants'][$variant] = array( |
||
| 1113 | 'label' => isset($txt['variant_' . $variant]) ? $txt['variant_' . $variant] : $variant, |
||
| 1114 | 'thumbnail' => !file_exists($theme_data['theme_dir'] . '/images/thumbnail.png') || file_exists($theme_data['theme_dir'] . '/images/thumbnail_' . $variant . '.png') ? $theme_data['images_url'] . '/thumbnail_' . $variant . '.png' : ($theme_data['images_url'] . '/thumbnail.png'), |
||
| 1115 | ); |
||
| 1116 | |||
| 1117 | $context['available_themes'][$id_theme]['selected_variant'] = isset($_GET['vrt']) ? $_GET['vrt'] : (!empty($variant_preferences[$id_theme]) ? $variant_preferences[$id_theme] : (!empty($settings['default_variant']) ? $settings['default_variant'] : $settings['theme_variants'][0])); |
||
| 1118 | if (!isset($context['available_themes'][$id_theme]['variants'][$context['available_themes'][$id_theme]['selected_variant']]['thumbnail'])) |
||
| 1119 | $context['available_themes'][$id_theme]['selected_variant'] = $settings['theme_variants'][0]; |
||
| 1120 | |||
| 1121 | $context['available_themes'][$id_theme]['thumbnail_href'] = $context['available_themes'][$id_theme]['variants'][$context['available_themes'][$id_theme]['selected_variant']]['thumbnail']; |
||
| 1122 | // Allow themes to override the text. |
||
| 1123 | $context['available_themes'][$id_theme]['pick_label'] = isset($txt['variant_pick']) ? $txt['variant_pick'] : $txt['theme_pick_variant']; |
||
| 1124 | } |
||
| 1125 | } |
||
| 1126 | } |
||
| 1127 | } |
||
| 1128 | // Then return it. |
||
| 1129 | addJavaScriptVar( |
||
| 1130 | 'oThemeVariants', |
||
| 1131 | json_encode(array_map(function($theme) |
||
| 1132 | { |
||
| 1133 | return $theme['variants']; |
||
| 1134 | }, $context['available_themes'] |
||
| 1135 | ))); |
||
| 1136 | loadJavaScriptFile('profile.js', array('defer' => false, 'minimize' => true), 'smf_profile'); |
||
| 1137 | $settings['images_url'] = $current_images_url; |
||
| 1138 | $settings['theme_variants'] = $current_theme_variants; |
||
| 1139 | |||
| 1140 | // As long as we're not doing the default theme... |
||
| 1141 | if (!isset($_REQUEST['u']) || $_REQUEST['u'] >= 0) |
||
| 1142 | { |
||
| 1143 | if ($guest_theme != 0) |
||
| 1144 | $context['available_themes'][0] = $context['available_themes'][$guest_theme]; |
||
| 1145 | |||
| 1146 | $context['available_themes'][0]['id'] = 0; |
||
| 1147 | $context['available_themes'][0]['name'] = $txt['theme_forum_default']; |
||
| 1148 | $context['available_themes'][0]['selected'] = $context['current_theme'] == 0; |
||
| 1149 | $context['available_themes'][0]['description'] = $txt['theme_global_description']; |
||
| 1150 | } |
||
| 1151 | |||
| 1152 | ksort($context['available_themes']); |
||
| 1153 | |||
| 1154 | $context['page_title'] = $txt['theme_pick']; |
||
| 1155 | $context['sub_template'] = 'pick'; |
||
| 1156 | createToken('pick-th'); |
||
| 1157 | } |
||
| 1158 | |||
| 1159 | /** |
||
| 1160 | * Installs new themes, calls the respective function according to the install type. |
||
| 1161 | * - puts themes in $boardurl/Themes. |
||
| 1162 | * - assumes the gzip has a root directory in it. (ie default.) |
||
| 1163 | * Requires admin_forum. |
||
| 1164 | * Accessed with ?action=admin;area=theme;sa=install. |
||
| 1165 | */ |
||
| 1166 | function ThemeInstall() |
||
| 1167 | { |
||
| 1168 | global $sourcedir, $txt, $context, $boarddir, $boardurl; |
||
| 1169 | global $themedir, $themeurl, $smcFunc; |
||
| 1170 | |||
| 1171 | checkSession('request'); |
||
| 1172 | isAllowedTo('admin_forum'); |
||
| 1173 | |||
| 1174 | require_once($sourcedir . '/Subs-Package.php'); |
||
| 1175 | |||
| 1176 | // Make it easier to change the path and url. |
||
| 1177 | $themedir = $boarddir . '/Themes'; |
||
| 1178 | $themeurl = $boardurl . '/Themes'; |
||
| 1179 | |||
| 1180 | loadTemplate('Themes'); |
||
| 1181 | |||
| 1182 | $subActions = array( |
||
| 1183 | 'file' => 'InstallFile', |
||
| 1184 | 'copy' => 'InstallCopy', |
||
| 1185 | 'dir' => 'InstallDir', |
||
| 1186 | ); |
||
| 1187 | |||
| 1188 | // Is there a function to call? |
||
| 1189 | if (isset($_GET['do']) && !empty($_GET['do']) && isset($subActions[$_GET['do']])) |
||
| 1190 | { |
||
| 1191 | $action = $smcFunc['htmlspecialchars'](trim($_GET['do'])); |
||
| 1192 | |||
| 1193 | // Got any info from the specific form? |
||
| 1194 | if (!isset($_POST['save_' . $action])) |
||
| 1195 | fatal_lang_error('theme_install_no_action', false); |
||
| 1196 | |||
| 1197 | validateToken('admin-t-' . $action); |
||
| 1198 | |||
| 1199 | // Hopefully the themes directory is writable, or we might have a problem. |
||
| 1200 | if (!is_writable($themedir)) |
||
| 1201 | fatal_lang_error('theme_install_write_error', 'critical'); |
||
| 1202 | |||
| 1203 | // Call the function and handle the result. |
||
| 1204 | $result = $subActions[$action](); |
||
| 1205 | |||
| 1206 | // Everything went better than expected! |
||
| 1207 | if (!empty($result)) |
||
| 1208 | { |
||
| 1209 | $context['sub_template'] = 'installed'; |
||
| 1210 | $context['page_title'] = $txt['theme_installed']; |
||
| 1211 | $context['installed_theme'] = $result; |
||
| 1212 | } |
||
| 1213 | } |
||
| 1214 | |||
| 1215 | // Nope, show a nice error. |
||
| 1216 | else |
||
| 1217 | fatal_lang_error('theme_install_no_action', false); |
||
| 1218 | } |
||
| 1219 | |||
| 1220 | /** |
||
| 1221 | * Installs a theme from a theme package. |
||
| 1222 | * |
||
| 1223 | * Stores the theme files on a temp dir, on success it renames the dir to the new theme's name. Ends execution with fatal_lang_error() on any error. |
||
| 1224 | * |
||
| 1225 | * @return array The newly created theme's info. |
||
| 1226 | */ |
||
| 1227 | function InstallFile() |
||
| 1228 | { |
||
| 1229 | global $themedir, $themeurl, $context; |
||
| 1230 | |||
| 1231 | // Set a temp dir for dumping all required files on it. |
||
| 1232 | $dirtemp = $themedir . '/temp'; |
||
| 1233 | |||
| 1234 | // Make sure the temp dir doesn't already exist |
||
| 1235 | if (file_exists($dirtemp)) |
||
| 1236 | remove_dir($dirtemp); |
||
| 1237 | |||
| 1238 | // Create the temp dir. |
||
| 1239 | mkdir($dirtemp, 0777); |
||
| 1240 | |||
| 1241 | // Hopefully the temp directory is writable, or we might have a problem. |
||
| 1242 | if (!is_writable($dirtemp)) |
||
| 1243 | { |
||
| 1244 | // Lets give it a try. |
||
| 1245 | smf_chmod($dirtemp, '0755'); |
||
| 1246 | |||
| 1247 | // How about now? |
||
| 1248 | if (!is_writable($dirtemp)) |
||
| 1249 | fatal_lang_error('theme_install_write_error', 'critical'); |
||
| 1250 | } |
||
| 1251 | |||
| 1252 | // This happens when the admin session is gone and the user has to login again. |
||
| 1253 | if (!isset($_FILES) || !isset($_FILES['theme_gz']) || empty($_FILES['theme_gz'])) |
||
| 1254 | redirectexit('action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id']); |
||
| 1255 | |||
| 1256 | // Another error check layer, something went wrong with the upload. |
||
| 1257 | if (isset($_FILES['theme_gz']['error']) && $_FILES['theme_gz']['error'] != 0) |
||
| 1258 | fatal_lang_error('theme_install_error_file_' . $_FILES['theme_gz']['error'], false); |
||
| 1259 | |||
| 1260 | // Get the theme's name. |
||
| 1261 | $name = pathinfo($_FILES['theme_gz']['name'], PATHINFO_FILENAME); |
||
| 1262 | $name = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/', '/\.tar$/'), array('_', '.', '', ''), $name); |
||
| 1263 | |||
| 1264 | // Start setting some vars. |
||
| 1265 | $context['to_install'] = array( |
||
| 1266 | 'theme_dir' => $themedir . '/' . $name, |
||
| 1267 | 'theme_url' => $themeurl . '/' . $name, |
||
| 1268 | 'images_url' => $themeurl . '/' . $name . '/images', |
||
| 1269 | 'name' => $name, |
||
| 1270 | ); |
||
| 1271 | |||
| 1272 | // Extract the file on the proper themes dir. |
||
| 1273 | $extracted = read_tgz_file($_FILES['theme_gz']['tmp_name'], $dirtemp, false, true); |
||
| 1274 | |||
| 1275 | if ($extracted) |
||
| 1276 | { |
||
| 1277 | // Read its info form the XML file. |
||
| 1278 | $theme_info = get_theme_info($dirtemp); |
||
| 1279 | $context['to_install'] += $theme_info; |
||
| 1280 | |||
| 1281 | // Install the theme. theme_install() will return the new installed ID. |
||
| 1282 | $context['to_install']['id'] = theme_install($context['to_install']); |
||
| 1283 | |||
| 1284 | // Rename the temp dir to the actual theme name. |
||
| 1285 | rename($dirtemp, $context['to_install']['theme_dir']); |
||
| 1286 | |||
| 1287 | // return all the info. |
||
| 1288 | return $context['to_install']; |
||
| 1289 | } |
||
| 1290 | |||
| 1291 | else |
||
| 1292 | fatal_lang_error('theme_install_error_title', false); |
||
| 1293 | } |
||
| 1294 | |||
| 1295 | /** |
||
| 1296 | * Makes a copy from the default theme, assigns a name for it and installs it. |
||
| 1297 | * |
||
| 1298 | * Creates a new .xml file containing all the theme's info. |
||
| 1299 | * |
||
| 1300 | * @return array The newly created theme's info. |
||
| 1301 | */ |
||
| 1302 | function InstallCopy() |
||
| 1303 | { |
||
| 1304 | global $themedir, $themeurl, $settings, $smcFunc, $context; |
||
| 1305 | |||
| 1306 | // There's gotta be something to work with. |
||
| 1307 | if (!isset($_REQUEST['copy']) || empty($_REQUEST['copy'])) |
||
| 1308 | fatal_lang_error('theme_install_error_title', false); |
||
| 1309 | |||
| 1310 | // Get a cleaner version. |
||
| 1311 | $name = preg_replace('~[^A-Za-z0-9_\- ]~', '', $_REQUEST['copy']); |
||
| 1312 | |||
| 1313 | // Is there a theme already named like this? |
||
| 1314 | if (file_exists($themedir . '/' . $name)) |
||
| 1315 | fatal_lang_error('theme_install_already_dir', false); |
||
| 1316 | |||
| 1317 | // This is a brand new theme so set all possible values. |
||
| 1318 | $context['to_install'] = array( |
||
| 1319 | 'theme_dir' => $themedir . '/' . $name, |
||
| 1320 | 'theme_url' => $themeurl . '/' . $name, |
||
| 1321 | 'name' => $name, |
||
| 1322 | 'images_url' => $themeurl . '/' . $name . '/images', |
||
| 1323 | 'version' => '1.0', |
||
| 1324 | 'install_for' => '2.1 - 2.1.99, ' . SMF_VERSION, |
||
| 1325 | 'based_on' => '', |
||
| 1326 | 'based_on_dir' => $themedir . '/default', |
||
| 1327 | ); |
||
| 1328 | |||
| 1329 | // Create the specific dir. |
||
| 1330 | umask(0); |
||
| 1331 | mkdir($context['to_install']['theme_dir'], 0777); |
||
| 1332 | |||
| 1333 | // Buy some time. |
||
| 1334 | @set_time_limit(600); |
||
| 1335 | if (function_exists('apache_reset_timeout')) |
||
| 1336 | @apache_reset_timeout(); |
||
| 1337 | |||
| 1338 | // Create subdirectories for css and javascript files. |
||
| 1339 | mkdir($context['to_install']['theme_dir'] . '/css', 0777); |
||
| 1340 | mkdir($context['to_install']['theme_dir'] . '/scripts', 0777); |
||
| 1341 | |||
| 1342 | // Copy over the default non-theme files. |
||
| 1343 | $to_copy = array('/index.php', '/index.template.php', '/css/index.css', '/css/responsive.css', '/css/slider.min.css', '/css/rtl.css', '/css/calendar.css', '/css/calendar.rtl.css', '/css/admin.css', '/scripts/theme.js'); |
||
| 1344 | |||
| 1345 | foreach ($to_copy as $file) |
||
| 1346 | { |
||
| 1347 | copy($settings['default_theme_dir'] . $file, $context['to_install']['theme_dir'] . $file); |
||
| 1348 | smf_chmod($context['to_install']['theme_dir'] . $file, 0777); |
||
| 1349 | } |
||
| 1350 | |||
| 1351 | // And now the entire images directory! |
||
| 1352 | copytree($settings['default_theme_dir'] . '/images', $context['to_install']['theme_dir'] . '/images'); |
||
| 1353 | package_flush_cache(); |
||
| 1354 | |||
| 1355 | // Lets get some data for the new theme. |
||
| 1356 | $request = $smcFunc['db_query']('', ' |
||
| 1357 | SELECT variable, value |
||
| 1358 | FROM {db_prefix}themes |
||
| 1359 | WHERE variable IN ({string:theme_templates}, {string:theme_layers}) |
||
| 1360 | AND id_member = {int:no_member} |
||
| 1361 | AND id_theme = {int:default_theme}', |
||
| 1362 | array( |
||
| 1363 | 'no_member' => 0, |
||
| 1364 | 'default_theme' => 1, |
||
| 1365 | 'theme_templates' => 'theme_templates', |
||
| 1366 | 'theme_layers' => 'theme_layers', |
||
| 1367 | ) |
||
| 1368 | ); |
||
| 1369 | |||
| 1370 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1371 | { |
||
| 1372 | if ($row['variable'] == 'theme_templates') |
||
| 1373 | $theme_templates = $row['value']; |
||
| 1374 | elseif ($row['variable'] == 'theme_layers') |
||
| 1375 | $theme_layers = $row['value']; |
||
| 1376 | else |
||
| 1377 | continue; |
||
| 1378 | } |
||
| 1379 | |||
| 1380 | $smcFunc['db_free_result']($request); |
||
| 1381 | |||
| 1382 | $context['to_install'] += array( |
||
| 1383 | 'theme_layers' => empty($theme_layers) ? 'html,body' : $theme_layers, |
||
| 1384 | 'theme_templates' => empty($theme_templates) ? 'index' : $theme_templates, |
||
| 1385 | ); |
||
| 1386 | |||
| 1387 | // Lets add a theme_info.xml to this theme. |
||
| 1388 | $xml_info = '<' . '?xml version="1.0"?' . '> |
||
| 1389 | <theme-info xmlns="http://www.simplemachines.org/xml/theme-info" xmlns:smf="http://www.simplemachines.org/"> |
||
| 1390 | <!-- For the id, always use something unique - put your name, a colon, and then the package name. --> |
||
| 1391 | <id>smf:' . $smcFunc['strtolower']($context['to_install']['name']) . '</id> |
||
| 1392 | <!-- The theme\'s version, please try to use semantic versioning. --> |
||
| 1393 | <version>1.0</version> |
||
| 1394 | <!-- Install for, the SMF versions this theme was designed for. Uses the same wildcards used in the packager manager. This field is mandatory. --> |
||
| 1395 | <install for="' . $context['to_install']['install_for'] . '" /> |
||
| 1396 | <!-- Theme name, used purely for aesthetics. --> |
||
| 1397 | <name>' . $context['to_install']['name'] . '</name> |
||
| 1398 | <!-- Author: your email address or contact information. The name attribute is optional. --> |
||
| 1399 | <author name="Simple Machines">[email protected]</author> |
||
| 1400 | <!-- Website... where to get updates and more information. --> |
||
| 1401 | <website>https://www.simplemachines.org/</website> |
||
| 1402 | <!-- Template layers to use, defaults to "html,body". --> |
||
| 1403 | <layers>' . $context['to_install']['theme_layers'] . '</layers> |
||
| 1404 | <!-- Templates to load on startup. Default is "index". --> |
||
| 1405 | <templates>' . $context['to_install']['theme_templates'] . '</templates> |
||
| 1406 | <!-- Base this theme off another? Default is blank, or no. It could be "default". --> |
||
| 1407 | <based-on></based-on> |
||
| 1408 | </theme-info>'; |
||
| 1409 | |||
| 1410 | // Now write it. |
||
| 1411 | $fp = @fopen($context['to_install']['theme_dir'] . '/theme_info.xml', 'w+'); |
||
| 1412 | if ($fp) |
||
| 1413 | { |
||
| 1414 | fwrite($fp, $xml_info); |
||
| 1415 | fclose($fp); |
||
| 1416 | } |
||
| 1417 | |||
| 1418 | // Install the theme. theme_install() will take care of possible errors. |
||
| 1419 | $context['to_install']['id'] = theme_install($context['to_install']); |
||
| 1420 | |||
| 1421 | // return the info. |
||
| 1422 | return $context['to_install']; |
||
| 1423 | } |
||
| 1424 | |||
| 1425 | /** |
||
| 1426 | * Install a theme from a specific dir |
||
| 1427 | * |
||
| 1428 | * Assumes the dir is located on the main Themes dir. Ends execution with fatal_lang_error() on any error. |
||
| 1429 | * |
||
| 1430 | * @return array The newly created theme's info. |
||
| 1431 | */ |
||
| 1432 | function InstallDir() |
||
| 1433 | { |
||
| 1434 | global $themedir, $themeurl, $context; |
||
| 1435 | |||
| 1436 | // Cannot use the theme dir as a theme dir. |
||
| 1437 | if (!isset($_REQUEST['theme_dir']) || empty($_REQUEST['theme_dir']) || rtrim(realpath($_REQUEST['theme_dir']), '/\\') == realpath($themedir)) |
||
| 1438 | fatal_lang_error('theme_install_invalid_dir', false); |
||
| 1439 | |||
| 1440 | // Check is there is "something" on the dir. |
||
| 1441 | elseif (!is_dir($_REQUEST['theme_dir']) || !file_exists($_REQUEST['theme_dir'] . '/theme_info.xml')) |
||
| 1442 | fatal_lang_error('theme_install_error', false); |
||
| 1443 | |||
| 1444 | $name = basename($_REQUEST['theme_dir']); |
||
| 1445 | $name = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $name); |
||
| 1446 | |||
| 1447 | // All good! set some needed vars. |
||
| 1448 | $context['to_install'] = array( |
||
| 1449 | 'theme_dir' => $_REQUEST['theme_dir'], |
||
| 1450 | 'theme_url' => $themeurl . '/' . $name, |
||
| 1451 | 'name' => $name, |
||
| 1452 | 'images_url' => $themeurl . '/' . $name . '/images', |
||
| 1453 | ); |
||
| 1454 | |||
| 1455 | // Read its info form the XML file. |
||
| 1456 | $theme_info = get_theme_info($context['to_install']['theme_dir']); |
||
| 1457 | $context['to_install'] += $theme_info; |
||
| 1458 | |||
| 1459 | // Install the theme. theme_install() will take care of possible errors. |
||
| 1460 | $context['to_install']['id'] = theme_install($context['to_install']); |
||
| 1461 | |||
| 1462 | // return the info. |
||
| 1463 | return $context['to_install']; |
||
| 1464 | } |
||
| 1465 | |||
| 1466 | /** |
||
| 1467 | * Possibly the simplest and best example of how to use the template system. |
||
| 1468 | * - allows the theme to take care of actions. |
||
| 1469 | * - happens if $settings['catch_action'] is set and action isn't found |
||
| 1470 | * in the action array. |
||
| 1471 | * - can use a template, layers, sub_template, filename, and/or function. |
||
| 1472 | */ |
||
| 1473 | function WrapAction() |
||
| 1474 | { |
||
| 1475 | global $context, $settings; |
||
| 1476 | |||
| 1477 | // Load any necessary template(s)? |
||
| 1478 | if (isset($settings['catch_action']['template'])) |
||
| 1479 | { |
||
| 1480 | // Load both the template and language file. (but don't fret if the language file isn't there...) |
||
| 1481 | loadTemplate($settings['catch_action']['template']); |
||
| 1482 | loadLanguage($settings['catch_action']['template'], '', false); |
||
| 1483 | } |
||
| 1484 | |||
| 1485 | // Any special layers? |
||
| 1486 | if (isset($settings['catch_action']['layers'])) |
||
| 1487 | $context['template_layers'] = $settings['catch_action']['layers']; |
||
| 1488 | |||
| 1489 | // Any function to call? |
||
| 1490 | if (isset($settings['catch_action']['function'])) |
||
| 1491 | { |
||
| 1492 | $hook = $settings['catch_action']['function']; |
||
| 1493 | |||
| 1494 | if (!isset($settings['catch_action']['filename'])) |
||
| 1495 | $settings['catch_action']['filename'] = ''; |
||
| 1496 | |||
| 1497 | add_integration_function('integrate_wrap_action', $hook, false, $settings['catch_action']['filename'], false); |
||
| 1498 | call_integration_hook('integrate_wrap_action'); |
||
| 1499 | } |
||
| 1500 | // And finally, the main sub template ;). |
||
| 1501 | if (isset($settings['catch_action']['sub_template'])) |
||
| 1502 | $context['sub_template'] = $settings['catch_action']['sub_template']; |
||
| 1503 | } |
||
| 1504 | |||
| 1505 | /** |
||
| 1506 | * Set an option via javascript. |
||
| 1507 | * - sets a theme option without outputting anything. |
||
| 1508 | * - can be used with javascript, via a dummy image... (which doesn't require |
||
| 1509 | * the page to reload.) |
||
| 1510 | * - requires someone who is logged in. |
||
| 1511 | * - accessed via ?action=jsoption;var=variable;val=value;session_var=sess_id. |
||
| 1512 | * - does not log access to the Who's Online log. (in index.php..) |
||
| 1513 | */ |
||
| 1514 | function SetJavaScript() |
||
| 1515 | { |
||
| 1516 | global $settings, $user_info, $smcFunc, $options; |
||
| 1517 | |||
| 1518 | // Check the session id. |
||
| 1519 | checkSession('get'); |
||
| 1520 | |||
| 1521 | // This good-for-nothing pixel is being used to keep the session alive. |
||
| 1522 | if (empty($_GET['var']) || !isset($_GET['val'])) |
||
| 1523 | redirectexit($settings['images_url'] . '/blank.png'); |
||
| 1524 | |||
| 1525 | // Sorry, guests can't go any further than this. |
||
| 1526 | if ($user_info['is_guest'] || $user_info['id'] == 0) |
||
| 1527 | obExit(false); |
||
| 1528 | |||
| 1529 | $reservedVars = array( |
||
| 1530 | 'actual_theme_url', |
||
| 1531 | 'actual_images_url', |
||
| 1532 | 'base_theme_dir', |
||
| 1533 | 'base_theme_url', |
||
| 1534 | 'default_images_url', |
||
| 1535 | 'default_theme_dir', |
||
| 1536 | 'default_theme_url', |
||
| 1537 | 'default_template', |
||
| 1538 | 'images_url', |
||
| 1539 | 'number_recent_posts', |
||
| 1540 | 'smiley_sets_default', |
||
| 1541 | 'theme_dir', |
||
| 1542 | 'theme_id', |
||
| 1543 | 'theme_layers', |
||
| 1544 | 'theme_templates', |
||
| 1545 | 'theme_url', |
||
| 1546 | 'name', |
||
| 1547 | ); |
||
| 1548 | |||
| 1549 | // Can't change reserved vars. |
||
| 1550 | if (in_array(strtolower($_GET['var']), $reservedVars)) |
||
| 1551 | redirectexit($settings['images_url'] . '/blank.png'); |
||
| 1552 | |||
| 1553 | // Use a specific theme? |
||
| 1554 | if (isset($_GET['th']) || isset($_GET['id'])) |
||
| 1555 | { |
||
| 1556 | // Invalidate the current themes cache too. |
||
| 1557 | cache_put_data('theme_settings-' . $settings['theme_id'] . ':' . $user_info['id'], null, 60); |
||
| 1558 | |||
| 1559 | $settings['theme_id'] = isset($_GET['th']) ? (int) $_GET['th'] : (int) $_GET['id']; |
||
| 1560 | } |
||
| 1561 | |||
| 1562 | // If this is the admin preferences the passed value will just be an element of it. |
||
| 1563 | if ($_GET['var'] == 'admin_preferences') |
||
| 1564 | { |
||
| 1565 | $options['admin_preferences'] = !empty($options['admin_preferences']) ? $smcFunc['json_decode']($options['admin_preferences'], true) : array(); |
||
| 1566 | // New thingy... |
||
| 1567 | if (isset($_GET['admin_key']) && strlen($_GET['admin_key']) < 5) |
||
| 1568 | $options['admin_preferences'][$_GET['admin_key']] = $_GET['val']; |
||
| 1569 | |||
| 1570 | // Change the value to be something nice, |
||
| 1571 | $_GET['val'] = $smcFunc['json_encode']($options['admin_preferences']); |
||
| 1572 | } |
||
| 1573 | |||
| 1574 | // Update the option. |
||
| 1575 | $smcFunc['db_insert']('replace', |
||
| 1576 | '{db_prefix}themes', |
||
| 1577 | array('id_theme' => 'int', 'id_member' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), |
||
| 1578 | array($settings['theme_id'], $user_info['id'], $_GET['var'], is_array($_GET['val']) ? implode(',', $_GET['val']) : $_GET['val']), |
||
| 1579 | array('id_theme', 'id_member', 'variable') |
||
| 1580 | ); |
||
| 1581 | |||
| 1582 | cache_put_data('theme_settings-' . $settings['theme_id'] . ':' . $user_info['id'], null, 60); |
||
| 1583 | |||
| 1584 | // Don't output anything... |
||
| 1585 | redirectexit($settings['images_url'] . '/blank.png'); |
||
| 1586 | } |
||
| 1587 | |||
| 1588 | /** |
||
| 1589 | * Shows an interface for editing the templates. |
||
| 1590 | * - uses the Themes template and edit_template/edit_style sub template. |
||
| 1591 | * - accessed via ?action=admin;area=theme;sa=edit |
||
| 1592 | */ |
||
| 1593 | function EditTheme() |
||
| 1594 | { |
||
| 1595 | global $context, $scripturl, $boarddir, $smcFunc, $txt; |
||
| 1596 | |||
| 1597 | // @todo Should this be removed? |
||
| 1598 | if (isset($_REQUEST['preview'])) |
||
| 1599 | die('die() with fire'); |
||
|
0 ignored issues
–
show
|
|||
| 1600 | |||
| 1601 | isAllowedTo('admin_forum'); |
||
| 1602 | loadTemplate('Themes'); |
||
| 1603 | |||
| 1604 | $_GET['th'] = isset($_GET['th']) ? (int) $_GET['th'] : (int) @$_GET['id']; |
||
| 1605 | |||
| 1606 | if (empty($_GET['th'])) |
||
| 1607 | { |
||
| 1608 | get_installed_themes(); |
||
| 1609 | |||
| 1610 | foreach ($context['themes'] as $key => $theme) |
||
| 1611 | { |
||
| 1612 | // There has to be a Settings template! |
||
| 1613 | if (!file_exists($theme['theme_dir'] . '/index.template.php') && !file_exists($theme['theme_dir'] . '/css/index.css')) |
||
| 1614 | unset($context['themes'][$key]); |
||
| 1615 | |||
| 1616 | else |
||
| 1617 | $context['themes'][$key]['can_edit_style'] = file_exists($theme['theme_dir'] . '/css/index.css'); |
||
| 1618 | } |
||
| 1619 | |||
| 1620 | $context['sub_template'] = 'edit_list'; |
||
| 1621 | |||
| 1622 | return 'no_themes'; |
||
| 1623 | } |
||
| 1624 | |||
| 1625 | $context['session_error'] = false; |
||
| 1626 | |||
| 1627 | // Get the directory of the theme we are editing. |
||
| 1628 | $currentTheme = get_single_theme($_GET['th']); |
||
| 1629 | $context['theme_id'] = $currentTheme['id']; |
||
| 1630 | $context['browse_title'] = sprintf($txt['themeadmin_browsing_theme'], $currentTheme['name']); |
||
| 1631 | |||
| 1632 | if (!file_exists($currentTheme['theme_dir'] . '/index.template.php') && !file_exists($currentTheme['theme_dir'] . '/css/index.css')) |
||
| 1633 | fatal_lang_error('theme_edit_missing', false); |
||
| 1634 | |||
| 1635 | if (!isset($_REQUEST['filename'])) |
||
| 1636 | { |
||
| 1637 | if (isset($_GET['directory'])) |
||
| 1638 | { |
||
| 1639 | if (substr($_GET['directory'], 0, 1) == '.') |
||
| 1640 | $_GET['directory'] = ''; |
||
| 1641 | else |
||
| 1642 | { |
||
| 1643 | $_GET['directory'] = preg_replace(array('~^[\./\\:\0\n\r]+~', '~[\\\\]~', '~/[\./]+~'), array('', '/', '/'), $_GET['directory']); |
||
| 1644 | |||
| 1645 | $temp = realpath($currentTheme['theme_dir'] . '/' . $_GET['directory']); |
||
| 1646 | if (empty($temp) || substr($temp, 0, strlen(realpath($currentTheme['theme_dir']))) != realpath($currentTheme['theme_dir'])) |
||
| 1647 | $_GET['directory'] = ''; |
||
| 1648 | } |
||
| 1649 | } |
||
| 1650 | |||
| 1651 | if (isset($_GET['directory']) && $_GET['directory'] != '') |
||
| 1652 | { |
||
| 1653 | $context['theme_files'] = get_file_listing($currentTheme['theme_dir'] . '/' . $_GET['directory'], $_GET['directory'] . '/'); |
||
| 1654 | |||
| 1655 | $temp = dirname($_GET['directory']); |
||
| 1656 | array_unshift($context['theme_files'], array( |
||
| 1657 | 'filename' => $temp == '.' || $temp == '' ? '/ (..)' : $temp . ' (..)', |
||
| 1658 | 'is_writable' => is_writable($currentTheme['theme_dir'] . '/' . $temp), |
||
| 1659 | 'is_directory' => true, |
||
| 1660 | 'is_template' => false, |
||
| 1661 | 'is_image' => false, |
||
| 1662 | 'is_editable' => false, |
||
| 1663 | 'href' => $scripturl . '?action=admin;area=theme;th=' . $_GET['th'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=edit;directory=' . $temp, |
||
| 1664 | 'size' => '', |
||
| 1665 | )); |
||
| 1666 | } |
||
| 1667 | else |
||
| 1668 | $context['theme_files'] = get_file_listing($currentTheme['theme_dir'], ''); |
||
| 1669 | |||
| 1670 | // Do not list minified_ files |
||
| 1671 | foreach ($context['theme_files'] as $key => $file) |
||
| 1672 | { |
||
| 1673 | if (strpos($file['filename'], 'minified_') !== false) |
||
| 1674 | unset($context['theme_files'][$key]); |
||
| 1675 | } |
||
| 1676 | |||
| 1677 | $context['sub_template'] = 'edit_browse'; |
||
| 1678 | |||
| 1679 | return; |
||
| 1680 | } |
||
| 1681 | else |
||
| 1682 | { |
||
| 1683 | if (substr($_REQUEST['filename'], 0, 1) == '.') |
||
| 1684 | $_REQUEST['filename'] = ''; |
||
| 1685 | else |
||
| 1686 | { |
||
| 1687 | $_REQUEST['filename'] = preg_replace(array('~^[\./\\:\0\n\r]+~', '~[\\\\]~', '~/[\./]+~'), array('', '/', '/'), $_REQUEST['filename']); |
||
| 1688 | |||
| 1689 | $temp = realpath($currentTheme['theme_dir'] . '/' . $_REQUEST['filename']); |
||
| 1690 | if (empty($temp) || substr($temp, 0, strlen(realpath($currentTheme['theme_dir']))) != realpath($currentTheme['theme_dir'])) |
||
| 1691 | $_REQUEST['filename'] = ''; |
||
| 1692 | } |
||
| 1693 | |||
| 1694 | if (empty($_REQUEST['filename'])) |
||
| 1695 | fatal_lang_error('theme_edit_missing', false); |
||
| 1696 | } |
||
| 1697 | |||
| 1698 | if (isset($_POST['save'])) |
||
| 1699 | { |
||
| 1700 | if (checkSession('post', '', false) == '' && validateToken('admin-te-' . md5($_GET['th'] . '-' . $_REQUEST['filename']), 'post', false) == true) |
||
| 1701 | { |
||
| 1702 | if (is_array($_POST['entire_file'])) |
||
| 1703 | $_POST['entire_file'] = implode("\n", $_POST['entire_file']); |
||
| 1704 | |||
| 1705 | $_POST['entire_file'] = rtrim(strtr($_POST['entire_file'], array("\r" => '', ' ' => "\t"))); |
||
| 1706 | |||
| 1707 | // Check for a parse error! |
||
| 1708 | if (substr($_REQUEST['filename'], -13) == '.template.php' && is_writable($currentTheme['theme_dir']) && ini_get('display_errors')) |
||
| 1709 | { |
||
| 1710 | $fp = fopen($currentTheme['theme_dir'] . '/tmp_' . session_id() . '.php', 'w'); |
||
| 1711 | fwrite($fp, $_POST['entire_file']); |
||
| 1712 | fclose($fp); |
||
| 1713 | |||
| 1714 | $error = @file_get_contents($currentTheme['theme_url'] . '/tmp_' . session_id() . '.php'); |
||
| 1715 | if (preg_match('~ <b>(\d+)</b><br( /)?' . '>$~i', $error) != 0) |
||
| 1716 | $error_file = $currentTheme['theme_dir'] . '/tmp_' . session_id() . '.php'; |
||
| 1717 | else |
||
| 1718 | unlink($currentTheme['theme_dir'] . '/tmp_' . session_id() . '.php'); |
||
| 1719 | } |
||
| 1720 | |||
| 1721 | if (!isset($error_file)) |
||
| 1722 | { |
||
| 1723 | $fp = fopen($currentTheme['theme_dir'] . '/' . $_REQUEST['filename'], 'w'); |
||
| 1724 | fwrite($fp, $_POST['entire_file']); |
||
| 1725 | fclose($fp); |
||
| 1726 | |||
| 1727 | // Nuke any minified files and update $modSettings['browser_cache'] |
||
| 1728 | deleteAllMinified(); |
||
| 1729 | |||
| 1730 | redirectexit('action=admin;area=theme;th=' . $_GET['th'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=edit;directory=' . dirname($_REQUEST['filename'])); |
||
| 1731 | } |
||
| 1732 | } |
||
| 1733 | // Session timed out. |
||
| 1734 | else |
||
| 1735 | { |
||
| 1736 | loadLanguage('Errors'); |
||
| 1737 | |||
| 1738 | $context['session_error'] = true; |
||
| 1739 | $context['sub_template'] = 'edit_file'; |
||
| 1740 | |||
| 1741 | // Recycle the submitted data. |
||
| 1742 | if (is_array($_POST['entire_file'])) |
||
| 1743 | $context['entire_file'] = $smcFunc['htmlspecialchars'](implode("\n", $_POST['entire_file'])); |
||
| 1744 | else |
||
| 1745 | $context['entire_file'] = $smcFunc['htmlspecialchars']($_POST['entire_file']); |
||
| 1746 | |||
| 1747 | $context['edit_filename'] = $smcFunc['htmlspecialchars']($_POST['filename']); |
||
| 1748 | |||
| 1749 | // You were able to submit it, so it's reasonable to assume you are allowed to save. |
||
| 1750 | $context['allow_save'] = true; |
||
| 1751 | |||
| 1752 | // Re-create the token so that it can be used |
||
| 1753 | createToken('admin-te-' . md5($_GET['th'] . '-' . $_REQUEST['filename'])); |
||
| 1754 | |||
| 1755 | return; |
||
| 1756 | } |
||
| 1757 | } |
||
| 1758 | |||
| 1759 | $context['allow_save'] = is_writable($currentTheme['theme_dir'] . '/' . $_REQUEST['filename']); |
||
| 1760 | $context['allow_save_filename'] = strtr($currentTheme['theme_dir'] . '/' . $_REQUEST['filename'], array($boarddir => '...')); |
||
| 1761 | $context['edit_filename'] = $smcFunc['htmlspecialchars']($_REQUEST['filename']); |
||
| 1762 | |||
| 1763 | if (substr($_REQUEST['filename'], -4) == '.css') |
||
| 1764 | { |
||
| 1765 | $context['sub_template'] = 'edit_style'; |
||
| 1766 | |||
| 1767 | $context['entire_file'] = $smcFunc['htmlspecialchars'](strtr(file_get_contents($currentTheme['theme_dir'] . '/' . $_REQUEST['filename']), array("\t" => ' '))); |
||
| 1768 | } |
||
| 1769 | elseif (substr($_REQUEST['filename'], -13) == '.template.php') |
||
| 1770 | { |
||
| 1771 | $context['sub_template'] = 'edit_template'; |
||
| 1772 | |||
| 1773 | if (!isset($error_file)) |
||
| 1774 | $file_data = file($currentTheme['theme_dir'] . '/' . $_REQUEST['filename']); |
||
| 1775 | else |
||
| 1776 | { |
||
| 1777 | if (preg_match('~(<b>.+?</b>:.+?<b>).+?(</b>.+?<b>\d+</b>)<br( /)?' . '>$~i', $error, $match) != 0) |
||
| 1778 | $context['parse_error'] = $match[1] . $_REQUEST['filename'] . $match[2]; |
||
| 1779 | $file_data = file($error_file); |
||
| 1780 | unlink($error_file); |
||
| 1781 | } |
||
| 1782 | |||
| 1783 | $j = 0; |
||
| 1784 | $context['file_parts'] = array(array('lines' => 0, 'line' => 1, 'data' => '')); |
||
| 1785 | for ($i = 0, $n = count($file_data); $i < $n; $i++) |
||
| 1786 | { |
||
| 1787 | if (isset($file_data[$i + 1]) && substr($file_data[$i + 1], 0, 9) == 'function ') |
||
| 1788 | { |
||
| 1789 | // Try to format the functions a little nicer... |
||
| 1790 | $context['file_parts'][$j]['data'] = trim($context['file_parts'][$j]['data']) . "\n"; |
||
| 1791 | |||
| 1792 | if (empty($context['file_parts'][$j]['lines'])) |
||
| 1793 | unset($context['file_parts'][$j]); |
||
| 1794 | $context['file_parts'][++$j] = array('lines' => 0, 'line' => $i + 1, 'data' => ''); |
||
| 1795 | } |
||
| 1796 | |||
| 1797 | $context['file_parts'][$j]['lines']++; |
||
| 1798 | $context['file_parts'][$j]['data'] .= $smcFunc['htmlspecialchars'](strtr($file_data[$i], array("\t" => ' '))); |
||
| 1799 | } |
||
| 1800 | |||
| 1801 | $context['entire_file'] = $smcFunc['htmlspecialchars'](strtr(implode('', $file_data), array("\t" => ' '))); |
||
| 1802 | } |
||
| 1803 | else |
||
| 1804 | { |
||
| 1805 | $context['sub_template'] = 'edit_file'; |
||
| 1806 | |||
| 1807 | $context['entire_file'] = $smcFunc['htmlspecialchars'](strtr(file_get_contents($currentTheme['theme_dir'] . '/' . $_REQUEST['filename']), array("\t" => ' '))); |
||
| 1808 | } |
||
| 1809 | |||
| 1810 | // Create a special token to allow editing of multiple files. |
||
| 1811 | createToken('admin-te-' . md5($_GET['th'] . '-' . $_REQUEST['filename'])); |
||
| 1812 | } |
||
| 1813 | |||
| 1814 | /** |
||
| 1815 | * Makes a copy of a template file in a new location |
||
| 1816 | * |
||
| 1817 | * @uses Themes template, copy_template sub-template. |
||
| 1818 | */ |
||
| 1819 | function CopyTemplate() |
||
| 1820 | { |
||
| 1821 | global $context, $settings; |
||
| 1822 | |||
| 1823 | isAllowedTo('admin_forum'); |
||
| 1824 | loadTemplate('Themes'); |
||
| 1825 | |||
| 1826 | $context[$context['admin_menu_name']]['current_subsection'] = 'edit'; |
||
| 1827 | |||
| 1828 | $_GET['th'] = isset($_GET['th']) ? (int) $_GET['th'] : (int) $_GET['id']; |
||
| 1829 | |||
| 1830 | if (empty($_GET['th'])) |
||
| 1831 | fatal_lang_error('theme_install_invalid_id'); |
||
| 1832 | |||
| 1833 | // Get the theme info. |
||
| 1834 | $theme = get_single_theme($_GET['th']); |
||
| 1835 | $context['theme_id'] = $theme['id']; |
||
| 1836 | |||
| 1837 | if (isset($_REQUEST['template']) && preg_match('~[\./\\\\:\0]~', $_REQUEST['template']) == 0) |
||
| 1838 | { |
||
| 1839 | if (file_exists($settings['default_theme_dir'] . '/' . $_REQUEST['template'] . '.template.php')) |
||
| 1840 | $filename = $settings['default_theme_dir'] . '/' . $_REQUEST['template'] . '.template.php'; |
||
| 1841 | |||
| 1842 | else |
||
| 1843 | fatal_lang_error('no_access', false); |
||
| 1844 | |||
| 1845 | $fp = fopen($theme['theme_dir'] . '/' . $_REQUEST['template'] . '.template.php', 'w'); |
||
| 1846 | fwrite($fp, file_get_contents($filename)); |
||
| 1847 | fclose($fp); |
||
| 1848 | |||
| 1849 | redirectexit('action=admin;area=theme;th=' . $context['theme_id'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=copy'); |
||
| 1850 | } |
||
| 1851 | elseif (isset($_REQUEST['lang_file']) && preg_match('~^[^\./\\\\:\0]\.[^\./\\\\:\0]$~', $_REQUEST['lang_file']) != 0) |
||
| 1852 | { |
||
| 1853 | if (file_exists($settings['default_theme_dir'] . '/languages/' . $_REQUEST['template'] . '.php')) |
||
| 1854 | $filename = $settings['default_theme_dir'] . '/languages/' . $_REQUEST['template'] . '.php'; |
||
| 1855 | |||
| 1856 | else |
||
| 1857 | fatal_lang_error('no_access', false); |
||
| 1858 | |||
| 1859 | $fp = fopen($theme['theme_dir'] . '/languages/' . $_REQUEST['lang_file'] . '.php', 'w'); |
||
| 1860 | fwrite($fp, file_get_contents($filename)); |
||
| 1861 | fclose($fp); |
||
| 1862 | |||
| 1863 | redirectexit('action=admin;area=theme;th=' . $context['theme_id'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=copy'); |
||
| 1864 | } |
||
| 1865 | |||
| 1866 | $templates = array(); |
||
| 1867 | $lang_files = array(); |
||
| 1868 | |||
| 1869 | $dir = dir($settings['default_theme_dir']); |
||
| 1870 | while ($entry = $dir->read()) |
||
| 1871 | { |
||
| 1872 | if (substr($entry, -13) == '.template.php') |
||
| 1873 | $templates[] = substr($entry, 0, -13); |
||
| 1874 | } |
||
| 1875 | $dir->close(); |
||
| 1876 | |||
| 1877 | $dir = dir($settings['default_theme_dir'] . '/languages'); |
||
| 1878 | while ($entry = $dir->read()) |
||
| 1879 | { |
||
| 1880 | if (preg_match('~^([^\.]+\.[^\.]+)\.php$~', $entry, $matches)) |
||
| 1881 | $lang_files[] = $matches[1]; |
||
| 1882 | } |
||
| 1883 | $dir->close(); |
||
| 1884 | |||
| 1885 | natcasesort($templates); |
||
| 1886 | natcasesort($lang_files); |
||
| 1887 | |||
| 1888 | $context['available_templates'] = array(); |
||
| 1889 | foreach ($templates as $template) |
||
| 1890 | $context['available_templates'][$template] = array( |
||
| 1891 | 'filename' => $template . '.template.php', |
||
| 1892 | 'value' => $template, |
||
| 1893 | 'already_exists' => false, |
||
| 1894 | 'can_copy' => is_writable($theme['theme_dir']), |
||
| 1895 | ); |
||
| 1896 | $context['available_language_files'] = array(); |
||
| 1897 | foreach ($lang_files as $file) |
||
| 1898 | $context['available_language_files'][$file] = array( |
||
| 1899 | 'filename' => $file . '.php', |
||
| 1900 | 'value' => $file, |
||
| 1901 | 'already_exists' => false, |
||
| 1902 | 'can_copy' => file_exists($theme['theme_dir'] . '/languages') ? is_writable($theme['theme_dir'] . '/languages') : is_writable($theme['theme_dir']), |
||
| 1903 | ); |
||
| 1904 | |||
| 1905 | $dir = dir($theme['theme_dir']); |
||
| 1906 | while ($entry = $dir->read()) |
||
| 1907 | { |
||
| 1908 | if (substr($entry, -13) == '.template.php' && isset($context['available_templates'][substr($entry, 0, -13)])) |
||
| 1909 | { |
||
| 1910 | $context['available_templates'][substr($entry, 0, -13)]['already_exists'] = true; |
||
| 1911 | $context['available_templates'][substr($entry, 0, -13)]['can_copy'] = is_writable($theme['theme_dir'] . '/' . $entry); |
||
| 1912 | } |
||
| 1913 | } |
||
| 1914 | $dir->close(); |
||
| 1915 | |||
| 1916 | if (file_exists($theme['theme_dir'] . '/languages')) |
||
| 1917 | { |
||
| 1918 | $dir = dir($theme['theme_dir'] . '/languages'); |
||
| 1919 | while ($entry = $dir->read()) |
||
| 1920 | { |
||
| 1921 | if (preg_match('~^([^\.]+\.[^\.]+)\.php$~', $entry, $matches) && isset($context['available_language_files'][$matches[1]])) |
||
| 1922 | { |
||
| 1923 | $context['available_language_files'][$matches[1]]['already_exists'] = true; |
||
| 1924 | $context['available_language_files'][$matches[1]]['can_copy'] = is_writable($theme['theme_dir'] . '/languages/' . $entry); |
||
| 1925 | } |
||
| 1926 | } |
||
| 1927 | $dir->close(); |
||
| 1928 | } |
||
| 1929 | |||
| 1930 | $context['sub_template'] = 'copy_template'; |
||
| 1931 | } |
||
| 1932 | |||
| 1933 | ?> |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.