Yoshi2889 /
SMF2.1
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 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 2017 Simple Machines and individual contributors |
||
| 28 | * @license http://www.simplemachines.org/about/smf/license.php BSD |
||
| 29 | * |
||
| 30 | * @version 2.1 Beta 4 |
||
| 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 | View Code Duplication | 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 installed and 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_all_themes(false); |
||
| 202 | |||
| 203 | $setValues = array(); |
||
| 204 | foreach ($context['themes'] as $id => $theme) |
||
| 205 | { |
||
| 206 | View Code Duplication | 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 | View Code Duplication | 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 | View Code Duplication | 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_all_themes(false); |
||
| 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 | View Code Duplication | 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 | View Code Duplication | 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 | View Code Duplication | 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 | View Code Duplication | 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 | View Code Duplication | 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 | $context['sub_template'] = 'set_options'; |
||
| 563 | $context['page_title'] = $txt['theme_settings']; |
||
| 564 | |||
| 565 | $context['options'] = $context['theme_options']; |
||
| 566 | $context['theme_settings'] = $settings; |
||
| 567 | |||
| 568 | if (empty($_REQUEST['who'])) |
||
| 569 | { |
||
| 570 | $request = $smcFunc['db_query']('', ' |
||
| 571 | SELECT variable, value |
||
| 572 | FROM {db_prefix}themes |
||
| 573 | WHERE id_theme IN (1, {int:current_theme}) |
||
| 574 | AND id_member = {int:guest_member}', |
||
| 575 | array( |
||
| 576 | 'current_theme' => $_GET['th'], |
||
| 577 | 'guest_member' => -1, |
||
| 578 | ) |
||
| 579 | ); |
||
| 580 | $context['theme_options'] = array(); |
||
| 581 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 582 | $context['theme_options'][$row['variable']] = $row['value']; |
||
| 583 | $smcFunc['db_free_result']($request); |
||
| 584 | |||
| 585 | $context['theme_options_reset'] = false; |
||
| 586 | } |
||
| 587 | else |
||
| 588 | { |
||
| 589 | $context['theme_options'] = array(); |
||
| 590 | $context['theme_options_reset'] = true; |
||
| 591 | } |
||
| 592 | |||
| 593 | foreach ($context['options'] as $i => $setting) |
||
| 594 | { |
||
| 595 | // Just skip separators |
||
| 596 | if (!is_array($setting)) |
||
| 597 | continue; |
||
| 598 | |||
| 599 | // Is this disabled? |
||
| 600 | if ($setting['id'] == 'calendar_start_day' && empty($modSettings['cal_enabled'])) |
||
| 601 | { |
||
| 602 | unset($context['options'][$i]); |
||
| 603 | continue; |
||
| 604 | } |
||
| 605 | elseif (($setting['id'] == 'topics_per_page' || $setting['id'] == 'messages_per_page') && !empty($modSettings['disableCustomPerPage'])) |
||
| 606 | { |
||
| 607 | unset($context['options'][$i]); |
||
| 608 | continue; |
||
| 609 | } |
||
| 610 | |||
| 611 | View Code Duplication | if (!isset($setting['type']) || $setting['type'] == 'bool') |
|
| 612 | $context['options'][$i]['type'] = 'checkbox'; |
||
| 613 | elseif ($setting['type'] == 'int' || $setting['type'] == 'integer') |
||
| 614 | $context['options'][$i]['type'] = 'number'; |
||
| 615 | elseif ($setting['type'] == 'string') |
||
| 616 | $context['options'][$i]['type'] = 'text'; |
||
| 617 | |||
| 618 | if (isset($setting['options'])) |
||
| 619 | $context['options'][$i]['type'] = 'list'; |
||
| 620 | |||
| 621 | $context['options'][$i]['value'] = !isset($context['theme_options'][$setting['id']]) ? '' : $context['theme_options'][$setting['id']]; |
||
| 622 | } |
||
| 623 | |||
| 624 | // Restore the existing theme. |
||
| 625 | loadTheme($old_id, false); |
||
| 626 | $settings = $old_settings; |
||
| 627 | |||
| 628 | loadTemplate('Themes'); |
||
| 629 | createToken('admin-sto'); |
||
| 630 | } |
||
| 631 | |||
| 632 | /** |
||
| 633 | * Administrative global settings. |
||
| 634 | * - saves and requests global theme settings. ($settings) |
||
| 635 | * - loads the Admin language file. |
||
| 636 | * - calls ThemeAdmin() if no theme is specified. (the theme center.) |
||
| 637 | * - requires admin_forum permission. |
||
| 638 | * - accessed with ?action=admin;area=theme;sa=list&th=xx. |
||
| 639 | */ |
||
| 640 | function SetThemeSettings() |
||
| 641 | { |
||
| 642 | global $txt, $context, $settings, $modSettings, $smcFunc; |
||
| 643 | |||
| 644 | if (empty($_GET['th']) && empty($_GET['id'])) |
||
| 645 | return ThemeAdmin(); |
||
| 646 | |||
| 647 | $_GET['th'] = isset($_GET['th']) ? (int) $_GET['th'] : (int) $_GET['id']; |
||
| 648 | |||
| 649 | // Select the best fitting tab. |
||
| 650 | $context[$context['admin_menu_name']]['current_subsection'] = 'list'; |
||
| 651 | |||
| 652 | loadLanguage('Admin'); |
||
| 653 | isAllowedTo('admin_forum'); |
||
| 654 | |||
| 655 | // Validate inputs/user. |
||
| 656 | if (empty($_GET['th'])) |
||
| 657 | fatal_lang_error('no_theme', false); |
||
| 658 | |||
| 659 | // Fetch the smiley sets... |
||
| 660 | $sets = explode(',', 'none,' . $modSettings['smiley_sets_known']); |
||
| 661 | $set_names = explode("\n", $txt['smileys_none'] . "\n" . $modSettings['smiley_sets_names']); |
||
| 662 | $context['smiley_sets'] = array( |
||
| 663 | '' => $txt['smileys_no_default'] |
||
| 664 | ); |
||
| 665 | foreach ($sets as $i => $set) |
||
| 666 | $context['smiley_sets'][$set] = $smcFunc['htmlspecialchars']($set_names[$i]); |
||
| 667 | |||
| 668 | $old_id = $settings['theme_id']; |
||
| 669 | $old_settings = $settings; |
||
| 670 | |||
| 671 | loadTheme($_GET['th'], false); |
||
| 672 | |||
| 673 | // Sadly we really do need to init the template. |
||
| 674 | loadSubTemplate('init', 'ignore'); |
||
| 675 | |||
| 676 | // Also load the actual themes language file - in case of special settings. |
||
| 677 | loadLanguage('Settings', '', true, true); |
||
| 678 | |||
| 679 | // And the custom language strings... |
||
| 680 | loadLanguage('ThemeStrings', '', false, true); |
||
| 681 | |||
| 682 | // Let the theme take care of the settings. |
||
| 683 | loadTemplate('Settings'); |
||
| 684 | loadSubTemplate('settings'); |
||
| 685 | |||
| 686 | // Load the variants separately... |
||
| 687 | $settings['theme_variants'] = array(); |
||
| 688 | if (file_exists($settings['theme_dir'] . '/index.template.php')) |
||
| 689 | { |
||
| 690 | $file_contents = implode('', file($settings['theme_dir'] . '/index.template.php')); |
||
| 691 | if (preg_match('~\$settings\[\'theme_variants\'\]\s*=(.+?);~', $file_contents, $matches)) |
||
| 692 | eval('global $settings;' . $matches[0]); |
||
| 693 | } |
||
| 694 | |||
| 695 | // Submitting! |
||
| 696 | if (isset($_POST['save'])) |
||
| 697 | { |
||
| 698 | checkSession(); |
||
| 699 | validateToken('admin-sts'); |
||
| 700 | |||
| 701 | if (empty($_POST['options'])) |
||
| 702 | $_POST['options'] = array(); |
||
| 703 | if (empty($_POST['default_options'])) |
||
| 704 | $_POST['default_options'] = array(); |
||
| 705 | |||
| 706 | // Make sure items are cast correctly. |
||
| 707 | foreach ($context['theme_settings'] as $item) |
||
| 708 | { |
||
| 709 | // Disregard this item if this is just a separator. |
||
| 710 | if (!is_array($item)) |
||
| 711 | continue; |
||
| 712 | |||
| 713 | foreach (array('options', 'default_options') as $option) |
||
| 714 | { |
||
| 715 | if (!isset($_POST[$option][$item['id']])) |
||
| 716 | continue; |
||
| 717 | // Checkbox. |
||
| 718 | View Code Duplication | elseif (empty($item['type'])) |
|
| 719 | $_POST[$option][$item['id']] = $_POST[$option][$item['id']] ? 1 : 0; |
||
| 720 | // Number |
||
| 721 | View Code Duplication | elseif ($item['type'] == 'number') |
|
| 722 | $_POST[$option][$item['id']] = (int) $_POST[$option][$item['id']]; |
||
| 723 | } |
||
| 724 | } |
||
| 725 | |||
| 726 | // Set up the sql query. |
||
| 727 | $inserts = array(); |
||
| 728 | View Code Duplication | foreach ($_POST['options'] as $opt => $val) |
|
| 729 | $inserts[] = array(0, $_GET['th'], $opt, is_array($val) ? implode(',', $val) : $val); |
||
| 730 | View Code Duplication | foreach ($_POST['default_options'] as $opt => $val) |
|
| 731 | $inserts[] = array(0, 1, $opt, is_array($val) ? implode(',', $val) : $val); |
||
| 732 | // If we're actually inserting something.. |
||
| 733 | View Code Duplication | if (!empty($inserts)) |
|
| 734 | { |
||
| 735 | $smcFunc['db_insert']('replace', |
||
| 736 | '{db_prefix}themes', |
||
| 737 | array('id_member' => 'int', 'id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), |
||
| 738 | $inserts, |
||
| 739 | array('id_member', 'id_theme', 'variable') |
||
| 740 | ); |
||
| 741 | } |
||
| 742 | |||
| 743 | cache_put_data('theme_settings-' . $_GET['th'], null, 90); |
||
| 744 | cache_put_data('theme_settings-1', null, 90); |
||
| 745 | |||
| 746 | // Invalidate the cache. |
||
| 747 | updateSettings(array('settings_updated' => time())); |
||
| 748 | |||
| 749 | redirectexit('action=admin;area=theme;sa=list;th=' . $_GET['th'] . ';' . $context['session_var'] . '=' . $context['session_id']); |
||
| 750 | } |
||
| 751 | |||
| 752 | $context['sub_template'] = 'set_settings'; |
||
| 753 | $context['page_title'] = $txt['theme_settings']; |
||
| 754 | |||
| 755 | foreach ($settings as $setting => $dummy) |
||
| 756 | { |
||
| 757 | if (!in_array($setting, array('theme_url', 'theme_dir', 'images_url', 'template_dirs'))) |
||
| 758 | $settings[$setting] = htmlspecialchars__recursive($settings[$setting]); |
||
| 759 | } |
||
| 760 | |||
| 761 | $context['settings'] = $context['theme_settings']; |
||
| 762 | $context['theme_settings'] = $settings; |
||
| 763 | |||
| 764 | foreach ($context['settings'] as $i => $setting) |
||
| 765 | { |
||
| 766 | // Separators are dummies, so leave them alone. |
||
| 767 | if (!is_array($setting)) |
||
| 768 | continue; |
||
| 769 | |||
| 770 | View Code Duplication | if (!isset($setting['type']) || $setting['type'] == 'bool') |
|
| 771 | $context['settings'][$i]['type'] = 'checkbox'; |
||
| 772 | elseif ($setting['type'] == 'int' || $setting['type'] == 'integer') |
||
| 773 | $context['settings'][$i]['type'] = 'number'; |
||
| 774 | elseif ($setting['type'] == 'string') |
||
| 775 | $context['settings'][$i]['type'] = 'text'; |
||
| 776 | |||
| 777 | if (isset($setting['options'])) |
||
| 778 | $context['settings'][$i]['type'] = 'list'; |
||
| 779 | |||
| 780 | $context['settings'][$i]['value'] = !isset($settings[$setting['id']]) ? '' : $settings[$setting['id']]; |
||
| 781 | } |
||
| 782 | |||
| 783 | // Do we support variants? |
||
| 784 | if (!empty($settings['theme_variants'])) |
||
| 785 | { |
||
| 786 | $context['theme_variants'] = array(); |
||
| 787 | View Code Duplication | foreach ($settings['theme_variants'] as $variant) |
|
| 788 | { |
||
| 789 | // Have any text, old chap? |
||
| 790 | $context['theme_variants'][$variant] = array( |
||
| 791 | 'label' => isset($txt['variant_' . $variant]) ? $txt['variant_' . $variant] : $variant, |
||
| 792 | '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'), |
||
| 793 | ); |
||
| 794 | } |
||
| 795 | $context['default_variant'] = !empty($settings['default_variant']) && isset($context['theme_variants'][$settings['default_variant']]) ? $settings['default_variant'] : $settings['theme_variants'][0]; |
||
| 796 | } |
||
| 797 | |||
| 798 | // Restore the current theme. |
||
| 799 | loadTheme($old_id, false); |
||
| 800 | |||
| 801 | // Reinit just incase. |
||
| 802 | loadSubTemplate('init', 'ignore'); |
||
| 803 | |||
| 804 | $settings = $old_settings; |
||
| 805 | |||
| 806 | loadTemplate('Themes'); |
||
| 807 | |||
| 808 | // We like Kenny better than Token. |
||
| 809 | createToken('admin-sts'); |
||
| 810 | } |
||
| 811 | |||
| 812 | /** |
||
| 813 | * Remove a theme from the database. |
||
| 814 | * - removes an installed theme. |
||
| 815 | * - requires an administrator. |
||
| 816 | * - accessed with ?action=admin;area=theme;sa=remove. |
||
| 817 | */ |
||
| 818 | function RemoveTheme() |
||
| 819 | { |
||
| 820 | global $context; |
||
| 821 | |||
| 822 | checkSession('get'); |
||
| 823 | |||
| 824 | isAllowedTo('admin_forum'); |
||
| 825 | validateToken('admin-tr', 'request'); |
||
| 826 | |||
| 827 | // The theme's ID must be an integer. |
||
| 828 | $themeID = isset($_GET['th']) ? (int) $_GET['th'] : (int) $_GET['id']; |
||
| 829 | |||
| 830 | // You can't delete the default theme! |
||
| 831 | if ($themeID == 1) |
||
| 832 | fatal_lang_error('no_access', false); |
||
| 833 | |||
| 834 | $theme_info = get_single_theme($themeID); |
||
| 835 | |||
| 836 | // Remove it from the DB. |
||
| 837 | remove_theme($themeID); |
||
| 838 | |||
| 839 | // And remove all its files and folders too. |
||
| 840 | if (!empty($theme_info) && !empty($theme_info['theme_dir'])) |
||
| 841 | remove_dir($theme_info['theme_dir']); |
||
| 842 | |||
| 843 | // Go back to the list page. |
||
| 844 | redirectexit('action=admin;area=theme;sa=list;' . $context['session_var'] . '=' . $context['session_id'] . ';done=removing'); |
||
| 845 | } |
||
| 846 | |||
| 847 | /** |
||
| 848 | * Handles enabling/disabling a theme from the admin center |
||
| 849 | */ |
||
| 850 | function EnableTheme() |
||
| 851 | { |
||
| 852 | global $modSettings, $context; |
||
| 853 | |||
| 854 | checkSession('get'); |
||
| 855 | |||
| 856 | isAllowedTo('admin_forum'); |
||
| 857 | validateToken('admin-tre', 'request'); |
||
| 858 | |||
| 859 | // The theme's ID must be an string. |
||
| 860 | $themeID = isset($_GET['th']) ? (string) trim($_GET['th']) : (string) trim($_GET['id']); |
||
| 861 | |||
| 862 | // Get the current list. |
||
| 863 | $enableThemes = explode(',', $modSettings['enableThemes']); |
||
| 864 | |||
| 865 | // Are we disabling it? |
||
| 866 | if (isset($_GET['disabled'])) |
||
| 867 | $enableThemes = array_diff($enableThemes, array($themeID)); |
||
| 868 | |||
| 869 | // Nope? then enable it! |
||
| 870 | else |
||
| 871 | $enableThemes[] = (string) $themeID; |
||
| 872 | |||
| 873 | // Update the setting. |
||
| 874 | $enableThemes = strtr(implode(',', $enableThemes), array(',,' => ',')); |
||
| 875 | updateSettings(array('enableThemes' => $enableThemes)); |
||
| 876 | |||
| 877 | // Done! |
||
| 878 | redirectexit('action=admin;area=theme;sa=list;' . $context['session_var'] . '=' . $context['session_id'] . ';done=' . (isset($_GET['disabled']) ? 'disabling' : 'enabling')); |
||
| 879 | } |
||
| 880 | |||
| 881 | /** |
||
| 882 | * Choose a theme from a list. |
||
| 883 | * allows an user or administrator to pick a new theme with an interface. |
||
| 884 | * - can edit everyone's (u = 0), guests' (u = -1), or a specific user's. |
||
| 885 | * - uses the Themes template. (pick sub template.) |
||
| 886 | * - accessed with ?action=admin;area=theme;sa=pick. |
||
| 887 | * @todo thought so... Might be better to split this file in ManageThemes and Themes, |
||
| 888 | * with centralized admin permissions on ManageThemes. |
||
| 889 | */ |
||
| 890 | function PickTheme() |
||
| 891 | { |
||
| 892 | global $txt, $context, $modSettings, $user_info, $language, $smcFunc, $settings, $scripturl; |
||
| 893 | |||
| 894 | loadLanguage('Profile'); |
||
| 895 | loadTemplate('Themes'); |
||
| 896 | |||
| 897 | // Build the link tree. |
||
| 898 | $context['linktree'][] = array( |
||
| 899 | 'url' => $scripturl . '?action=theme;sa=pick;u=' . (!empty($_REQUEST['u']) ? (int) $_REQUEST['u'] : 0), |
||
| 900 | 'name' => $txt['theme_pick'], |
||
| 901 | ); |
||
| 902 | $context['default_theme_id'] = $modSettings['theme_default']; |
||
| 903 | |||
| 904 | $_SESSION['id_theme'] = 0; |
||
| 905 | |||
| 906 | if (isset($_GET['id'])) |
||
| 907 | $_GET['th'] = $_GET['id']; |
||
| 908 | |||
| 909 | // Saving a variant cause JS doesn't work - pretend it did ;) |
||
| 910 | if (isset($_POST['save'])) |
||
| 911 | { |
||
| 912 | // Which theme? |
||
| 913 | foreach ($_POST['save'] as $k => $v) |
||
| 914 | $_GET['th'] = (int) $k; |
||
| 915 | |||
| 916 | if (isset($_POST['vrt'][$k])) |
||
| 917 | $_GET['vrt'] = $_POST['vrt'][$k]; |
||
|
0 ignored issues
–
show
|
|||
| 918 | } |
||
| 919 | |||
| 920 | // Have we made a decision, or are we just browsing? |
||
| 921 | if (isset($_GET['th'])) |
||
| 922 | { |
||
| 923 | checkSession('get'); |
||
| 924 | |||
| 925 | $_GET['th'] = (int) $_GET['th']; |
||
| 926 | |||
| 927 | // Save for this user. |
||
| 928 | if (!isset($_REQUEST['u']) || !allowedTo('admin_forum')) |
||
| 929 | { |
||
| 930 | updateMemberData($user_info['id'], array('id_theme' => (int) $_GET['th'])); |
||
| 931 | |||
| 932 | // A variants to save for the user? |
||
| 933 | if (!empty($_GET['vrt'])) |
||
| 934 | { |
||
| 935 | $smcFunc['db_insert']('replace', |
||
| 936 | '{db_prefix}themes', |
||
| 937 | array('id_theme' => 'int', 'id_member' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), |
||
| 938 | array($_GET['th'], $user_info['id'], 'theme_variant', $_GET['vrt']), |
||
| 939 | array('id_theme', 'id_member', 'variable') |
||
| 940 | ); |
||
| 941 | cache_put_data('theme_settings-' . $_GET['th'] . ':' . $user_info['id'], null, 90); |
||
| 942 | |||
| 943 | $_SESSION['id_variant'] = 0; |
||
| 944 | } |
||
| 945 | |||
| 946 | redirectexit('action=profile;area=theme'); |
||
| 947 | } |
||
| 948 | |||
| 949 | // If changing members or guests - and there's a variant - assume changing default variant. |
||
| 950 | if (!empty($_GET['vrt']) && ($_REQUEST['u'] == '0' || $_REQUEST['u'] == '-1')) |
||
| 951 | { |
||
| 952 | $smcFunc['db_insert']('replace', |
||
| 953 | '{db_prefix}themes', |
||
| 954 | array('id_theme' => 'int', 'id_member' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), |
||
| 955 | array($_GET['th'], 0, 'default_variant', $_GET['vrt']), |
||
| 956 | array('id_theme', 'id_member', 'variable') |
||
| 957 | ); |
||
| 958 | |||
| 959 | // Make it obvious that it's changed |
||
| 960 | cache_put_data('theme_settings-' . $_GET['th'], null, 90); |
||
| 961 | } |
||
| 962 | |||
| 963 | // For everyone. |
||
| 964 | if ($_REQUEST['u'] == '0') |
||
| 965 | { |
||
| 966 | updateMemberData(null, array('id_theme' => (int) $_GET['th'])); |
||
| 967 | |||
| 968 | // Remove any custom variants. |
||
| 969 | if (!empty($_GET['vrt'])) |
||
| 970 | { |
||
| 971 | $smcFunc['db_query']('', ' |
||
| 972 | DELETE FROM {db_prefix}themes |
||
| 973 | WHERE id_theme = {int:current_theme} |
||
| 974 | AND variable = {string:theme_variant}', |
||
| 975 | array( |
||
| 976 | 'current_theme' => (int) $_GET['th'], |
||
| 977 | 'theme_variant' => 'theme_variant', |
||
| 978 | ) |
||
| 979 | ); |
||
| 980 | } |
||
| 981 | |||
| 982 | redirectexit('action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id']); |
||
| 983 | } |
||
| 984 | // Change the default/guest theme. |
||
| 985 | elseif ($_REQUEST['u'] == '-1') |
||
| 986 | { |
||
| 987 | updateSettings(array('theme_guests' => (int) $_GET['th'])); |
||
| 988 | |||
| 989 | redirectexit('action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id']); |
||
| 990 | } |
||
| 991 | // Change a specific member's theme. |
||
| 992 | else |
||
| 993 | { |
||
| 994 | // The forum's default theme is always 0 and we |
||
| 995 | if (isset($_GET['th']) && $_GET['th'] == 0) |
||
| 996 | $_GET['th'] = $modSettings['theme_guests']; |
||
| 997 | |||
| 998 | updateMemberData((int) $_REQUEST['u'], array('id_theme' => (int) $_GET['th'])); |
||
| 999 | |||
| 1000 | if (!empty($_GET['vrt'])) |
||
| 1001 | { |
||
| 1002 | $smcFunc['db_insert']('replace', |
||
| 1003 | '{db_prefix}themes', |
||
| 1004 | array('id_theme' => 'int', 'id_member' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), |
||
| 1005 | array($_GET['th'], (int) $_REQUEST['u'], 'theme_variant', $_GET['vrt']), |
||
| 1006 | array('id_theme', 'id_member', 'variable') |
||
| 1007 | ); |
||
| 1008 | cache_put_data('theme_settings-' . $_GET['th'] . ':' . (int) $_REQUEST['u'], null, 90); |
||
| 1009 | |||
| 1010 | if ($user_info['id'] == $_REQUEST['u']) |
||
| 1011 | $_SESSION['id_variant'] = 0; |
||
| 1012 | } |
||
| 1013 | |||
| 1014 | redirectexit('action=profile;u=' . (int) $_REQUEST['u'] . ';area=theme'); |
||
| 1015 | } |
||
| 1016 | } |
||
| 1017 | |||
| 1018 | // Figure out who the member of the minute is, and what theme they've chosen. |
||
| 1019 | if (!isset($_REQUEST['u']) || !allowedTo('admin_forum')) |
||
| 1020 | { |
||
| 1021 | $context['current_member'] = $user_info['id']; |
||
| 1022 | $context['current_theme'] = $user_info['theme']; |
||
| 1023 | } |
||
| 1024 | // Everyone can't chose just one. |
||
| 1025 | elseif ($_REQUEST['u'] == '0') |
||
| 1026 | { |
||
| 1027 | $context['current_member'] = 0; |
||
| 1028 | $context['current_theme'] = 0; |
||
| 1029 | } |
||
| 1030 | // Guests and such... |
||
| 1031 | elseif ($_REQUEST['u'] == '-1') |
||
| 1032 | { |
||
| 1033 | $context['current_member'] = -1; |
||
| 1034 | $context['current_theme'] = $modSettings['theme_guests']; |
||
| 1035 | } |
||
| 1036 | // Someones else :P. |
||
| 1037 | View Code Duplication | else |
|
| 1038 | { |
||
| 1039 | $context['current_member'] = (int) $_REQUEST['u']; |
||
| 1040 | |||
| 1041 | $request = $smcFunc['db_query']('', ' |
||
| 1042 | SELECT id_theme |
||
| 1043 | FROM {db_prefix}members |
||
| 1044 | WHERE id_member = {int:current_member} |
||
| 1045 | LIMIT 1', |
||
| 1046 | array( |
||
| 1047 | 'current_member' => $context['current_member'], |
||
| 1048 | ) |
||
| 1049 | ); |
||
| 1050 | list ($context['current_theme']) = $smcFunc['db_fetch_row']($request); |
||
| 1051 | $smcFunc['db_free_result']($request); |
||
| 1052 | } |
||
| 1053 | |||
| 1054 | // Get the theme name and descriptions. |
||
| 1055 | $context['available_themes'] = array(); |
||
| 1056 | if (!empty($modSettings['knownThemes'])) |
||
| 1057 | { |
||
| 1058 | $request = $smcFunc['db_query']('', ' |
||
| 1059 | SELECT id_theme, variable, value |
||
| 1060 | FROM {db_prefix}themes |
||
| 1061 | WHERE variable IN ({string:name}, {string:theme_url}, {string:theme_dir}, {string:images_url}, {string:disable_user_variant})' . (!allowedTo('admin_forum') ? ' |
||
| 1062 | AND id_theme IN ({array_string:known_themes})' : '') . ' |
||
| 1063 | AND id_theme != {int:default_theme} |
||
| 1064 | AND id_member = {int:no_member} |
||
| 1065 | AND id_theme IN ({array_string:enable_themes})', |
||
| 1066 | array( |
||
| 1067 | 'default_theme' => 0, |
||
| 1068 | 'name' => 'name', |
||
| 1069 | 'no_member' => 0, |
||
| 1070 | 'theme_url' => 'theme_url', |
||
| 1071 | 'theme_dir' => 'theme_dir', |
||
| 1072 | 'images_url' => 'images_url', |
||
| 1073 | 'disable_user_variant' => 'disable_user_variant', |
||
| 1074 | 'known_themes' => explode(',', $modSettings['knownThemes']), |
||
| 1075 | 'enable_themes' => explode(',', $modSettings['enableThemes']), |
||
| 1076 | ) |
||
| 1077 | ); |
||
| 1078 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1079 | { |
||
| 1080 | if (!isset($context['available_themes'][$row['id_theme']])) |
||
| 1081 | $context['available_themes'][$row['id_theme']] = array( |
||
| 1082 | 'id' => $row['id_theme'], |
||
| 1083 | 'selected' => $context['current_theme'] == $row['id_theme'], |
||
| 1084 | 'num_users' => 0 |
||
| 1085 | ); |
||
| 1086 | $context['available_themes'][$row['id_theme']][$row['variable']] = $row['value']; |
||
| 1087 | } |
||
| 1088 | $smcFunc['db_free_result']($request); |
||
| 1089 | } |
||
| 1090 | |||
| 1091 | // Okay, this is a complicated problem: the default theme is 1, but they aren't allowed to access 1! |
||
| 1092 | if (!isset($context['available_themes'][$modSettings['theme_guests']])) |
||
| 1093 | { |
||
| 1094 | $context['available_themes'][0] = array( |
||
| 1095 | 'num_users' => 0 |
||
| 1096 | ); |
||
| 1097 | $guest_theme = 0; |
||
| 1098 | } |
||
| 1099 | else |
||
| 1100 | $guest_theme = $modSettings['theme_guests']; |
||
| 1101 | |||
| 1102 | $request = $smcFunc['db_query']('', ' |
||
| 1103 | SELECT id_theme, COUNT(*) AS the_count |
||
| 1104 | FROM {db_prefix}members |
||
| 1105 | GROUP BY id_theme |
||
| 1106 | ORDER BY id_theme DESC', |
||
| 1107 | array( |
||
| 1108 | ) |
||
| 1109 | ); |
||
| 1110 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1111 | { |
||
| 1112 | // Figure out which theme it is they are REALLY using. |
||
| 1113 | if (!empty($modSettings['knownThemes']) && !in_array($row['id_theme'], explode(',', $modSettings['knownThemes']))) |
||
| 1114 | $row['id_theme'] = $guest_theme; |
||
| 1115 | elseif (empty($modSettings['theme_allow'])) |
||
| 1116 | $row['id_theme'] = $guest_theme; |
||
| 1117 | |||
| 1118 | if (isset($context['available_themes'][$row['id_theme']])) |
||
| 1119 | $context['available_themes'][$row['id_theme']]['num_users'] += $row['the_count']; |
||
| 1120 | else |
||
| 1121 | $context['available_themes'][$guest_theme]['num_users'] += $row['the_count']; |
||
| 1122 | } |
||
| 1123 | $smcFunc['db_free_result']($request); |
||
| 1124 | |||
| 1125 | // Get any member variant preferences. |
||
| 1126 | $variant_preferences = array(); |
||
| 1127 | if ($context['current_member'] > 0) |
||
| 1128 | { |
||
| 1129 | $request = $smcFunc['db_query']('', ' |
||
| 1130 | SELECT id_theme, value |
||
| 1131 | FROM {db_prefix}themes |
||
| 1132 | WHERE variable = {string:theme_variant} |
||
| 1133 | AND id_member IN ({array_int:id_member}) |
||
| 1134 | ORDER BY id_member ASC', |
||
| 1135 | array( |
||
| 1136 | 'theme_variant' => 'theme_variant', |
||
| 1137 | 'id_member' => isset($_REQUEST['sa']) && $_REQUEST['sa'] == 'pick' ? array(-1, $context['current_member']) : array(-1), |
||
| 1138 | ) |
||
| 1139 | ); |
||
| 1140 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1141 | $variant_preferences[$row['id_theme']] = $row['value']; |
||
| 1142 | $smcFunc['db_free_result']($request); |
||
| 1143 | } |
||
| 1144 | |||
| 1145 | // Save the setting first. |
||
| 1146 | $current_images_url = $settings['images_url']; |
||
| 1147 | $current_theme_variants = !empty($settings['theme_variants']) ? $settings['theme_variants'] : array(); |
||
| 1148 | |||
| 1149 | foreach ($context['available_themes'] as $id_theme => $theme_data) |
||
| 1150 | { |
||
| 1151 | // Don't try to load the forum or board default theme's data... it doesn't have any! |
||
| 1152 | if ($id_theme == 0) |
||
| 1153 | continue; |
||
| 1154 | |||
| 1155 | // The thumbnail needs the correct path. |
||
| 1156 | $settings['images_url'] = &$theme_data['images_url']; |
||
| 1157 | |||
| 1158 | if (file_exists($theme_data['theme_dir'] . '/languages/Settings.' . $user_info['language'] . '.php')) |
||
| 1159 | include($theme_data['theme_dir'] . '/languages/Settings.' . $user_info['language'] . '.php'); |
||
| 1160 | elseif (file_exists($theme_data['theme_dir'] . '/languages/Settings.' . $language . '.php')) |
||
| 1161 | include($theme_data['theme_dir'] . '/languages/Settings.' . $language . '.php'); |
||
| 1162 | else |
||
| 1163 | { |
||
| 1164 | $txt['theme_thumbnail_href'] = $theme_data['images_url'] . '/thumbnail.png'; |
||
| 1165 | $txt['theme_description'] = ''; |
||
| 1166 | } |
||
| 1167 | |||
| 1168 | $context['available_themes'][$id_theme]['thumbnail_href'] = $txt['theme_thumbnail_href']; |
||
| 1169 | $context['available_themes'][$id_theme]['description'] = $txt['theme_description']; |
||
| 1170 | |||
| 1171 | // Are there any variants? |
||
| 1172 | if (file_exists($theme_data['theme_dir'] . '/index.template.php') && (empty($theme_data['disable_user_variant']) || allowedTo('admin_forum'))) |
||
| 1173 | { |
||
| 1174 | $file_contents = implode('', file($theme_data['theme_dir'] . '/index.template.php')); |
||
| 1175 | if (preg_match('~\$settings\[\'theme_variants\'\]\s*=(.+?);~', $file_contents, $matches)) |
||
| 1176 | { |
||
| 1177 | $settings['theme_variants'] = array(); |
||
| 1178 | |||
| 1179 | // Fill settings up. |
||
| 1180 | eval('global $settings;' . $matches[0]); |
||
| 1181 | |||
| 1182 | if (!empty($settings['theme_variants'])) |
||
| 1183 | { |
||
| 1184 | loadLanguage('Settings'); |
||
| 1185 | |||
| 1186 | $context['available_themes'][$id_theme]['variants'] = array(); |
||
| 1187 | View Code Duplication | foreach ($settings['theme_variants'] as $variant) |
|
| 1188 | $context['available_themes'][$id_theme]['variants'][$variant] = array( |
||
| 1189 | 'label' => isset($txt['variant_' . $variant]) ? $txt['variant_' . $variant] : $variant, |
||
| 1190 | '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'), |
||
| 1191 | ); |
||
| 1192 | |||
| 1193 | $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])); |
||
| 1194 | if (!isset($context['available_themes'][$id_theme]['variants'][$context['available_themes'][$id_theme]['selected_variant']]['thumbnail'])) |
||
| 1195 | $context['available_themes'][$id_theme]['selected_variant'] = $settings['theme_variants'][0]; |
||
| 1196 | |||
| 1197 | $context['available_themes'][$id_theme]['thumbnail_href'] = $context['available_themes'][$id_theme]['variants'][$context['available_themes'][$id_theme]['selected_variant']]['thumbnail']; |
||
| 1198 | // Allow themes to override the text. |
||
| 1199 | $context['available_themes'][$id_theme]['pick_label'] = isset($txt['variant_pick']) ? $txt['variant_pick'] : $txt['theme_pick_variant']; |
||
| 1200 | } |
||
| 1201 | } |
||
| 1202 | } |
||
| 1203 | } |
||
| 1204 | // Then return it. |
||
| 1205 | $settings['images_url'] = $current_images_url; |
||
| 1206 | $settings['theme_variants'] = $current_theme_variants; |
||
| 1207 | |||
| 1208 | // As long as we're not doing the default theme... |
||
| 1209 | if (!isset($_REQUEST['u']) || $_REQUEST['u'] >= 0) |
||
| 1210 | { |
||
| 1211 | if ($guest_theme != 0) |
||
| 1212 | $context['available_themes'][0] = $context['available_themes'][$guest_theme]; |
||
| 1213 | |||
| 1214 | $context['available_themes'][0]['id'] = 0; |
||
| 1215 | $context['available_themes'][0]['name'] = $txt['theme_forum_default']; |
||
| 1216 | $context['available_themes'][0]['selected'] = $context['current_theme'] == 0; |
||
| 1217 | $context['available_themes'][0]['description'] = $txt['theme_global_description']; |
||
| 1218 | } |
||
| 1219 | |||
| 1220 | ksort($context['available_themes']); |
||
| 1221 | |||
| 1222 | $context['page_title'] = $txt['theme_pick']; |
||
| 1223 | $context['sub_template'] = 'pick'; |
||
| 1224 | } |
||
| 1225 | |||
| 1226 | /** |
||
| 1227 | * Installs new themes, calls the respective function according to the install type. |
||
| 1228 | * - puts themes in $boardurl/Themes. |
||
| 1229 | * - assumes the gzip has a root directory in it. (ie default.) |
||
| 1230 | * Requires admin_forum. |
||
| 1231 | * Accessed with ?action=admin;area=theme;sa=install. |
||
| 1232 | */ |
||
| 1233 | function ThemeInstall() |
||
| 1234 | { |
||
| 1235 | global $sourcedir, $txt, $context, $boarddir, $boardurl; |
||
| 1236 | global $themedir, $themeurl, $smcFunc; |
||
| 1237 | |||
| 1238 | checkSession('request'); |
||
| 1239 | isAllowedTo('admin_forum'); |
||
| 1240 | |||
| 1241 | require_once($sourcedir . '/Subs-Package.php'); |
||
| 1242 | |||
| 1243 | // Make it easier to change the path and url. |
||
| 1244 | $themedir = $boarddir . '/Themes'; |
||
| 1245 | $themeurl = $boardurl . '/Themes'; |
||
| 1246 | |||
| 1247 | loadTemplate('Themes'); |
||
| 1248 | |||
| 1249 | $subActions = array( |
||
| 1250 | 'file' => 'InstallFile', |
||
| 1251 | 'copy' => 'InstallCopy', |
||
| 1252 | 'dir' => 'InstallDir', |
||
| 1253 | ); |
||
| 1254 | |||
| 1255 | // Is there a function to call? |
||
| 1256 | if (isset($_GET['do']) && !empty($_GET['do']) && isset($subActions[$_GET['do']])) |
||
| 1257 | { |
||
| 1258 | $action = $smcFunc['htmlspecialchars'](trim($_GET['do'])); |
||
| 1259 | |||
| 1260 | // Got any info from the specific form? |
||
| 1261 | if (!isset($_POST['save_' . $action])) |
||
| 1262 | fatal_lang_error('theme_install_no_action', false); |
||
| 1263 | |||
| 1264 | validateToken('admin-t-' . $action); |
||
| 1265 | |||
| 1266 | // Hopefully the themes directory is writable, or we might have a problem. |
||
| 1267 | if (!is_writable($themedir)) |
||
| 1268 | fatal_lang_error('theme_install_write_error', 'critical'); |
||
| 1269 | |||
| 1270 | // Call the function and handle the result. |
||
| 1271 | $result = $subActions[$action](); |
||
| 1272 | |||
| 1273 | // Everything went better than expected! |
||
| 1274 | if (!empty($result)) |
||
| 1275 | { |
||
| 1276 | $context['sub_template'] = 'installed'; |
||
| 1277 | $context['page_title'] = $txt['theme_installed']; |
||
| 1278 | $context['installed_theme'] = $result; |
||
| 1279 | } |
||
| 1280 | } |
||
| 1281 | |||
| 1282 | // Nope, show a nice error. |
||
| 1283 | else |
||
| 1284 | fatal_lang_error('theme_install_no_action', false); |
||
| 1285 | } |
||
| 1286 | |||
| 1287 | /** |
||
| 1288 | * Installs a theme from a theme package. |
||
| 1289 | * |
||
| 1290 | * 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. |
||
| 1291 | * @return array The newly created theme's info. |
||
| 1292 | */ |
||
| 1293 | function InstallFile() |
||
| 1294 | { |
||
| 1295 | global $themedir, $themeurl, $context; |
||
| 1296 | |||
| 1297 | // Set a temp dir for dumping all required files on it. |
||
| 1298 | $dirtemp = $themedir . '/temp'; |
||
| 1299 | |||
| 1300 | // Make sure the temp dir doesn't already exist |
||
| 1301 | if (file_exists($dirtemp)) |
||
| 1302 | remove_dir($dirtemp); |
||
| 1303 | |||
| 1304 | // Create the temp dir. |
||
| 1305 | mkdir($dirtemp, 0777); |
||
| 1306 | |||
| 1307 | // Hopefully the temp directory is writable, or we might have a problem. |
||
| 1308 | if (!is_writable($dirtemp)) |
||
| 1309 | { |
||
| 1310 | // Lets give it a try. |
||
| 1311 | smf_chmod($dirtemp, '0755'); |
||
| 1312 | |||
| 1313 | // How about now? |
||
| 1314 | if (!is_writable($dirtemp)) |
||
| 1315 | fatal_lang_error('theme_install_write_error', 'critical'); |
||
| 1316 | } |
||
| 1317 | |||
| 1318 | // This happens when the admin session is gone and the user has to login again. |
||
| 1319 | if (!isset($_FILES) || !isset($_FILES['theme_gz']) || empty($_FILES['theme_gz'])) |
||
| 1320 | redirectexit('action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id']); |
||
| 1321 | |||
| 1322 | // Another error check layer, something went wrong with the upload. |
||
| 1323 | if (isset($_FILES['theme_gz']['error']) && $_FILES['theme_gz']['error'] != 0) |
||
| 1324 | fatal_lang_error('theme_install_error_file_' . $_FILES['theme_gz']['error'], false); |
||
| 1325 | |||
| 1326 | // Get the theme's name. |
||
| 1327 | $name = pathinfo($_FILES['theme_gz']['name'], PATHINFO_FILENAME); |
||
| 1328 | $name = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $name); |
||
| 1329 | |||
| 1330 | // Start setting some vars. |
||
| 1331 | $context['to_install'] = array( |
||
| 1332 | 'theme_dir' => $themedir . '/' . $name, |
||
| 1333 | 'theme_url' => $themeurl . '/' . $name, |
||
| 1334 | 'images_url' => $themeurl . '/' . $name . '/images', |
||
| 1335 | 'name' => $name, |
||
| 1336 | ); |
||
| 1337 | |||
| 1338 | // Extract the file on the proper themes dir. |
||
| 1339 | $extracted = read_tgz_file($_FILES['theme_gz']['tmp_name'], $dirtemp, false, true); |
||
| 1340 | |||
| 1341 | if ($extracted) |
||
| 1342 | { |
||
| 1343 | // Read its info form the XML file. |
||
| 1344 | $theme_info = get_theme_info($dirtemp); |
||
| 1345 | $context['to_install'] += $theme_info; |
||
| 1346 | |||
| 1347 | // Install the theme. theme_install() will return the new installed ID. |
||
| 1348 | $context['to_install']['id'] = theme_install($context['to_install']); |
||
| 1349 | |||
| 1350 | // Rename the temp dir to the actual theme name. |
||
| 1351 | rename($dirtemp, $context['to_install']['theme_dir']); |
||
| 1352 | |||
| 1353 | // return all the info. |
||
| 1354 | return $context['to_install']; |
||
| 1355 | } |
||
| 1356 | |||
| 1357 | else |
||
| 1358 | fatal_lang_error('theme_install_error_title', false); |
||
| 1359 | } |
||
| 1360 | |||
| 1361 | /** |
||
| 1362 | * Makes a copy from the default theme, assigns a name for it and installs it. |
||
| 1363 | * |
||
| 1364 | * Creates a new .xml file containing all the theme's info. |
||
| 1365 | * @return array The newly created theme's info. |
||
| 1366 | */ |
||
| 1367 | function InstallCopy() |
||
| 1368 | { |
||
| 1369 | global $themedir, $themeurl, $settings, $smcFunc, $context; |
||
| 1370 | global $forum_version; |
||
| 1371 | |||
| 1372 | // There's gotta be something to work with. |
||
| 1373 | if (!isset($_REQUEST['copy']) || empty($_REQUEST['copy'])) |
||
| 1374 | fatal_lang_error('theme_install_error_title', false); |
||
| 1375 | |||
| 1376 | // Get a cleaner version. |
||
| 1377 | $name = preg_replace('~[^A-Za-z0-9_\- ]~', '', $_REQUEST['copy']); |
||
| 1378 | |||
| 1379 | // Is there a theme already named like this? |
||
| 1380 | if (file_exists($themedir . '/' . $name)) |
||
| 1381 | fatal_lang_error('theme_install_already_dir', false); |
||
| 1382 | |||
| 1383 | // This is a brand new theme so set all possible values. |
||
| 1384 | $context['to_install'] = array( |
||
| 1385 | 'theme_dir' => $themedir . '/' . $name, |
||
| 1386 | 'theme_url' => $themeurl . '/' . $name, |
||
| 1387 | 'name' => $name, |
||
| 1388 | 'images_url' => $themeurl . '/' . $name . '/images', |
||
| 1389 | 'version' => '1.0', |
||
| 1390 | 'install_for' => '2.1 - 2.1.99, ' . strtr($forum_version, array('SMF ' => '')), |
||
| 1391 | 'based_on' => '', |
||
| 1392 | 'based_on_dir' => $themedir . '/default', |
||
| 1393 | ); |
||
| 1394 | |||
| 1395 | // Create the specific dir. |
||
| 1396 | umask(0); |
||
| 1397 | mkdir($context['to_install']['theme_dir'], 0777); |
||
| 1398 | |||
| 1399 | // Buy some time. |
||
| 1400 | @set_time_limit(600); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 1401 | if (function_exists('apache_reset_timeout')) |
||
| 1402 | @apache_reset_timeout(); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 1403 | |||
| 1404 | // Create subdirectories for css and javascript files. |
||
| 1405 | mkdir($context['to_install']['theme_dir'] . '/css', 0777); |
||
| 1406 | mkdir($context['to_install']['theme_dir'] . '/scripts', 0777); |
||
| 1407 | |||
| 1408 | // Copy over the default non-theme files. |
||
| 1409 | $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'); |
||
| 1410 | |||
| 1411 | foreach ($to_copy as $file) |
||
| 1412 | { |
||
| 1413 | copy($settings['default_theme_dir'] . $file, $context['to_install']['theme_dir'] . $file); |
||
| 1414 | smf_chmod($context['to_install']['theme_dir'] . $file, 0777); |
||
| 1415 | } |
||
| 1416 | |||
| 1417 | // And now the entire images directory! |
||
| 1418 | copytree($settings['default_theme_dir'] . '/images', $context['to_install']['theme_dir'] . '/images'); |
||
| 1419 | package_flush_cache(); |
||
| 1420 | |||
| 1421 | // Lets get some data for the new theme. |
||
| 1422 | $request = $smcFunc['db_query']('', ' |
||
| 1423 | SELECT variable, value |
||
| 1424 | FROM {db_prefix}themes |
||
| 1425 | WHERE variable IN ({string:theme_templates}, {string:theme_layers}) |
||
| 1426 | AND id_member = {int:no_member} |
||
| 1427 | AND id_theme = {int:default_theme}', |
||
| 1428 | array( |
||
| 1429 | 'no_member' => 0, |
||
| 1430 | 'default_theme' => 1, |
||
| 1431 | 'theme_templates' => 'theme_templates', |
||
| 1432 | 'theme_layers' => 'theme_layers', |
||
| 1433 | ) |
||
| 1434 | ); |
||
| 1435 | |||
| 1436 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1437 | { |
||
| 1438 | if ($row['variable'] == 'theme_templates') |
||
| 1439 | $theme_templates = $row['value']; |
||
| 1440 | elseif ($row['variable'] == 'theme_layers') |
||
| 1441 | $theme_layers = $row['value']; |
||
| 1442 | else |
||
| 1443 | continue; |
||
| 1444 | } |
||
| 1445 | |||
| 1446 | $smcFunc['db_free_result']($request); |
||
| 1447 | |||
| 1448 | $context['to_install'] += array( |
||
| 1449 | 'theme_layers' => empty($theme_layers) ? 'html,body' : $theme_layers, |
||
| 1450 | 'theme_templates' => empty($theme_templates) ? 'index' : $theme_templates, |
||
| 1451 | ); |
||
| 1452 | |||
| 1453 | // Lets add a theme_info.xml to this theme. |
||
| 1454 | $xml_info = '<' . '?xml version="1.0"?' . '> |
||
| 1455 | <theme-info xmlns="http://www.simplemachines.org/xml/theme-info" xmlns:smf="http://www.simplemachines.org/"> |
||
| 1456 | <!-- For the id, always use something unique - put your name, a colon, and then the package name. --> |
||
| 1457 | <id>smf:' . $smcFunc['strtolower']($context['to_install']['name']) . '</id> |
||
| 1458 | <!-- The theme\'s version, please try to use semantic versioning. --> |
||
| 1459 | <version>1.0</version> |
||
| 1460 | <!-- Install for, the SMF versions this theme was designed for. Uses the same wildcards used in the packager manager. This field is mandatory. --> |
||
| 1461 | <install for="'. $context['to_install']['install_for'] . '" /> |
||
| 1462 | <!-- Theme name, used purely for aesthetics. --> |
||
| 1463 | <name>' . $context['to_install']['name'] . '</name> |
||
| 1464 | <!-- Author: your email address or contact information. The name attribute is optional. --> |
||
| 1465 | <author name="Simple Machines">[email protected]</author> |
||
| 1466 | <!-- Website... where to get updates and more information. --> |
||
| 1467 | <website>https://www.simplemachines.org/</website> |
||
| 1468 | <!-- Template layers to use, defaults to "html,body". --> |
||
| 1469 | <layers>' . $context['to_install']['theme_layers'] . '</layers> |
||
| 1470 | <!-- Templates to load on startup. Default is "index". --> |
||
| 1471 | <templates>' . $context['to_install']['theme_templates'] . '</templates> |
||
| 1472 | <!-- Base this theme off another? Default is blank, or no. It could be "default". --> |
||
| 1473 | <based-on></based-on> |
||
| 1474 | </theme-info>'; |
||
| 1475 | |||
| 1476 | // Now write it. |
||
| 1477 | $fp = @fopen($context['to_install']['theme_dir'] . '/theme_info.xml', 'w+'); |
||
| 1478 | if ($fp) |
||
| 1479 | { |
||
| 1480 | fwrite($fp, $xml_info); |
||
| 1481 | fclose($fp); |
||
| 1482 | } |
||
| 1483 | |||
| 1484 | // Install the theme. theme_install() will take care of possible errors. |
||
| 1485 | $context['to_install']['id'] = theme_install($context['to_install']); |
||
| 1486 | |||
| 1487 | // return the info. |
||
| 1488 | return $context['to_install']; |
||
| 1489 | } |
||
| 1490 | |||
| 1491 | /** |
||
| 1492 | * Install a theme from a specific dir |
||
| 1493 | * |
||
| 1494 | * Assumes the dir is located on the main Themes dir. Ends execution with fatal_lang_error() on any error. |
||
| 1495 | * @return array The newly created theme's info. |
||
| 1496 | */ |
||
| 1497 | function InstallDir() |
||
| 1498 | { |
||
| 1499 | global $themedir, $themeurl, $context; |
||
| 1500 | |||
| 1501 | // Cannot use the theme dir as a theme dir. |
||
| 1502 | if (!isset($_REQUEST['theme_dir']) || empty($_REQUEST['theme_dir']) || rtrim(realpath($_REQUEST['theme_dir']), '/\\') == realpath($themedir)) |
||
| 1503 | fatal_lang_error('theme_install_invalid_dir', false); |
||
| 1504 | |||
| 1505 | // Check is there is "something" on the dir. |
||
| 1506 | View Code Duplication | elseif (!is_dir($_REQUEST['theme_dir']) || !file_exists($_REQUEST['theme_dir'] . '/theme_info.xml')) |
|
| 1507 | fatal_lang_error('theme_install_error', false); |
||
| 1508 | |||
| 1509 | $name = basename($_REQUEST['theme_dir']); |
||
| 1510 | $name = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $name); |
||
| 1511 | |||
| 1512 | // All good! set some needed vars. |
||
| 1513 | $context['to_install'] = array( |
||
| 1514 | 'theme_dir' => $_REQUEST['theme_dir'], |
||
| 1515 | 'theme_url' => $themeurl . '/' . $name, |
||
| 1516 | 'name' => $name, |
||
| 1517 | 'images_url' => $themeurl . '/' . $name . '/images', |
||
| 1518 | ); |
||
| 1519 | |||
| 1520 | // Read its info form the XML file. |
||
| 1521 | $theme_info = get_theme_info($context['to_install']['theme_dir']); |
||
| 1522 | $context['to_install'] += $theme_info; |
||
| 1523 | |||
| 1524 | // Install the theme. theme_install() will take care of possible errors. |
||
| 1525 | $context['to_install']['id'] = theme_install($context['to_install']); |
||
| 1526 | |||
| 1527 | // return the info. |
||
| 1528 | return $context['to_install']; |
||
| 1529 | } |
||
| 1530 | |||
| 1531 | /** |
||
| 1532 | * Possibly the simplest and best example of how to use the template system. |
||
| 1533 | * - allows the theme to take care of actions. |
||
| 1534 | * - happens if $settings['catch_action'] is set and action isn't found |
||
| 1535 | * in the action array. |
||
| 1536 | * - can use a template, layers, sub_template, filename, and/or function. |
||
| 1537 | */ |
||
| 1538 | function WrapAction() |
||
| 1539 | { |
||
| 1540 | global $context, $settings; |
||
| 1541 | |||
| 1542 | // Load any necessary template(s)? |
||
| 1543 | if (isset($settings['catch_action']['template'])) |
||
| 1544 | { |
||
| 1545 | // Load both the template and language file. (but don't fret if the language file isn't there...) |
||
| 1546 | loadTemplate($settings['catch_action']['template']); |
||
| 1547 | loadLanguage($settings['catch_action']['template'], '', false); |
||
| 1548 | } |
||
| 1549 | |||
| 1550 | // Any special layers? |
||
| 1551 | if (isset($settings['catch_action']['layers'])) |
||
| 1552 | $context['template_layers'] = $settings['catch_action']['layers']; |
||
| 1553 | |||
| 1554 | // Any function to call? |
||
| 1555 | if (isset($settings['catch_action']['function'])) |
||
| 1556 | { |
||
| 1557 | $hook = $settings['catch_action']['function']; |
||
| 1558 | |||
| 1559 | if (!isset($settings['catch_action']['filename'])) |
||
| 1560 | $settings['catch_action']['filename'] = ''; |
||
| 1561 | |||
| 1562 | add_integration_function('integrate_wrap_action', $hook, false, $settings['catch_action']['filename'], false); |
||
| 1563 | call_integration_hook('integrate_wrap_action'); |
||
| 1564 | } |
||
| 1565 | // And finally, the main sub template ;). |
||
| 1566 | if (isset($settings['catch_action']['sub_template'])) |
||
| 1567 | $context['sub_template'] = $settings['catch_action']['sub_template']; |
||
| 1568 | } |
||
| 1569 | |||
| 1570 | /** |
||
| 1571 | * Set an option via javascript. |
||
| 1572 | * - sets a theme option without outputting anything. |
||
| 1573 | * - can be used with javascript, via a dummy image... (which doesn't require |
||
| 1574 | * the page to reload.) |
||
| 1575 | * - requires someone who is logged in. |
||
| 1576 | * - accessed via ?action=jsoption;var=variable;val=value;session_var=sess_id. |
||
| 1577 | * - does not log access to the Who's Online log. (in index.php..) |
||
| 1578 | */ |
||
| 1579 | function SetJavaScript() |
||
| 1580 | { |
||
| 1581 | global $settings, $user_info, $smcFunc, $options; |
||
| 1582 | |||
| 1583 | // Check the session id. |
||
| 1584 | checkSession('get'); |
||
| 1585 | |||
| 1586 | // This good-for-nothing pixel is being used to keep the session alive. |
||
| 1587 | if (empty($_GET['var']) || !isset($_GET['val'])) |
||
| 1588 | redirectexit($settings['images_url'] . '/blank.png'); |
||
| 1589 | |||
| 1590 | // Sorry, guests can't go any further than this. |
||
| 1591 | if ($user_info['is_guest'] || $user_info['id'] == 0) |
||
| 1592 | obExit(false); |
||
| 1593 | |||
| 1594 | $reservedVars = array( |
||
| 1595 | 'actual_theme_url', |
||
| 1596 | 'actual_images_url', |
||
| 1597 | 'base_theme_dir', |
||
| 1598 | 'base_theme_url', |
||
| 1599 | 'default_images_url', |
||
| 1600 | 'default_theme_dir', |
||
| 1601 | 'default_theme_url', |
||
| 1602 | 'default_template', |
||
| 1603 | 'images_url', |
||
| 1604 | 'number_recent_posts', |
||
| 1605 | 'smiley_sets_default', |
||
| 1606 | 'theme_dir', |
||
| 1607 | 'theme_id', |
||
| 1608 | 'theme_layers', |
||
| 1609 | 'theme_templates', |
||
| 1610 | 'theme_url', |
||
| 1611 | 'name', |
||
| 1612 | ); |
||
| 1613 | |||
| 1614 | // Can't change reserved vars. |
||
| 1615 | if (in_array(strtolower($_GET['var']), $reservedVars)) |
||
| 1616 | redirectexit($settings['images_url'] . '/blank.png'); |
||
| 1617 | |||
| 1618 | // Use a specific theme? |
||
| 1619 | if (isset($_GET['th']) || isset($_GET['id'])) |
||
| 1620 | { |
||
| 1621 | // Invalidate the current themes cache too. |
||
| 1622 | cache_put_data('theme_settings-' . $settings['theme_id'] . ':' . $user_info['id'], null, 60); |
||
| 1623 | |||
| 1624 | $settings['theme_id'] = isset($_GET['th']) ? (int) $_GET['th'] : (int) $_GET['id']; |
||
| 1625 | } |
||
| 1626 | |||
| 1627 | // If this is the admin preferences the passed value will just be an element of it. |
||
| 1628 | if ($_GET['var'] == 'admin_preferences') |
||
| 1629 | { |
||
| 1630 | $options['admin_preferences'] = !empty($options['admin_preferences']) ? $smcFunc['json_decode']($options['admin_preferences'], true) : array(); |
||
| 1631 | // New thingy... |
||
| 1632 | if (isset($_GET['admin_key']) && strlen($_GET['admin_key']) < 5) |
||
| 1633 | $options['admin_preferences'][$_GET['admin_key']] = $_GET['val']; |
||
| 1634 | |||
| 1635 | // Change the value to be something nice, |
||
| 1636 | $_GET['val'] = $smcFunc['json_encode']($options['admin_preferences']); |
||
| 1637 | } |
||
| 1638 | |||
| 1639 | // Update the option. |
||
| 1640 | $smcFunc['db_insert']('replace', |
||
| 1641 | '{db_prefix}themes', |
||
| 1642 | array('id_theme' => 'int', 'id_member' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), |
||
| 1643 | array($settings['theme_id'], $user_info['id'], $_GET['var'], is_array($_GET['val']) ? implode(',', $_GET['val']) : $_GET['val']), |
||
| 1644 | array('id_theme', 'id_member', 'variable') |
||
| 1645 | ); |
||
| 1646 | |||
| 1647 | cache_put_data('theme_settings-' . $settings['theme_id'] . ':' . $user_info['id'], null, 60); |
||
| 1648 | |||
| 1649 | // Don't output anything... |
||
| 1650 | redirectexit($settings['images_url'] . '/blank.png'); |
||
| 1651 | } |
||
| 1652 | |||
| 1653 | /** |
||
| 1654 | * Shows an interface for editing the templates. |
||
| 1655 | * - uses the Themes template and edit_template/edit_style sub template. |
||
| 1656 | * - accessed via ?action=admin;area=theme;sa=edit |
||
| 1657 | */ |
||
| 1658 | function EditTheme() |
||
| 1659 | { |
||
| 1660 | global $context, $scripturl, $boarddir, $smcFunc, $txt; |
||
| 1661 | |||
| 1662 | // @todo Should this be removed? |
||
| 1663 | if (isset($_REQUEST['preview'])) |
||
| 1664 | die('die() with fire'); |
||
| 1665 | |||
| 1666 | isAllowedTo('admin_forum'); |
||
| 1667 | loadTemplate('Themes'); |
||
| 1668 | |||
| 1669 | $_GET['th'] = isset($_GET['th']) ? (int) $_GET['th'] : (int) @$_GET['id']; |
||
| 1670 | |||
| 1671 | if (empty($_GET['th'])) |
||
| 1672 | { |
||
| 1673 | get_all_themes(); |
||
| 1674 | |||
| 1675 | foreach ($context['themes'] as $key => $theme) |
||
| 1676 | { |
||
| 1677 | // There has to be a Settings template! |
||
| 1678 | if (!file_exists($theme['theme_dir'] . '/index.template.php') && !file_exists($theme['theme_dir'] . '/css/index.css')) |
||
| 1679 | unset($context['themes'][$key]); |
||
| 1680 | |||
| 1681 | else |
||
| 1682 | $context['themes'][$key]['can_edit_style'] = file_exists($theme['theme_dir'] . '/css/index.css'); |
||
| 1683 | } |
||
| 1684 | |||
| 1685 | $context['sub_template'] = 'edit_list'; |
||
| 1686 | |||
| 1687 | return 'no_themes'; |
||
| 1688 | } |
||
| 1689 | |||
| 1690 | $context['session_error'] = false; |
||
| 1691 | |||
| 1692 | // Get the directory of the theme we are editing. |
||
| 1693 | $currentTheme = get_single_theme($_GET['th']); |
||
| 1694 | $context['theme_id'] = $currentTheme['id']; |
||
| 1695 | $context['browse_title'] = sprintf($txt['themeadmin_browsing_theme'], $currentTheme['name']); |
||
| 1696 | |||
| 1697 | View Code Duplication | if (!file_exists($currentTheme['theme_dir'] . '/index.template.php') && !file_exists($currentTheme['theme_dir'] . '/css/index.css')) |
|
| 1698 | fatal_lang_error('theme_edit_missing', false); |
||
| 1699 | |||
| 1700 | if (!isset($_REQUEST['filename'])) |
||
| 1701 | { |
||
| 1702 | View Code Duplication | if (isset($_GET['directory'])) |
|
| 1703 | { |
||
| 1704 | if (substr($_GET['directory'], 0, 1) == '.') |
||
| 1705 | $_GET['directory'] = ''; |
||
| 1706 | else |
||
| 1707 | { |
||
| 1708 | $_GET['directory'] = preg_replace(array('~^[\./\\:\0\n\r]+~', '~[\\\\]~', '~/[\./]+~'), array('', '/', '/'), $_GET['directory']); |
||
| 1709 | |||
| 1710 | $temp = realpath($currentTheme['theme_dir'] . '/' . $_GET['directory']); |
||
| 1711 | if (empty($temp) || substr($temp, 0, strlen(realpath($currentTheme['theme_dir']))) != realpath($currentTheme['theme_dir'])) |
||
| 1712 | $_GET['directory'] = ''; |
||
| 1713 | } |
||
| 1714 | } |
||
| 1715 | |||
| 1716 | if (isset($_GET['directory']) && $_GET['directory'] != '') |
||
| 1717 | { |
||
| 1718 | $context['theme_files'] = get_file_listing($currentTheme['theme_dir'] . '/' . $_GET['directory'], $_GET['directory'] . '/'); |
||
| 1719 | |||
| 1720 | $temp = dirname($_GET['directory']); |
||
| 1721 | array_unshift($context['theme_files'], array( |
||
| 1722 | 'filename' => $temp == '.' || $temp == '' ? '/ (..)' : $temp . ' (..)', |
||
| 1723 | 'is_writable' => is_writable($currentTheme['theme_dir'] . '/' . $temp), |
||
| 1724 | 'is_directory' => true, |
||
| 1725 | 'is_template' => false, |
||
| 1726 | 'is_image' => false, |
||
| 1727 | 'is_editable' => false, |
||
| 1728 | 'href' => $scripturl . '?action=admin;area=theme;th=' . $_GET['th'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=edit;directory=' . $temp, |
||
| 1729 | 'size' => '', |
||
| 1730 | )); |
||
| 1731 | } |
||
| 1732 | else |
||
| 1733 | $context['theme_files'] = get_file_listing($currentTheme['theme_dir'], ''); |
||
| 1734 | |||
| 1735 | $context['sub_template'] = 'edit_browse'; |
||
| 1736 | |||
| 1737 | return; |
||
| 1738 | } |
||
| 1739 | else |
||
| 1740 | { |
||
| 1741 | View Code Duplication | if (substr($_REQUEST['filename'], 0, 1) == '.') |
|
| 1742 | $_REQUEST['filename'] = ''; |
||
| 1743 | else |
||
| 1744 | { |
||
| 1745 | $_REQUEST['filename'] = preg_replace(array('~^[\./\\:\0\n\r]+~', '~[\\\\]~', '~/[\./]+~'), array('', '/', '/'), $_REQUEST['filename']); |
||
| 1746 | |||
| 1747 | $temp = realpath($currentTheme['theme_dir'] . '/' . $_REQUEST['filename']); |
||
| 1748 | if (empty($temp) || substr($temp, 0, strlen(realpath($currentTheme['theme_dir']))) != realpath($currentTheme['theme_dir'])) |
||
| 1749 | $_REQUEST['filename'] = ''; |
||
| 1750 | } |
||
| 1751 | |||
| 1752 | if (empty($_REQUEST['filename'])) |
||
| 1753 | fatal_lang_error('theme_edit_missing', false); |
||
| 1754 | } |
||
| 1755 | |||
| 1756 | if (isset($_POST['save'])) |
||
| 1757 | { |
||
| 1758 | if (checkSession('post', '', false) == '' && validateToken('admin-te-' . md5($_GET['th'] . '-' . $_REQUEST['filename']), 'post', false) == true) |
||
| 1759 | { |
||
| 1760 | if (is_array($_POST['entire_file'])) |
||
| 1761 | $_POST['entire_file'] = implode("\n", $_POST['entire_file']); |
||
| 1762 | |||
| 1763 | $_POST['entire_file'] = rtrim(strtr($_POST['entire_file'], array("\r" => '', ' ' => "\t"))); |
||
| 1764 | |||
| 1765 | // Check for a parse error! |
||
| 1766 | if (substr($_REQUEST['filename'], -13) == '.template.php' && is_writable($currentTheme['theme_dir']) && ini_get('display_errors')) |
||
| 1767 | { |
||
| 1768 | $fp = fopen($currentTheme['theme_dir'] . '/tmp_' . session_id() . '.php', 'w'); |
||
| 1769 | fwrite($fp, $_POST['entire_file']); |
||
| 1770 | fclose($fp); |
||
| 1771 | |||
| 1772 | $error = @file_get_contents($currentTheme['theme_url'] . '/tmp_' . session_id() . '.php'); |
||
| 1773 | if (preg_match('~ <b>(\d+)</b><br( /)?' . '>$~i', $error) != 0) |
||
| 1774 | $error_file = $currentTheme['theme_dir'] . '/tmp_' . session_id() . '.php'; |
||
| 1775 | else |
||
| 1776 | unlink($currentTheme['theme_dir'] . '/tmp_' . session_id() . '.php'); |
||
| 1777 | } |
||
| 1778 | |||
| 1779 | if (!isset($error_file)) |
||
| 1780 | { |
||
| 1781 | $fp = fopen($currentTheme['theme_dir'] . '/' . $_REQUEST['filename'], 'w'); |
||
| 1782 | fwrite($fp, $_POST['entire_file']); |
||
| 1783 | fclose($fp); |
||
| 1784 | |||
| 1785 | redirectexit('action=admin;area=theme;th=' . $_GET['th'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=edit;directory=' . dirname($_REQUEST['filename'])); |
||
| 1786 | } |
||
| 1787 | } |
||
| 1788 | // Session timed out. |
||
| 1789 | else |
||
| 1790 | { |
||
| 1791 | loadLanguage('Errors'); |
||
| 1792 | |||
| 1793 | $context['session_error'] = true; |
||
| 1794 | $context['sub_template'] = 'edit_file'; |
||
| 1795 | |||
| 1796 | // Recycle the submitted data. |
||
| 1797 | if (is_array($_POST['entire_file'])) |
||
| 1798 | $context['entire_file'] = $smcFunc['htmlspecialchars'](implode("\n", $_POST['entire_file'])); |
||
| 1799 | else |
||
| 1800 | $context['entire_file'] = $smcFunc['htmlspecialchars']($_POST['entire_file']); |
||
| 1801 | |||
| 1802 | $context['edit_filename'] = $smcFunc['htmlspecialchars']($_POST['filename']); |
||
| 1803 | |||
| 1804 | // You were able to submit it, so it's reasonable to assume you are allowed to save. |
||
| 1805 | $context['allow_save'] = true; |
||
| 1806 | |||
| 1807 | // Re-create the token so that it can be used |
||
| 1808 | createToken('admin-te-' . md5($_GET['th'] . '-' . $_REQUEST['filename'])); |
||
| 1809 | |||
| 1810 | return; |
||
| 1811 | } |
||
| 1812 | } |
||
| 1813 | |||
| 1814 | $context['allow_save'] = is_writable($currentTheme['theme_dir'] . '/' . $_REQUEST['filename']); |
||
| 1815 | $context['allow_save_filename'] = strtr($currentTheme['theme_dir'] . '/' . $_REQUEST['filename'], array($boarddir => '...')); |
||
| 1816 | $context['edit_filename'] = $smcFunc['htmlspecialchars']($_REQUEST['filename']); |
||
| 1817 | |||
| 1818 | if (substr($_REQUEST['filename'], -4) == '.css') |
||
| 1819 | { |
||
| 1820 | $context['sub_template'] = 'edit_style'; |
||
| 1821 | |||
| 1822 | $context['entire_file'] = $smcFunc['htmlspecialchars'](strtr(file_get_contents($currentTheme['theme_dir'] . '/' . $_REQUEST['filename']), array("\t" => ' '))); |
||
| 1823 | } |
||
| 1824 | elseif (substr($_REQUEST['filename'], -13) == '.template.php') |
||
| 1825 | { |
||
| 1826 | $context['sub_template'] = 'edit_template'; |
||
| 1827 | |||
| 1828 | if (!isset($error_file)) |
||
| 1829 | $file_data = file($currentTheme['theme_dir'] . '/' . $_REQUEST['filename']); |
||
| 1830 | else |
||
| 1831 | { |
||
| 1832 | if (preg_match('~(<b>.+?</b>:.+?<b>).+?(</b>.+?<b>\d+</b>)<br( /)?' . '>$~i', $error, $match) != 0) |
||
|
0 ignored issues
–
show
The variable
$error does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
| 1833 | $context['parse_error'] = $match[1] . $_REQUEST['filename'] . $match[2]; |
||
| 1834 | $file_data = file($error_file); |
||
| 1835 | unlink($error_file); |
||
| 1836 | } |
||
| 1837 | |||
| 1838 | $j = 0; |
||
| 1839 | $context['file_parts'] = array(array('lines' => 0, 'line' => 1, 'data' => '')); |
||
| 1840 | for ($i = 0, $n = count($file_data); $i < $n; $i++) |
||
| 1841 | { |
||
| 1842 | if (isset($file_data[$i + 1]) && substr($file_data[$i + 1], 0, 9) == 'function ') |
||
| 1843 | { |
||
| 1844 | // Try to format the functions a little nicer... |
||
| 1845 | $context['file_parts'][$j]['data'] = trim($context['file_parts'][$j]['data']) . "\n"; |
||
| 1846 | |||
| 1847 | if (empty($context['file_parts'][$j]['lines'])) |
||
| 1848 | unset($context['file_parts'][$j]); |
||
| 1849 | $context['file_parts'][++$j] = array('lines' => 0, 'line' => $i + 1, 'data' => ''); |
||
| 1850 | } |
||
| 1851 | |||
| 1852 | $context['file_parts'][$j]['lines']++; |
||
| 1853 | $context['file_parts'][$j]['data'] .= $smcFunc['htmlspecialchars'](strtr($file_data[$i], array("\t" => ' '))); |
||
| 1854 | } |
||
| 1855 | |||
| 1856 | $context['entire_file'] = $smcFunc['htmlspecialchars'](strtr(implode('', $file_data), array("\t" => ' '))); |
||
| 1857 | } |
||
| 1858 | else |
||
| 1859 | { |
||
| 1860 | $context['sub_template'] = 'edit_file'; |
||
| 1861 | |||
| 1862 | $context['entire_file'] = $smcFunc['htmlspecialchars'](strtr(file_get_contents($currentTheme['theme_dir'] . '/' . $_REQUEST['filename']), array("\t" => ' '))); |
||
| 1863 | } |
||
| 1864 | |||
| 1865 | // Create a special token to allow editing of multiple files. |
||
| 1866 | createToken('admin-te-' . md5($_GET['th'] . '-' . $_REQUEST['filename'])); |
||
| 1867 | } |
||
| 1868 | |||
| 1869 | /** |
||
| 1870 | * Makes a copy of a template file in a new location |
||
| 1871 | * @uses Themes template, copy_template sub-template. |
||
| 1872 | */ |
||
| 1873 | function CopyTemplate() |
||
| 1874 | { |
||
| 1875 | global $context, $settings; |
||
| 1876 | |||
| 1877 | isAllowedTo('admin_forum'); |
||
| 1878 | loadTemplate('Themes'); |
||
| 1879 | |||
| 1880 | $context[$context['admin_menu_name']]['current_subsection'] = 'edit'; |
||
| 1881 | |||
| 1882 | $_GET['th'] = isset($_GET['th']) ? (int) $_GET['th'] : (int) $_GET['id']; |
||
| 1883 | |||
| 1884 | if (empty($_GET['th'])) |
||
| 1885 | fatal_lang_error('theme_install_invalid_id'); |
||
| 1886 | |||
| 1887 | // Get the theme info. |
||
| 1888 | $theme = get_single_theme($_GET['th']); |
||
| 1889 | $context['theme_id'] = $theme['id']; |
||
| 1890 | |||
| 1891 | if (isset($_REQUEST['template']) && preg_match('~[\./\\\\:\0]~', $_REQUEST['template']) == 0) |
||
| 1892 | { |
||
| 1893 | View Code Duplication | if (file_exists($settings['default_theme_dir'] . '/' . $_REQUEST['template'] . '.template.php')) |
|
| 1894 | $filename = $settings['default_theme_dir'] . '/' . $_REQUEST['template'] . '.template.php'; |
||
| 1895 | |||
| 1896 | else |
||
| 1897 | fatal_lang_error('no_access', false); |
||
| 1898 | |||
| 1899 | $fp = fopen($theme['theme_dir'] . '/' . $_REQUEST['template'] . '.template.php', 'w'); |
||
| 1900 | fwrite($fp, file_get_contents($filename)); |
||
|
0 ignored issues
–
show
The variable
$filename does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
| 1901 | fclose($fp); |
||
| 1902 | |||
| 1903 | redirectexit('action=admin;area=theme;th=' . $context['theme_id'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=copy'); |
||
| 1904 | } |
||
| 1905 | elseif (isset($_REQUEST['lang_file']) && preg_match('~^[^\./\\\\:\0]\.[^\./\\\\:\0]$~', $_REQUEST['lang_file']) != 0) |
||
| 1906 | { |
||
| 1907 | View Code Duplication | if (file_exists($settings['default_theme_dir'] . '/languages/' . $_REQUEST['template'] . '.php')) |
|
| 1908 | $filename = $settings['default_theme_dir'] . '/languages/' . $_REQUEST['template'] . '.php'; |
||
| 1909 | |||
| 1910 | else |
||
| 1911 | fatal_lang_error('no_access', false); |
||
| 1912 | |||
| 1913 | $fp = fopen($theme['theme_dir'] . '/languages/' . $_REQUEST['lang_file'] . '.php', 'w'); |
||
| 1914 | fwrite($fp, file_get_contents($filename)); |
||
| 1915 | fclose($fp); |
||
| 1916 | |||
| 1917 | redirectexit('action=admin;area=theme;th=' . $context['theme_id'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=copy'); |
||
| 1918 | } |
||
| 1919 | |||
| 1920 | $templates = array(); |
||
| 1921 | $lang_files = array(); |
||
| 1922 | |||
| 1923 | $dir = dir($settings['default_theme_dir']); |
||
| 1924 | while ($entry = $dir->read()) |
||
| 1925 | { |
||
| 1926 | if (substr($entry, -13) == '.template.php') |
||
| 1927 | $templates[] = substr($entry, 0, -13); |
||
| 1928 | } |
||
| 1929 | $dir->close(); |
||
| 1930 | |||
| 1931 | $dir = dir($settings['default_theme_dir'] . '/languages'); |
||
| 1932 | while ($entry = $dir->read()) |
||
| 1933 | { |
||
| 1934 | if (preg_match('~^([^\.]+\.[^\.]+)\.php$~', $entry, $matches)) |
||
| 1935 | $lang_files[] = $matches[1]; |
||
| 1936 | } |
||
| 1937 | $dir->close(); |
||
| 1938 | |||
| 1939 | natcasesort($templates); |
||
| 1940 | natcasesort($lang_files); |
||
| 1941 | |||
| 1942 | $context['available_templates'] = array(); |
||
| 1943 | foreach ($templates as $template) |
||
| 1944 | $context['available_templates'][$template] = array( |
||
| 1945 | 'filename' => $template . '.template.php', |
||
| 1946 | 'value' => $template, |
||
| 1947 | 'already_exists' => false, |
||
| 1948 | 'can_copy' => is_writable($theme['theme_dir']), |
||
| 1949 | ); |
||
| 1950 | $context['available_language_files'] = array(); |
||
| 1951 | foreach ($lang_files as $file) |
||
| 1952 | $context['available_language_files'][$file] = array( |
||
| 1953 | 'filename' => $file . '.php', |
||
| 1954 | 'value' => $file, |
||
| 1955 | 'already_exists' => false, |
||
| 1956 | 'can_copy' => file_exists($theme['theme_dir'] . '/languages') ? is_writable($theme['theme_dir'] . '/languages') : is_writable($theme['theme_dir']), |
||
| 1957 | ); |
||
| 1958 | |||
| 1959 | $dir = dir($theme['theme_dir']); |
||
| 1960 | while ($entry = $dir->read()) |
||
| 1961 | { |
||
| 1962 | if (substr($entry, -13) == '.template.php' && isset($context['available_templates'][substr($entry, 0, -13)])) |
||
| 1963 | { |
||
| 1964 | $context['available_templates'][substr($entry, 0, -13)]['already_exists'] = true; |
||
| 1965 | $context['available_templates'][substr($entry, 0, -13)]['can_copy'] = is_writable($theme['theme_dir'] . '/' . $entry); |
||
| 1966 | } |
||
| 1967 | } |
||
| 1968 | $dir->close(); |
||
| 1969 | |||
| 1970 | if (file_exists($theme['theme_dir'] . '/languages')) |
||
| 1971 | { |
||
| 1972 | $dir = dir($theme['theme_dir'] . '/languages'); |
||
| 1973 | while ($entry = $dir->read()) |
||
| 1974 | { |
||
| 1975 | if (preg_match('~^([^\.]+\.[^\.]+)\.php$~', $entry, $matches) && isset($context['available_language_files'][$matches[1]])) |
||
| 1976 | { |
||
| 1977 | $context['available_language_files'][$matches[1]]['already_exists'] = true; |
||
| 1978 | $context['available_language_files'][$matches[1]]['can_copy'] = is_writable($theme['theme_dir'] . '/languages/' . $entry); |
||
| 1979 | } |
||
| 1980 | } |
||
| 1981 | $dir->close(); |
||
| 1982 | } |
||
| 1983 | |||
| 1984 | $context['sub_template'] = 'copy_template'; |
||
| 1985 | } |
||
| 1986 | |||
| 1987 | ?> |
It seems like you are relying on a variable being defined by an iteration: