SimpleMachines /
SMF2.1
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * Simple Machines Forum (SMF) |
||
| 5 | * |
||
| 6 | * @package SMF |
||
| 7 | * @author Simple Machines http://www.simplemachines.org |
||
| 8 | * @copyright 2019 Simple Machines and individual contributors |
||
| 9 | * @license http://www.simplemachines.org/about/smf/license.php BSD |
||
| 10 | * |
||
| 11 | * @version 2.1 RC2 |
||
| 12 | */ |
||
| 13 | |||
| 14 | // Version information... |
||
| 15 | define('SMF_VERSION', '2.1 RC2'); |
||
| 16 | define('SMF_FULL_VERSION', 'SMF ' . SMF_VERSION); |
||
| 17 | define('SMF_SOFTWARE_YEAR', '2019'); |
||
| 18 | define('SMF_LANG_VERSION', '2.1 RC2'); |
||
| 19 | define('SMF_INSTALLING', 1); |
||
| 20 | |||
| 21 | /** |
||
| 22 | * The minimum required PHP version. |
||
| 23 | * |
||
| 24 | * @var string |
||
| 25 | */ |
||
| 26 | $GLOBALS['required_php_version'] = '5.4.0'; |
||
| 27 | |||
| 28 | /** |
||
| 29 | * A list of supported database systems. |
||
| 30 | * |
||
| 31 | * @var array |
||
| 32 | */ |
||
| 33 | $databases = array( |
||
| 34 | 'mysql' => array( |
||
| 35 | 'name' => 'MySQL', |
||
| 36 | 'version' => '5.0.22', |
||
| 37 | 'version_check' => 'global $db_connection; return min(mysqli_get_server_info($db_connection), mysqli_get_client_info());', |
||
| 38 | 'utf8_support' => true, |
||
| 39 | 'utf8_version' => '5.0.22', |
||
| 40 | 'utf8_version_check' => 'global $db_connection; return mysqli_get_server_info($db_connection);', |
||
| 41 | 'alter_support' => true, |
||
| 42 | ), |
||
| 43 | 'postgresql' => array( |
||
| 44 | 'name' => 'PostgreSQL', |
||
| 45 | 'version' => '9.4', |
||
| 46 | 'version_check' => '$version = pg_version(); return $version[\'client\'];', |
||
| 47 | 'always_has_db' => true, |
||
| 48 | ), |
||
| 49 | ); |
||
| 50 | |||
| 51 | /** |
||
| 52 | * The maximum time a single substep may take, in seconds. |
||
| 53 | * |
||
| 54 | * @var int |
||
| 55 | */ |
||
| 56 | $timeLimitThreshold = 3; |
||
| 57 | |||
| 58 | /** |
||
| 59 | * The current path to the upgrade.php file. |
||
| 60 | * |
||
| 61 | * @var string |
||
| 62 | */ |
||
| 63 | $upgrade_path = dirname(__FILE__); |
||
| 64 | |||
| 65 | /** |
||
| 66 | * The URL of the current page. |
||
| 67 | * |
||
| 68 | * @var string |
||
| 69 | */ |
||
| 70 | $upgradeurl = $_SERVER['PHP_SELF']; |
||
| 71 | |||
| 72 | /** |
||
| 73 | * Flag to disable the required administrator login. |
||
| 74 | * |
||
| 75 | * @var bool |
||
| 76 | */ |
||
| 77 | $disable_security = false; |
||
| 78 | |||
| 79 | /** |
||
| 80 | * The amount of seconds allowed between logins. |
||
| 81 | * If the first user to login is inactive for this amount of seconds, a second login is allowed. |
||
| 82 | * |
||
| 83 | * @var int |
||
| 84 | */ |
||
| 85 | $upcontext['inactive_timeout'] = 10; |
||
| 86 | |||
| 87 | global $txt; |
||
| 88 | |||
| 89 | // All the steps in detail. |
||
| 90 | // Number,Name,Function,Progress Weight. |
||
| 91 | $upcontext['steps'] = array( |
||
| 92 | 0 => array(1, 'upgrade_step_login', 'WelcomeLogin', 2), |
||
| 93 | 1 => array(2, 'upgrade_step_options', 'UpgradeOptions', 2), |
||
| 94 | 2 => array(3, 'upgrade_step_backup', 'BackupDatabase', 10), |
||
| 95 | 3 => array(4, 'upgrade_step_database', 'DatabaseChanges', 50), |
||
| 96 | 4 => array(5, 'upgrade_step_convertjson', 'serialize_to_json', 10), |
||
| 97 | 5 => array(6, 'upgrade_step_convertutf', 'ConvertUtf8', 20), |
||
| 98 | 6 => array(7, 'upgrade_step_delete', 'DeleteUpgrade', 1), |
||
| 99 | ); |
||
| 100 | // Just to remember which one has files in it. |
||
| 101 | $upcontext['database_step'] = 3; |
||
| 102 | @set_time_limit(600); |
||
| 103 | if (!ini_get('safe_mode')) |
||
| 104 | { |
||
| 105 | ini_set('mysql.connect_timeout', -1); |
||
| 106 | ini_set('default_socket_timeout', 900); |
||
| 107 | } |
||
| 108 | // Clean the upgrade path if this is from the client. |
||
| 109 | if (!empty($_SERVER['argv']) && php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR'])) |
||
| 110 | for ($i = 1; $i < $_SERVER['argc']; $i++) |
||
| 111 | { |
||
| 112 | if (preg_match('~^--path=(.+)$~', $_SERVER['argv'][$i], $match) != 0) |
||
| 113 | $upgrade_path = substr($match[1], -1) == '/' ? substr($match[1], 0, -1) : $match[1]; |
||
| 114 | } |
||
| 115 | |||
| 116 | // Are we from the client? |
||
| 117 | if (php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR'])) |
||
| 118 | { |
||
| 119 | $command_line = true; |
||
| 120 | $disable_security = true; |
||
| 121 | } |
||
| 122 | else |
||
| 123 | $command_line = false; |
||
| 124 | |||
| 125 | // We can't do anything without these files. |
||
| 126 | foreach (array('upgrade-helper.php', 'Settings.php') as $required_file) |
||
| 127 | { |
||
| 128 | if (!file_exists($upgrade_path . '/' . $required_file)) |
||
| 129 | die($required_file . ' was not found where it was expected: ' . $upgrade_path . '/' . $required_file . '! Make sure you have uploaded ALL files from the upgrade package to your forum\'s root directory. The upgrader cannot continue.'); |
||
| 130 | |||
| 131 | require_once($upgrade_path . '/' . $required_file); |
||
| 132 | } |
||
| 133 | |||
| 134 | // We don't use "-utf8" anymore... Tweak the entry that may have been loaded by Settings.php |
||
| 135 | if (isset($language)) |
||
| 136 | $language = str_ireplace('-utf8', '', basename($language, '.lng')); |
||
| 137 | |||
| 138 | // Figure out a valid language request (if any) |
||
| 139 | // Can't use $_GET until it's been cleaned, so do this manually and VERY restrictively! This even strips off those '-utf8' bits that we don't want. |
||
| 140 | if (isset($_SERVER['QUERY_STRING']) && preg_match('~\blang=(\w+)~', $_SERVER['QUERY_STRING'], $matches)) |
||
| 141 | $upcontext['lang'] = $matches[1]; |
||
| 142 | |||
| 143 | // Are we logged in? |
||
| 144 | if (isset($upgradeData)) |
||
| 145 | { |
||
| 146 | $upcontext['user'] = json_decode(base64_decode($upgradeData), true); |
||
| 147 | |||
| 148 | // Check for sensible values. |
||
| 149 | if (empty($upcontext['user']['started']) || $upcontext['user']['started'] < time() - 86400) |
||
| 150 | $upcontext['user']['started'] = time(); |
||
| 151 | if (empty($upcontext['user']['updated']) || $upcontext['user']['updated'] < time() - 86400) |
||
| 152 | $upcontext['user']['updated'] = 0; |
||
| 153 | |||
| 154 | $upcontext['started'] = $upcontext['user']['started']; |
||
| 155 | $upcontext['updated'] = $upcontext['user']['updated']; |
||
| 156 | |||
| 157 | $is_debug = !empty($upcontext['user']['debug']) ? true : false; |
||
| 158 | |||
| 159 | $upcontext['skip_db_substeps'] = !empty($upcontext['user']['skip_db_substeps']); |
||
| 160 | } |
||
| 161 | |||
| 162 | // Nothing sensible? |
||
| 163 | if (empty($upcontext['updated'])) |
||
| 164 | { |
||
| 165 | $upcontext['started'] = time(); |
||
| 166 | $upcontext['updated'] = 0; |
||
| 167 | $upcontext['skip_db_substeps'] = false; |
||
| 168 | $upcontext['user'] = array( |
||
| 169 | 'id' => 0, |
||
| 170 | 'name' => 'Guest', |
||
| 171 | 'pass' => 0, |
||
| 172 | 'started' => $upcontext['started'], |
||
| 173 | 'updated' => $upcontext['updated'], |
||
| 174 | ); |
||
| 175 | } |
||
| 176 | |||
| 177 | // Try to load the language file... or at least define a few necessary strings for now. |
||
| 178 | load_lang_file(); |
||
| 179 | |||
| 180 | // Load up some essential data... |
||
| 181 | loadEssentialData(); |
||
| 182 | |||
| 183 | // Are we going to be mimic'ing SSI at this point? |
||
| 184 | if (isset($_GET['ssi'])) |
||
| 185 | { |
||
| 186 | require_once($sourcedir . '/Errors.php'); |
||
| 187 | require_once($sourcedir . '/Logging.php'); |
||
| 188 | require_once($sourcedir . '/Load.php'); |
||
| 189 | require_once($sourcedir . '/Security.php'); |
||
| 190 | require_once($sourcedir . '/Subs-Package.php'); |
||
| 191 | |||
| 192 | // SMF isn't started up properly, but loadUserSettings calls our cookies. |
||
| 193 | if (!isset($smcFunc['json_encode'])) |
||
| 194 | { |
||
| 195 | $smcFunc['json_encode'] = 'json_encode'; |
||
| 196 | $smcFunc['json_decode'] = 'smf_json_decode'; |
||
| 197 | } |
||
| 198 | |||
| 199 | loadUserSettings(); |
||
| 200 | loadPermissions(); |
||
| 201 | } |
||
| 202 | |||
| 203 | // Include our helper functions. |
||
| 204 | require_once($sourcedir . '/Subs.php'); |
||
| 205 | require_once($sourcedir . '/LogInOut.php'); |
||
| 206 | |||
| 207 | // This only exists if we're on SMF ;) |
||
| 208 | if (isset($modSettings['smfVersion'])) |
||
| 209 | { |
||
| 210 | $request = $smcFunc['db_query']('', ' |
||
| 211 | SELECT variable, value |
||
| 212 | FROM {db_prefix}themes |
||
| 213 | WHERE id_theme = {int:id_theme} |
||
| 214 | AND variable IN ({string:theme_url}, {string:theme_dir}, {string:images_url})', |
||
| 215 | array( |
||
| 216 | 'id_theme' => 1, |
||
| 217 | 'theme_url' => 'theme_url', |
||
| 218 | 'theme_dir' => 'theme_dir', |
||
| 219 | 'images_url' => 'images_url', |
||
| 220 | 'db_error_skip' => true, |
||
| 221 | ) |
||
| 222 | ); |
||
| 223 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 224 | $modSettings[$row['variable']] = $row['value']; |
||
| 225 | $smcFunc['db_free_result']($request); |
||
| 226 | } |
||
| 227 | |||
| 228 | if (!isset($modSettings['theme_url'])) |
||
| 229 | { |
||
| 230 | $modSettings['theme_dir'] = $boarddir . '/Themes/default'; |
||
| 231 | $modSettings['theme_url'] = 'Themes/default'; |
||
| 232 | $modSettings['images_url'] = 'Themes/default/images'; |
||
| 233 | } |
||
| 234 | if (!isset($settings['default_theme_url'])) |
||
| 235 | $settings['default_theme_url'] = $modSettings['theme_url']; |
||
| 236 | if (!isset($settings['default_theme_dir'])) |
||
| 237 | $settings['default_theme_dir'] = $modSettings['theme_dir']; |
||
| 238 | |||
| 239 | // This is needed in case someone invokes the upgrader using https when upgrading an http forum |
||
| 240 | if (httpsOn()) |
||
| 241 | $settings['default_theme_url'] = strtr($settings['default_theme_url'], array('http://' => 'https://')); |
||
| 242 | |||
| 243 | $upcontext['is_large_forum'] = (empty($modSettings['smfVersion']) || $modSettings['smfVersion'] <= '1.1 RC1') && !empty($modSettings['totalMessages']) && $modSettings['totalMessages'] > 75000; |
||
| 244 | |||
| 245 | // Have we got tracking data - if so use it (It will be clean!) |
||
| 246 | if (isset($_GET['data'])) |
||
| 247 | { |
||
| 248 | global $is_debug; |
||
| 249 | |||
| 250 | $upcontext['upgrade_status'] = json_decode(base64_decode($_GET['data']), true); |
||
| 251 | $upcontext['current_step'] = $upcontext['upgrade_status']['curstep']; |
||
| 252 | $upcontext['language'] = $upcontext['upgrade_status']['lang']; |
||
| 253 | $upcontext['rid'] = $upcontext['upgrade_status']['rid']; |
||
| 254 | $support_js = $upcontext['upgrade_status']['js']; |
||
| 255 | |||
| 256 | // Only set this if the upgrader status says so. |
||
| 257 | if (empty($is_debug)) |
||
| 258 | $is_debug = $upcontext['upgrade_status']['debug']; |
||
| 259 | } |
||
| 260 | // Set the defaults. |
||
| 261 | else |
||
| 262 | { |
||
| 263 | $upcontext['current_step'] = 0; |
||
| 264 | $upcontext['rid'] = mt_rand(0, 5000); |
||
| 265 | $upcontext['upgrade_status'] = array( |
||
| 266 | 'curstep' => 0, |
||
| 267 | 'lang' => isset($upcontext['lang']) ? $upcontext['lang'] : basename($language, '.lng'), |
||
| 268 | 'rid' => $upcontext['rid'], |
||
| 269 | 'pass' => 0, |
||
| 270 | 'debug' => 0, |
||
| 271 | 'js' => 0, |
||
| 272 | ); |
||
| 273 | $upcontext['language'] = $upcontext['upgrade_status']['lang']; |
||
| 274 | } |
||
| 275 | |||
| 276 | // Now that we have the necessary info, make sure we loaded the right language file. |
||
| 277 | load_lang_file(); |
||
| 278 | |||
| 279 | // Default title... |
||
| 280 | $upcontext['page_title'] = $txt['updating_smf_installation']; |
||
| 281 | |||
| 282 | // If this isn't the first stage see whether they are logging in and resuming. |
||
| 283 | if ($upcontext['current_step'] != 0 || !empty($upcontext['user']['step'])) |
||
| 284 | checkLogin(); |
||
| 285 | |||
| 286 | if ($command_line) |
||
| 287 | cmdStep0(); |
||
| 288 | |||
| 289 | // Don't error if we're using xml. |
||
| 290 | if (isset($_GET['xml'])) |
||
| 291 | $upcontext['return_error'] = true; |
||
| 292 | |||
| 293 | // Loop through all the steps doing each one as required. |
||
| 294 | $upcontext['overall_percent'] = 0; |
||
| 295 | foreach ($upcontext['steps'] as $num => $step) |
||
| 296 | { |
||
| 297 | if ($num >= $upcontext['current_step']) |
||
| 298 | { |
||
| 299 | // The current weight of this step in terms of overall progress. |
||
| 300 | $upcontext['step_weight'] = $step[3]; |
||
| 301 | // Make sure we reset the skip button. |
||
| 302 | $upcontext['skip'] = false; |
||
| 303 | |||
| 304 | // We cannot proceed if we're not logged in. |
||
| 305 | if ($num != 0 && !$disable_security && $upcontext['user']['pass'] != $upcontext['upgrade_status']['pass']) |
||
| 306 | { |
||
| 307 | $upcontext['steps'][0][2](); |
||
| 308 | break; |
||
| 309 | } |
||
| 310 | |||
| 311 | // Call the step and if it returns false that means pause! |
||
| 312 | if (function_exists($step[2]) && $step[2]() === false) |
||
| 313 | break; |
||
| 314 | elseif (function_exists($step[2])) |
||
| 315 | { |
||
| 316 | //Start each new step with this unset, so the 'normal' template is called first |
||
| 317 | unset($_GET['xml']); |
||
| 318 | //Clear out warnings at the start of each step |
||
| 319 | unset($upcontext['custom_warning']); |
||
| 320 | $_GET['substep'] = 0; |
||
| 321 | $upcontext['current_step']++; |
||
| 322 | } |
||
| 323 | } |
||
| 324 | $upcontext['overall_percent'] += $step[3]; |
||
| 325 | } |
||
| 326 | |||
| 327 | upgradeExit(); |
||
| 328 | |||
| 329 | // Exit the upgrade script. |
||
| 330 | function upgradeExit($fallThrough = false) |
||
| 331 | { |
||
| 332 | global $upcontext, $upgradeurl, $sourcedir, $command_line, $is_debug, $txt; |
||
| 333 | |||
| 334 | // Save where we are... |
||
| 335 | if (!empty($upcontext['current_step']) && !empty($upcontext['user']['id'])) |
||
| 336 | { |
||
| 337 | $upcontext['user']['step'] = $upcontext['current_step']; |
||
| 338 | $upcontext['user']['substep'] = $_GET['substep']; |
||
| 339 | $upcontext['user']['updated'] = time(); |
||
| 340 | $upcontext['user']['skip_db_substeps'] = !empty($upcontext['skip_db_substeps']); |
||
| 341 | $upcontext['debug'] = $is_debug; |
||
| 342 | $upgradeData = base64_encode(json_encode($upcontext['user'])); |
||
| 343 | require_once($sourcedir . '/Subs-Admin.php'); |
||
| 344 | updateSettingsFile(array('upgradeData' => '"' . $upgradeData . '"')); |
||
| 345 | updateDbLastError(0); |
||
| 346 | } |
||
| 347 | |||
| 348 | // Handle the progress of the step, if any. |
||
| 349 | if (!empty($upcontext['step_progress']) && isset($upcontext['steps'][$upcontext['current_step']])) |
||
| 350 | { |
||
| 351 | $upcontext['step_progress'] = round($upcontext['step_progress'], 1); |
||
| 352 | $upcontext['overall_percent'] += $upcontext['step_progress'] * ($upcontext['steps'][$upcontext['current_step']][3] / 100); |
||
| 353 | } |
||
| 354 | $upcontext['overall_percent'] = (int) $upcontext['overall_percent']; |
||
| 355 | |||
| 356 | // We usually dump our templates out. |
||
| 357 | if (!$fallThrough) |
||
| 358 | { |
||
| 359 | // This should not happen my dear... HELP ME DEVELOPERS!! |
||
| 360 | if (!empty($command_line)) |
||
| 361 | { |
||
| 362 | if (function_exists('debug_print_backtrace')) |
||
| 363 | debug_print_backtrace(); |
||
| 364 | |||
| 365 | printf($txt['error_unexpected_template_call'], isset($upcontext['sub_template']) ? $upcontext['sub_template'] : ''); |
||
| 366 | flush(); |
||
| 367 | die(); |
||
| 368 | } |
||
| 369 | |||
| 370 | if (!isset($_GET['xml'])) |
||
| 371 | template_upgrade_above(); |
||
| 372 | else |
||
| 373 | { |
||
| 374 | header('content-type: text/xml; charset=UTF-8'); |
||
| 375 | // Sadly we need to retain the $_GET data thanks to the old upgrade scripts. |
||
| 376 | $upcontext['get_data'] = array(); |
||
| 377 | foreach ($_GET as $k => $v) |
||
| 378 | { |
||
| 379 | if (substr($k, 0, 3) != 'amp' && !in_array($k, array('xml', 'substep', 'lang', 'data', 'step', 'filecount'))) |
||
| 380 | { |
||
| 381 | $upcontext['get_data'][$k] = $v; |
||
| 382 | } |
||
| 383 | } |
||
| 384 | template_xml_above(); |
||
| 385 | } |
||
| 386 | |||
| 387 | // Call the template. |
||
| 388 | if (isset($upcontext['sub_template'])) |
||
| 389 | { |
||
| 390 | $upcontext['upgrade_status']['curstep'] = $upcontext['current_step']; |
||
| 391 | $upcontext['form_url'] = $upgradeurl . '?step=' . $upcontext['current_step'] . '&substep=' . $_GET['substep'] . '&data=' . base64_encode(json_encode($upcontext['upgrade_status'])); |
||
| 392 | |||
| 393 | // Custom stuff to pass back? |
||
| 394 | if (!empty($upcontext['query_string'])) |
||
| 395 | $upcontext['form_url'] .= $upcontext['query_string']; |
||
| 396 | |||
| 397 | // Call the appropriate subtemplate |
||
| 398 | if (is_callable('template_' . $upcontext['sub_template'])) |
||
| 399 | call_user_func('template_' . $upcontext['sub_template']); |
||
| 400 | else |
||
| 401 | die(sprintf($txt['error_invalid_template'], $upcontext['sub_template'])); |
||
| 402 | } |
||
| 403 | |||
| 404 | // Was there an error? |
||
| 405 | if (!empty($upcontext['forced_error_message'])) |
||
| 406 | echo $upcontext['forced_error_message']; |
||
| 407 | |||
| 408 | // Show the footer. |
||
| 409 | if (!isset($_GET['xml'])) |
||
| 410 | template_upgrade_below(); |
||
| 411 | else |
||
| 412 | template_xml_below(); |
||
| 413 | } |
||
| 414 | |||
| 415 | // Show the upgrade time for CLI when we are completely done, if in debug mode. |
||
| 416 | if (!empty($command_line) && $is_debug) |
||
| 417 | { |
||
| 418 | $active = time() - $upcontext['started']; |
||
| 419 | $hours = floor($active / 3600); |
||
| 420 | $minutes = intval(($active / 60) % 60); |
||
| 421 | $seconds = intval($active % 60); |
||
| 422 | |||
| 423 | $totalTime = ''; |
||
| 424 | if ($hours > 0) |
||
| 425 | echo "\n" . '', sprintf($txt['upgrade_completed_time_hms'], $hours, $minutes, $seconds), '' . "\n"; |
||
| 426 | elseif ($minutes > 0) |
||
| 427 | echo "\n" . '', sprintf($txt['upgrade_completed_time_ms'], $minutes, $seconds), '' . "\n"; |
||
| 428 | elseif ($seconds > 0) |
||
| 429 | echo "\n" . '', sprintf($txt['upgrade_completed_time_s'], $seconds), '' . "\n"; |
||
| 430 | } |
||
| 431 | |||
| 432 | // Bang - gone! |
||
| 433 | die(); |
||
| 434 | } |
||
| 435 | |||
| 436 | // Load the list of language files, and the current language file. |
||
| 437 | function load_lang_file() |
||
| 438 | { |
||
| 439 | global $txt, $upcontext, $language; |
||
| 440 | |||
| 441 | static $lang_dir = '', $detected_languages = array(), $loaded_langfile = ''; |
||
| 442 | |||
| 443 | // Do we know where to look for the language files, or shall we just guess for now? |
||
| 444 | $temp = isset($modSettings['theme_dir']) ? $modSettings['theme_dir'] . '/languages' : dirname(__FILE__) . '/Themes/default/languages'; |
||
| 445 | |||
| 446 | if ($lang_dir != $temp) |
||
| 447 | { |
||
| 448 | $lang_dir = $temp; |
||
| 449 | $detected_languages = array(); |
||
| 450 | } |
||
| 451 | |||
| 452 | // Override the language file? |
||
| 453 | if (isset($upcontext['language'])) |
||
| 454 | $_SESSION['upgrader_langfile'] = 'Install.' . $upcontext['language'] . '.php'; |
||
| 455 | elseif (isset($upcontext['lang'])) |
||
| 456 | $_SESSION['upgrader_langfile'] = 'Install.' . $upcontext['lang'] . '.php'; |
||
| 457 | elseif (isset($language)) |
||
| 458 | $_SESSION['upgrader_langfile'] = 'Install.' . $language . '.php'; |
||
| 459 | |||
| 460 | // Avoid pointless repetition |
||
| 461 | if (isset($_SESSION['upgrader_langfile']) && $loaded_langfile == $lang_dir . '/' . $_SESSION['upgrader_langfile']) |
||
| 462 | return; |
||
| 463 | |||
| 464 | // Now try to find the language files |
||
| 465 | if (empty($detected_languages)) |
||
| 466 | { |
||
| 467 | // Make sure the languages directory actually exists. |
||
| 468 | if (file_exists($lang_dir)) |
||
| 469 | { |
||
| 470 | // Find all the "Install" language files in the directory. |
||
| 471 | $dir = dir($lang_dir); |
||
| 472 | while ($entry = $dir->read()) |
||
| 473 | { |
||
| 474 | // Skip any old '-utf8' language files that might be lying around |
||
| 475 | if (strpos($entry, '-utf8') !== false) |
||
| 476 | continue; |
||
| 477 | |||
| 478 | if (substr($entry, 0, 8) == 'Install.' && substr($entry, -4) == '.php') |
||
| 479 | $detected_languages[$entry] = ucfirst(substr($entry, 8, strlen($entry) - 12)); |
||
| 480 | } |
||
| 481 | $dir->close(); |
||
| 482 | } |
||
| 483 | // Our guess was wrong, but that's fine. We'll try again after $modSettings['theme_dir'] is defined. |
||
| 484 | elseif (!isset($modSettings['theme_dir'])) |
||
| 485 | { |
||
| 486 | // Define a few essential strings for now. |
||
| 487 | $txt['error_db_connect_settings'] = 'Cannot connect to the database server.<br><br>Please check that the database info variables are correct in Settings.php.'; |
||
| 488 | $txt['error_sourcefile_missing'] = 'Unable to find the Sources/%1$s file. Please make sure it was uploaded properly, and then try again.'; |
||
| 489 | |||
| 490 | $txt['warning_lang_old'] = 'The language files for your selected language, %1$s, have not been updated to the latest version. Upgrade will continue with the forum default, %2$s.'; |
||
| 491 | $txt['warning_lang_missing'] = 'The upgrader could not find the "Install" language file for your selected language, %1$s. Upgrade will continue with the forum default, %2$s.'; |
||
| 492 | |||
| 493 | return; |
||
| 494 | } |
||
| 495 | } |
||
| 496 | |||
| 497 | // Didn't find any, show an error message! |
||
| 498 | if (empty($detected_languages)) |
||
| 499 | { |
||
| 500 | $from = explode('/', $_SERVER['PHP_SELF']); |
||
| 501 | $to = explode('/', $lang_dir); |
||
| 502 | $relPath = $to; |
||
| 503 | |||
| 504 | foreach($from as $depth => $dir) |
||
| 505 | { |
||
| 506 | if ($dir === $to[$depth]) |
||
| 507 | array_shift($relPath); |
||
| 508 | else |
||
| 509 | { |
||
| 510 | $remaining = count($from) - $depth; |
||
| 511 | if ($remaining > 1) |
||
| 512 | { |
||
| 513 | $padLength = (count($relPath) + $remaining - 1) * -1; |
||
| 514 | $relPath = array_pad($relPath, $padLength, '..'); |
||
| 515 | break; |
||
| 516 | } |
||
| 517 | else |
||
| 518 | $relPath[0] = './' . $relPath[0]; |
||
| 519 | } |
||
| 520 | } |
||
| 521 | $relPath = implode(DIRECTORY_SEPARATOR, $relPath); |
||
| 522 | |||
| 523 | // Let's not cache this message, eh? |
||
| 524 | header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); |
||
| 525 | header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); |
||
| 526 | header('Cache-Control: no-cache'); |
||
| 527 | |||
| 528 | echo '<!DOCTYPE html> |
||
| 529 | <html> |
||
| 530 | <head> |
||
| 531 | <title>SMF Upgrader: Error!</title> |
||
| 532 | <style> |
||
| 533 | body { |
||
| 534 | font-family: sans-serif; |
||
| 535 | max-width: 700px; } |
||
| 536 | |||
| 537 | h1 { |
||
| 538 | font-size: 14pt; } |
||
| 539 | |||
| 540 | .directory { |
||
| 541 | margin: 0.3em; |
||
| 542 | font-family: monospace; |
||
| 543 | font-weight: bold; } |
||
| 544 | </style> |
||
| 545 | </head> |
||
| 546 | <body> |
||
| 547 | <h1>A critical error has occurred.</h1> |
||
| 548 | <p>This upgrader was unable to find the upgrader\'s language file or files. They should be found under:</p> |
||
| 549 | <div class="directory">', $relPath, '</div> |
||
| 550 | <p>In some cases, FTP clients do not properly upload files with this many folders. Please double check to make sure you <strong>have uploaded all the files in the distribution</strong>.</p> |
||
| 551 | <p>If that doesn\'t help, please make sure this upgrade.php file is in the same place as the Themes folder.</p> |
||
| 552 | <p>If you continue to get this error message, feel free to <a href="https://support.simplemachines.org/">look to us for support</a>.</p> |
||
| 553 | </body> |
||
| 554 | </html>'; |
||
| 555 | die; |
||
| 556 | } |
||
| 557 | |||
| 558 | // Make sure it exists. If it doesn't, reset it. |
||
| 559 | if (!isset($_SESSION['upgrader_langfile']) || preg_match('~[^\w.-]~', $_SESSION['upgrader_langfile']) === 1 || !file_exists($lang_dir . '/' . $_SESSION['upgrader_langfile'])) |
||
| 560 | { |
||
| 561 | // Use the first one... |
||
| 562 | list ($_SESSION['upgrader_langfile']) = array_keys($detected_languages); |
||
| 563 | |||
| 564 | // If we have English and some other language, use the other language. |
||
| 565 | if ($_SESSION['upgrader_langfile'] == 'Install.english.php' && count($detected_languages) > 1) |
||
| 566 | list (, $_SESSION['upgrader_langfile']) = array_keys($detected_languages); |
||
| 567 | } |
||
| 568 | |||
| 569 | // For backup we load English at first, then the second language will overwrite it. |
||
| 570 | if ($_SESSION['upgrader_langfile'] != 'Install.english.php') |
||
| 571 | require_once($lang_dir . '/Install.english.php'); |
||
| 572 | |||
| 573 | // And now include the actual language file itself. |
||
| 574 | require_once($lang_dir . '/' . $_SESSION['upgrader_langfile']); |
||
| 575 | |||
| 576 | // Remember what we've done |
||
| 577 | $loaded_langfile = $lang_dir . '/' . $_SESSION['upgrader_langfile']; |
||
| 578 | } |
||
| 579 | |||
| 580 | // Used to direct the user to another location. |
||
| 581 | function redirectLocation($location, $addForm = true) |
||
| 582 | { |
||
| 583 | global $upgradeurl, $upcontext, $command_line; |
||
| 584 | |||
| 585 | // Command line users can't be redirected. |
||
| 586 | if ($command_line) |
||
| 587 | upgradeExit(true); |
||
| 588 | |||
| 589 | // Are we providing the core info? |
||
| 590 | if ($addForm) |
||
| 591 | { |
||
| 592 | $upcontext['upgrade_status']['curstep'] = $upcontext['current_step']; |
||
| 593 | $location = $upgradeurl . '?step=' . $upcontext['current_step'] . '&substep=' . $_GET['substep'] . '&data=' . base64_encode(json_encode($upcontext['upgrade_status'])) . $location; |
||
| 594 | } |
||
| 595 | |||
| 596 | while (@ob_end_clean()) |
||
| 597 | header('location: ' . strtr($location, array('&' => '&'))); |
||
| 598 | |||
| 599 | // Exit - saving status as we go. |
||
| 600 | upgradeExit(true); |
||
| 601 | } |
||
| 602 | |||
| 603 | // Load all essential data and connect to the DB as this is pre SSI.php |
||
| 604 | function loadEssentialData() |
||
| 605 | { |
||
| 606 | global $db_server, $db_user, $db_passwd, $db_name, $db_connection; |
||
| 607 | global $db_prefix, $db_character_set, $db_type, $db_port; |
||
| 608 | global $db_mb4, $modSettings, $sourcedir, $smcFunc, $txt; |
||
| 609 | |||
| 610 | error_reporting(E_ALL); |
||
| 611 | define('SMF', 1); |
||
| 612 | |||
| 613 | // Start the session. |
||
| 614 | if (@ini_get('session.save_handler') == 'user') |
||
| 615 | @ini_set('session.save_handler', 'files'); |
||
| 616 | @session_start(); |
||
| 617 | |||
| 618 | if (empty($smcFunc)) |
||
| 619 | $smcFunc = array(); |
||
| 620 | |||
| 621 | $smcFunc['random_int'] = function($min = 0, $max = PHP_INT_MAX) |
||
| 622 | { |
||
| 623 | global $sourcedir; |
||
| 624 | |||
| 625 | // Oh, wouldn't it be great if I *was* crazy? Then the world would be okay. |
||
| 626 | if (!is_callable('random_int')) |
||
| 627 | require_once($sourcedir . '/random_compat/random.php'); |
||
| 628 | |||
| 629 | return random_int($min, $max); |
||
| 630 | }; |
||
| 631 | |||
| 632 | // We need this for authentication and some upgrade code |
||
| 633 | require_once($sourcedir . '/Subs-Auth.php'); |
||
| 634 | require_once($sourcedir . '/Class-Package.php'); |
||
| 635 | |||
| 636 | $smcFunc['strtolower'] = 'smf_strtolower'; |
||
| 637 | |||
| 638 | // Initialize everything... |
||
| 639 | initialize_inputs(); |
||
| 640 | |||
| 641 | // Get the database going! |
||
| 642 | if (empty($db_type) || $db_type == 'mysqli') |
||
| 643 | { |
||
| 644 | $db_type = 'mysql'; |
||
| 645 | // If overriding $db_type, need to set its settings.php entry too |
||
| 646 | $changes = array(); |
||
| 647 | $changes['db_type'] = '\'mysql\''; |
||
| 648 | require_once($sourcedir . '/Subs-Admin.php'); |
||
| 649 | updateSettingsFile($changes); |
||
| 650 | } |
||
| 651 | |||
| 652 | if (file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php')) |
||
| 653 | { |
||
| 654 | require_once($sourcedir . '/Subs-Db-' . $db_type . '.php'); |
||
| 655 | |||
| 656 | // Make the connection... |
||
| 657 | if (empty($db_connection)) |
||
| 658 | { |
||
| 659 | $options = array('non_fatal' => true); |
||
| 660 | // Add in the port if needed |
||
| 661 | if (!empty($db_port)) |
||
| 662 | $options['port'] = $db_port; |
||
| 663 | |||
| 664 | if (!empty($db_mb4)) |
||
| 665 | $options['db_mb4'] = $db_mb4; |
||
| 666 | |||
| 667 | $db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $options); |
||
| 668 | } |
||
| 669 | else |
||
| 670 | // If we've returned here, ping/reconnect to be safe |
||
| 671 | $smcFunc['db_ping']($db_connection); |
||
| 672 | |||
| 673 | // Oh dear god!! |
||
| 674 | if ($db_connection === null) |
||
| 675 | die($txt['error_db_connect_settings']); |
||
| 676 | |||
| 677 | if ($db_type == 'mysql' && isset($db_character_set) && preg_match('~^\w+$~', $db_character_set) === 1) |
||
| 678 | $smcFunc['db_query']('', ' |
||
| 679 | SET NAMES {string:db_character_set}', |
||
| 680 | array( |
||
| 681 | 'db_error_skip' => true, |
||
| 682 | 'db_character_set' => $db_character_set, |
||
| 683 | ) |
||
| 684 | ); |
||
| 685 | |||
| 686 | // Load the modSettings data... |
||
| 687 | $request = $smcFunc['db_query']('', ' |
||
| 688 | SELECT variable, value |
||
| 689 | FROM {db_prefix}settings', |
||
| 690 | array( |
||
| 691 | 'db_error_skip' => true, |
||
| 692 | ) |
||
| 693 | ); |
||
| 694 | $modSettings = array(); |
||
| 695 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 696 | $modSettings[$row['variable']] = $row['value']; |
||
| 697 | $smcFunc['db_free_result']($request); |
||
| 698 | } |
||
| 699 | else |
||
| 700 | return throw_error(sprintf($txt['error_sourcefile_missing'], 'Subs-Db-' . $db_type . '.php')); |
||
| 701 | |||
| 702 | require_once($sourcedir . '/Subs.php'); |
||
| 703 | |||
| 704 | // If they don't have the file, they're going to get a warning anyway so we won't need to clean request vars. |
||
| 705 | if (file_exists($sourcedir . '/QueryString.php') && php_version_check()) |
||
| 706 | { |
||
| 707 | require_once($sourcedir . '/QueryString.php'); |
||
| 708 | cleanRequest(); |
||
| 709 | } |
||
| 710 | |||
| 711 | if (!isset($_GET['substep'])) |
||
| 712 | $_GET['substep'] = 0; |
||
| 713 | } |
||
| 714 | |||
| 715 | function initialize_inputs() |
||
| 716 | { |
||
| 717 | global $start_time, $db_type; |
||
| 718 | |||
| 719 | $start_time = time(); |
||
| 720 | |||
| 721 | umask(0); |
||
| 722 | |||
| 723 | ob_start(); |
||
| 724 | |||
| 725 | // Better to upgrade cleanly and fall apart than to screw everything up if things take too long. |
||
| 726 | ignore_user_abort(true); |
||
| 727 | |||
| 728 | // This is really quite simple; if ?delete is on the URL, delete the upgrader... |
||
| 729 | if (isset($_GET['delete'])) |
||
| 730 | { |
||
| 731 | @unlink(__FILE__); |
||
| 732 | |||
| 733 | // And the extra little files ;). |
||
| 734 | @unlink(dirname(__FILE__) . '/upgrade_1-0.sql'); |
||
| 735 | @unlink(dirname(__FILE__) . '/upgrade_1-1.sql'); |
||
| 736 | @unlink(dirname(__FILE__) . '/upgrade_2-0_' . $db_type . '.sql'); |
||
| 737 | @unlink(dirname(__FILE__) . '/upgrade_2-1_' . $db_type . '.sql'); |
||
| 738 | @unlink(dirname(__FILE__) . '/upgrade-helper.php'); |
||
| 739 | |||
| 740 | $dh = opendir(dirname(__FILE__)); |
||
| 741 | while ($file = readdir($dh)) |
||
| 742 | { |
||
| 743 | if (preg_match('~upgrade_\d-\d_([A-Za-z])+\.sql~i', $file, $matches) && isset($matches[1])) |
||
| 744 | @unlink(dirname(__FILE__) . '/' . $file); |
||
| 745 | } |
||
| 746 | closedir($dh); |
||
| 747 | |||
| 748 | // Legacy files while we're at it. NOTE: We only touch files we KNOW shouldn't be there. |
||
| 749 | // 1.1 Sources files not in 2.0+ |
||
| 750 | @unlink(dirname(__FILE__) . '/Sources/ModSettings.php'); |
||
| 751 | // 1.1 Templates that don't exist any more (e.g. renamed) |
||
| 752 | @unlink(dirname(__FILE__) . '/Themes/default/Combat.template.php'); |
||
| 753 | @unlink(dirname(__FILE__) . '/Themes/default/Modlog.template.php'); |
||
| 754 | // 1.1 JS files were stored in the main theme folder, but in 2.0+ are in the scripts/ folder |
||
| 755 | @unlink(dirname(__FILE__) . '/Themes/default/fader.js'); |
||
| 756 | @unlink(dirname(__FILE__) . '/Themes/default/script.js'); |
||
| 757 | @unlink(dirname(__FILE__) . '/Themes/default/spellcheck.js'); |
||
| 758 | @unlink(dirname(__FILE__) . '/Themes/default/xml_board.js'); |
||
| 759 | @unlink(dirname(__FILE__) . '/Themes/default/xml_topic.js'); |
||
| 760 | |||
| 761 | // 2.0 Sources files not in 2.1+ |
||
| 762 | @unlink(dirname(__FILE__) . '/Sources/DumpDatabase.php'); |
||
| 763 | @unlink(dirname(__FILE__) . '/Sources/LockTopic.php'); |
||
| 764 | |||
| 765 | header('location: http://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.png'); |
||
| 766 | exit; |
||
| 767 | } |
||
| 768 | |||
| 769 | // Something is causing this to happen, and it's annoying. Stop it. |
||
| 770 | $temp = 'upgrade_php?step'; |
||
| 771 | while (strlen($temp) > 4) |
||
| 772 | { |
||
| 773 | if (isset($_GET[$temp])) |
||
| 774 | unset($_GET[$temp]); |
||
| 775 | $temp = substr($temp, 1); |
||
| 776 | } |
||
| 777 | |||
| 778 | // Force a step, defaulting to 0. |
||
| 779 | $_GET['step'] = (int) @$_GET['step']; |
||
| 780 | $_GET['substep'] = (int) @$_GET['substep']; |
||
| 781 | } |
||
| 782 | |||
| 783 | // Step 0 - Let's welcome them in and ask them to login! |
||
| 784 | function WelcomeLogin() |
||
| 785 | { |
||
| 786 | global $boarddir, $sourcedir, $modSettings, $cachedir, $upgradeurl, $upcontext; |
||
| 787 | global $smcFunc, $db_type, $databases, $boardurl; |
||
| 788 | |||
| 789 | // We global $txt here so that the language files can add to them. This variable is NOT unused. |
||
| 790 | global $txt; |
||
| 791 | |||
| 792 | $upcontext['sub_template'] = 'welcome_message'; |
||
| 793 | |||
| 794 | // Check for some key files - one template, one language, and a new and an old source file. |
||
| 795 | $check = @file_exists($modSettings['theme_dir'] . '/index.template.php') |
||
| 796 | && @file_exists($sourcedir . '/QueryString.php') |
||
| 797 | && @file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php') |
||
| 798 | && @file_exists(dirname(__FILE__) . '/upgrade_2-1_' . $db_type . '.sql'); |
||
| 799 | |||
| 800 | // Need legacy scripts? |
||
| 801 | if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < 2.1) |
||
| 802 | $check &= @file_exists(dirname(__FILE__) . '/upgrade_2-0_' . $db_type . '.sql'); |
||
| 803 | if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < 2.0) |
||
| 804 | $check &= @file_exists(dirname(__FILE__) . '/upgrade_1-1.sql'); |
||
| 805 | if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < 1.1) |
||
| 806 | $check &= @file_exists(dirname(__FILE__) . '/upgrade_1-0.sql'); |
||
| 807 | |||
| 808 | // We don't need "-utf8" files anymore... |
||
| 809 | $upcontext['language'] = str_ireplace('-utf8', '', $upcontext['language']); |
||
| 810 | |||
| 811 | if (!$check) |
||
| 812 | // Don't tell them what files exactly because it's a spot check - just like teachers don't tell which problems they are spot checking, that's dumb. |
||
| 813 | return throw_error($txt['error_upgrade_files_missing']); |
||
| 814 | |||
| 815 | // Do they meet the install requirements? |
||
| 816 | if (!php_version_check()) |
||
| 817 | return throw_error($txt['error_php_too_low']); |
||
| 818 | |||
| 819 | if (!db_version_check()) |
||
| 820 | return throw_error(sprintf($txt['error_db_too_low'], $databases[$db_type]['name'])); |
||
| 821 | |||
| 822 | // Do some checks to make sure they have proper privileges |
||
| 823 | db_extend('packages'); |
||
| 824 | |||
| 825 | // CREATE |
||
| 826 | $create = $smcFunc['db_create_table']('{db_prefix}priv_check', array(array('name' => 'id_test', 'type' => 'int', 'size' => 10, 'unsigned' => true, 'auto' => true)), array(array('columns' => array('id_test'), 'type' => 'primary')), array(), 'overwrite'); |
||
| 827 | |||
| 828 | // ALTER |
||
| 829 | $alter = $smcFunc['db_add_column']('{db_prefix}priv_check', array('name' => 'txt', 'type' => 'varchar', 'size' => 4, 'null' => false, 'default' => '')); |
||
| 830 | |||
| 831 | // DROP |
||
| 832 | $drop = $smcFunc['db_drop_table']('{db_prefix}priv_check'); |
||
| 833 | |||
| 834 | // Sorry... we need CREATE, ALTER and DROP |
||
| 835 | if (!$create || !$alter || !$drop) |
||
| 836 | return throw_error(sprintf($txt['error_db_privileges'], $databases[$db_type]['name'])); |
||
| 837 | |||
| 838 | // Do a quick version spot check. |
||
| 839 | $temp = substr(@implode('', @file($boarddir . '/index.php')), 0, 4096); |
||
| 840 | preg_match('~\*\s@version\s+(.+)[\s]{2}~i', $temp, $match); |
||
| 841 | if (empty($match[1]) || (trim($match[1]) != SMF_VERSION)) |
||
| 842 | return throw_error($txt['error_upgrade_old_files']); |
||
| 843 | |||
| 844 | // What absolutely needs to be writable? |
||
| 845 | $writable_files = array( |
||
| 846 | $boarddir . '/Settings.php', |
||
| 847 | $boarddir . '/Settings_bak.php', |
||
| 848 | ); |
||
| 849 | |||
| 850 | // Only check for minified writable files if we have it enabled or not set. |
||
| 851 | if (!empty($modSettings['minimize_files']) || !isset($modSettings['minimize_files'])) |
||
| 852 | $writable_files += array( |
||
| 853 | $modSettings['theme_dir'] . '/css/minified.css', |
||
| 854 | $modSettings['theme_dir'] . '/scripts/minified.js', |
||
| 855 | $modSettings['theme_dir'] . '/scripts/minified_deferred.js', |
||
| 856 | ); |
||
| 857 | |||
| 858 | // Do we need to add this setting? |
||
| 859 | $need_settings_update = empty($modSettings['custom_avatar_dir']); |
||
| 860 | |||
| 861 | $custom_av_dir = !empty($modSettings['custom_avatar_dir']) ? $modSettings['custom_avatar_dir'] : $GLOBALS['boarddir'] . '/custom_avatar'; |
||
| 862 | $custom_av_url = !empty($modSettings['custom_avatar_url']) ? $modSettings['custom_avatar_url'] : $boardurl . '/custom_avatar'; |
||
| 863 | |||
| 864 | // This little fellow has to cooperate... |
||
| 865 | quickFileWritable($custom_av_dir); |
||
| 866 | |||
| 867 | // Are we good now? |
||
| 868 | if (!is_writable($custom_av_dir)) |
||
| 869 | return throw_error(sprintf($txt['error_dir_not_writable'], $custom_av_dir)); |
||
| 870 | elseif ($need_settings_update) |
||
| 871 | { |
||
| 872 | if (!function_exists('cache_put_data')) |
||
| 873 | require_once($sourcedir . '/Load.php'); |
||
| 874 | |||
| 875 | updateSettings(array('custom_avatar_dir' => $custom_av_dir)); |
||
| 876 | updateSettings(array('custom_avatar_url' => $custom_av_url)); |
||
| 877 | } |
||
| 878 | |||
| 879 | require_once($sourcedir . '/Security.php'); |
||
| 880 | |||
| 881 | // Check the cache directory. |
||
| 882 | $cachedir_temp = empty($cachedir) ? $boarddir . '/cache' : $cachedir; |
||
| 883 | if (!file_exists($cachedir_temp)) |
||
| 884 | @mkdir($cachedir_temp); |
||
| 885 | |||
| 886 | if (!file_exists($cachedir_temp)) |
||
| 887 | return throw_error($txt['error_cache_not_found']); |
||
| 888 | |||
| 889 | if (!file_exists($modSettings['theme_dir'] . '/languages/index.' . $upcontext['language'] . '.php')) |
||
| 890 | return throw_error(sprintf($txt['error_lang_index_missing'], $upcontext['language'], $upgradeurl)); |
||
| 891 | elseif (!isset($_GET['skiplang'])) |
||
| 892 | { |
||
| 893 | $temp = substr(@implode('', @file($modSettings['theme_dir'] . '/languages/index.' . $upcontext['language'] . '.php')), 0, 4096); |
||
| 894 | preg_match('~(?://|/\*)\s*Version:\s+(.+?);\s*index(?:[\s]{2}|\*/)~i', $temp, $match); |
||
| 895 | |||
| 896 | if (empty($match[1]) || $match[1] != SMF_LANG_VERSION) |
||
| 897 | return throw_error(sprintf($txt['error_upgrade_old_lang_files'], $upcontext['language'], $upgradeurl)); |
||
| 898 | } |
||
| 899 | |||
| 900 | if (!makeFilesWritable($writable_files)) |
||
| 901 | return false; |
||
| 902 | |||
| 903 | // Check agreement.txt. (it may not exist, in which case $boarddir must be writable.) |
||
| 904 | if (isset($modSettings['agreement']) && (!is_writable($boarddir) || file_exists($boarddir . '/agreement.txt')) && !is_writable($boarddir . '/agreement.txt')) |
||
| 905 | return throw_error($txt['error_agreement_not_writable']); |
||
| 906 | |||
| 907 | // Upgrade the agreement. |
||
| 908 | elseif (isset($modSettings['agreement'])) |
||
| 909 | { |
||
| 910 | $fp = fopen($boarddir . '/agreement.txt', 'w'); |
||
| 911 | fwrite($fp, $modSettings['agreement']); |
||
| 912 | fclose($fp); |
||
| 913 | } |
||
| 914 | |||
| 915 | // We're going to check that their board dir setting is right in case they've been moving stuff around. |
||
| 916 | if (strtr($boarddir, array('/' => '', '\\' => '')) != strtr(dirname(__FILE__), array('/' => '', '\\' => ''))) |
||
| 917 | $upcontext['warning'] = ' |
||
| 918 | ' . sprintf($txt['upgrade_boarddir_settings'], $boarddir, dirname(__FILE__)) . '<br> |
||
| 919 | <ul> |
||
| 920 | <li>' . $txt['upgrade_boarddir'] . ' ' . $boarddir . '</li> |
||
| 921 | <li>' . $txt['upgrade_sourcedir'] . ' ' . $boarddir . '</li> |
||
| 922 | <li>' . $txt['upgrade_cachedir'] . ' ' . $cachedir_temp . '</li> |
||
| 923 | </ul> |
||
| 924 | ' . $txt['upgrade_incorrect_settings'] . ''; |
||
| 925 | |||
| 926 | // Confirm mbstring is loaded... |
||
| 927 | if (!extension_loaded('mbstring')) |
||
| 928 | return throw_error($txt['install_no_mbstring']); |
||
| 929 | |||
| 930 | // Check for https stream support. |
||
| 931 | $supported_streams = stream_get_wrappers(); |
||
| 932 | if (!in_array('https', $supported_streams)) |
||
| 933 | $upcontext['custom_warning'] = $txt['install_no_https']; |
||
| 934 | |||
| 935 | // Either we're logged in or we're going to present the login. |
||
| 936 | if (checkLogin()) |
||
| 937 | return true; |
||
| 938 | |||
| 939 | $upcontext += createToken('login'); |
||
| 940 | |||
| 941 | return false; |
||
| 942 | } |
||
| 943 | |||
| 944 | // Step 0.5: Does the login work? |
||
| 945 | function checkLogin() |
||
| 946 | { |
||
| 947 | global $modSettings, $upcontext, $disable_security; |
||
| 948 | global $smcFunc, $db_type, $support_js, $sourcedir; |
||
| 949 | |||
| 950 | // Don't bother if the security is disabled. |
||
| 951 | if ($disable_security) |
||
| 952 | return true; |
||
| 953 | |||
| 954 | // Are we trying to login? |
||
| 955 | if (isset($_POST['contbutt']) && (!empty($_POST['user']))) |
||
| 956 | { |
||
| 957 | // If we've disabled security pick a suitable name! |
||
| 958 | if (empty($_POST['user'])) |
||
| 959 | $_POST['user'] = 'Administrator'; |
||
| 960 | |||
| 961 | // Before 2.0 these column names were different! |
||
| 962 | $oldDB = false; |
||
| 963 | if (empty($db_type) || $db_type == 'mysql') |
||
| 964 | { |
||
| 965 | $request = $smcFunc['db_query']('', ' |
||
| 966 | SHOW COLUMNS |
||
| 967 | FROM {db_prefix}members |
||
| 968 | LIKE {string:member_name}', |
||
| 969 | array( |
||
| 970 | 'member_name' => 'memberName', |
||
| 971 | 'db_error_skip' => true, |
||
| 972 | ) |
||
| 973 | ); |
||
| 974 | if ($smcFunc['db_num_rows']($request) != 0) |
||
| 975 | $oldDB = true; |
||
| 976 | $smcFunc['db_free_result']($request); |
||
| 977 | } |
||
| 978 | |||
| 979 | // Get what we believe to be their details. |
||
| 980 | if (!$disable_security) |
||
| 981 | { |
||
| 982 | if ($oldDB) |
||
| 983 | $request = $smcFunc['db_query']('', ' |
||
| 984 | SELECT id_member, memberName AS member_name, passwd, id_group, |
||
| 985 | additionalGroups AS additional_groups, lngfile |
||
| 986 | FROM {db_prefix}members |
||
| 987 | WHERE memberName = {string:member_name}', |
||
| 988 | array( |
||
| 989 | 'member_name' => $_POST['user'], |
||
| 990 | 'db_error_skip' => true, |
||
| 991 | ) |
||
| 992 | ); |
||
| 993 | else |
||
| 994 | $request = $smcFunc['db_query']('', ' |
||
| 995 | SELECT id_member, member_name, passwd, id_group, additional_groups, lngfile |
||
| 996 | FROM {db_prefix}members |
||
| 997 | WHERE member_name = {string:member_name}', |
||
| 998 | array( |
||
| 999 | 'member_name' => $_POST['user'], |
||
| 1000 | 'db_error_skip' => true, |
||
| 1001 | ) |
||
| 1002 | ); |
||
| 1003 | if ($smcFunc['db_num_rows']($request) != 0) |
||
| 1004 | { |
||
| 1005 | list ($id_member, $name, $password, $id_group, $addGroups, $user_language) = $smcFunc['db_fetch_row']($request); |
||
| 1006 | |||
| 1007 | $groups = explode(',', $addGroups); |
||
| 1008 | $groups[] = $id_group; |
||
| 1009 | |||
| 1010 | foreach ($groups as $k => $v) |
||
| 1011 | $groups[$k] = (int) $v; |
||
| 1012 | |||
| 1013 | $sha_passwd = sha1(strtolower($name) . un_htmlspecialchars($_REQUEST['passwrd'])); |
||
| 1014 | |||
| 1015 | // We don't use "-utf8" anymore... |
||
| 1016 | $user_language = str_ireplace('-utf8', '', $user_language); |
||
| 1017 | } |
||
| 1018 | else |
||
| 1019 | $upcontext['username_incorrect'] = true; |
||
| 1020 | |||
| 1021 | $smcFunc['db_free_result']($request); |
||
| 1022 | } |
||
| 1023 | $upcontext['username'] = $_POST['user']; |
||
| 1024 | |||
| 1025 | // Track whether javascript works! |
||
| 1026 | if (!empty($_POST['js_works'])) |
||
| 1027 | { |
||
| 1028 | $upcontext['upgrade_status']['js'] = 1; |
||
| 1029 | $support_js = 1; |
||
| 1030 | } |
||
| 1031 | else |
||
| 1032 | $support_js = 0; |
||
| 1033 | |||
| 1034 | // Note down the version we are coming from. |
||
| 1035 | if (!empty($modSettings['smfVersion']) && empty($upcontext['user']['version'])) |
||
| 1036 | $upcontext['user']['version'] = $modSettings['smfVersion']; |
||
| 1037 | |||
| 1038 | // Didn't get anywhere? |
||
| 1039 | if (!$disable_security && (empty($sha_passwd) || (!empty($password) ? $password : '') != $sha_passwd) && !hash_verify_password((!empty($name) ? $name : ''), $_REQUEST['passwrd'], (!empty($password) ? $password : '')) && empty($upcontext['username_incorrect'])) |
||
| 1040 | { |
||
| 1041 | // MD5? |
||
| 1042 | $md5pass = md5_hmac($_REQUEST['passwrd'], strtolower($_POST['user'])); |
||
| 1043 | if ($md5pass != $password) |
||
| 1044 | { |
||
| 1045 | $upcontext['password_failed'] = true; |
||
| 1046 | // Disable the hashing this time. |
||
| 1047 | $upcontext['disable_login_hashing'] = true; |
||
| 1048 | } |
||
| 1049 | } |
||
| 1050 | |||
| 1051 | if ((empty($upcontext['password_failed']) && !empty($name)) || $disable_security) |
||
| 1052 | { |
||
| 1053 | // Set the password. |
||
| 1054 | if (!$disable_security) |
||
| 1055 | { |
||
| 1056 | // Do we actually have permission? |
||
| 1057 | if (!in_array(1, $groups)) |
||
| 1058 | { |
||
| 1059 | $request = $smcFunc['db_query']('', ' |
||
| 1060 | SELECT permission |
||
| 1061 | FROM {db_prefix}permissions |
||
| 1062 | WHERE id_group IN ({array_int:groups}) |
||
| 1063 | AND permission = {string:admin_forum}', |
||
| 1064 | array( |
||
| 1065 | 'groups' => $groups, |
||
| 1066 | 'admin_forum' => 'admin_forum', |
||
| 1067 | 'db_error_skip' => true, |
||
| 1068 | ) |
||
| 1069 | ); |
||
| 1070 | if ($smcFunc['db_num_rows']($request) == 0) |
||
| 1071 | return throw_error($txt['error_not_admin']); |
||
| 1072 | $smcFunc['db_free_result']($request); |
||
| 1073 | } |
||
| 1074 | |||
| 1075 | $upcontext['user']['id'] = $id_member; |
||
| 1076 | $upcontext['user']['name'] = $name; |
||
| 1077 | } |
||
| 1078 | else |
||
| 1079 | { |
||
| 1080 | $upcontext['user']['id'] = 1; |
||
| 1081 | $upcontext['user']['name'] = 'Administrator'; |
||
| 1082 | } |
||
| 1083 | |||
| 1084 | if (!is_callable('random_int')) |
||
| 1085 | require_once('Sources/random_compat/random.php'); |
||
| 1086 | |||
| 1087 | $upcontext['user']['pass'] = random_int(0, 60000); |
||
| 1088 | // This basically is used to match the GET variables to Settings.php. |
||
| 1089 | $upcontext['upgrade_status']['pass'] = $upcontext['user']['pass']; |
||
| 1090 | |||
| 1091 | // Set the language to that of the user? |
||
| 1092 | if (isset($user_language) && $user_language != $upcontext['language'] && file_exists($modSettings['theme_dir'] . '/languages/index.' . basename($user_language, '.lng') . '.php')) |
||
| 1093 | { |
||
| 1094 | $user_language = basename($user_language, '.lng'); |
||
| 1095 | $temp = substr(@implode('', @file($modSettings['theme_dir'] . '/languages/index.' . $user_language . '.php')), 0, 4096); |
||
| 1096 | preg_match('~(?://|/\*)\s*Version:\s+(.+?);\s*index(?:[\s]{2}|\*/)~i', $temp, $match); |
||
| 1097 | |||
| 1098 | if (empty($match[1]) || $match[1] != SMF_LANG_VERSION) |
||
| 1099 | $upcontext['upgrade_options_warning'] = sprintf($txt['warning_lang_old'], $user_language, $upcontext['language']); |
||
| 1100 | elseif (!file_exists($modSettings['theme_dir'] . '/languages/Install.' . $user_language . '.php')) |
||
| 1101 | $upcontext['upgrade_options_warning'] = sprintf($txt['warning_lang_missing'], $user_language, $upcontext['language']); |
||
| 1102 | else |
||
| 1103 | { |
||
| 1104 | // Set this as the new language. |
||
| 1105 | $upcontext['language'] = $user_language; |
||
| 1106 | $upcontext['upgrade_status']['lang'] = $upcontext['language']; |
||
| 1107 | |||
| 1108 | // Include the file. |
||
| 1109 | load_lang_file(); |
||
| 1110 | } |
||
| 1111 | } |
||
| 1112 | |||
| 1113 | // If we're resuming set the step and substep to be correct. |
||
| 1114 | if (isset($_POST['cont'])) |
||
| 1115 | { |
||
| 1116 | $upcontext['current_step'] = $upcontext['user']['step']; |
||
| 1117 | $_GET['substep'] = $upcontext['user']['substep']; |
||
| 1118 | } |
||
| 1119 | |||
| 1120 | return true; |
||
| 1121 | } |
||
| 1122 | } |
||
| 1123 | |||
| 1124 | return false; |
||
| 1125 | } |
||
| 1126 | |||
| 1127 | // Step 1: Do the maintenance and backup. |
||
| 1128 | function UpgradeOptions() |
||
| 1129 | { |
||
| 1130 | global $db_prefix, $command_line, $modSettings, $is_debug, $smcFunc, $packagesdir, $tasksdir, $language, $txt; |
||
| 1131 | global $boarddir, $boardurl, $sourcedir, $maintenance, $cachedir, $upcontext, $db_type, $db_server, $image_proxy_enabled; |
||
| 1132 | |||
| 1133 | $upcontext['sub_template'] = 'upgrade_options'; |
||
| 1134 | $upcontext['page_title'] = $txt['upgrade_options']; |
||
| 1135 | |||
| 1136 | db_extend('packages'); |
||
| 1137 | $upcontext['karma_installed'] = array('good' => false, 'bad' => false); |
||
| 1138 | $member_columns = $smcFunc['db_list_columns']('{db_prefix}members'); |
||
| 1139 | |||
| 1140 | $upcontext['karma_installed']['good'] = in_array('karma_good', $member_columns); |
||
| 1141 | $upcontext['karma_installed']['bad'] = in_array('karma_bad', $member_columns); |
||
| 1142 | |||
| 1143 | unset($member_columns); |
||
| 1144 | |||
| 1145 | // If these options are missing, we may need to migrate to a new Settings.php |
||
| 1146 | $upcontext['migrateSettingsNeeded'] = detectSettingsFileMigrationNeeded() ? 1 : 0; |
||
| 1147 | |||
| 1148 | // If we've not submitted then we're done. |
||
| 1149 | if (empty($_POST['upcont'])) |
||
| 1150 | return false; |
||
| 1151 | |||
| 1152 | // Firstly, if they're enabling SM stat collection just do it. |
||
| 1153 | if (!empty($_POST['stats']) && substr($boardurl, 0, 16) != 'http://localhost' && empty($modSettings['allow_sm_stats']) && empty($modSettings['enable_sm_stats'])) |
||
| 1154 | { |
||
| 1155 | $upcontext['allow_sm_stats'] = true; |
||
| 1156 | |||
| 1157 | // Don't register if we still have a key. |
||
| 1158 | if (empty($modSettings['sm_stats_key'])) |
||
| 1159 | { |
||
| 1160 | // Attempt to register the site etc. |
||
| 1161 | $fp = @fsockopen('www.simplemachines.org', 80, $errno, $errstr); |
||
| 1162 | if ($fp) |
||
| 1163 | { |
||
| 1164 | $out = 'GET /smf/stats/register_stats.php?site=' . base64_encode($boardurl) . ' HTTP/1.1' . "\r\n"; |
||
| 1165 | $out .= 'Host: www.simplemachines.org' . "\r\n"; |
||
| 1166 | $out .= 'Connection: Close' . "\r\n\r\n"; |
||
| 1167 | fwrite($fp, $out); |
||
| 1168 | |||
| 1169 | $return_data = ''; |
||
| 1170 | while (!feof($fp)) |
||
| 1171 | $return_data .= fgets($fp, 128); |
||
| 1172 | |||
| 1173 | fclose($fp); |
||
| 1174 | |||
| 1175 | // Get the unique site ID. |
||
| 1176 | preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID); |
||
| 1177 | |||
| 1178 | if (!empty($ID[1])) |
||
| 1179 | $smcFunc['db_insert']('replace', |
||
| 1180 | $db_prefix . 'settings', |
||
| 1181 | array('variable' => 'string', 'value' => 'string'), |
||
| 1182 | array( |
||
| 1183 | array('sm_stats_key', $ID[1]), |
||
| 1184 | array('enable_sm_stats', 1), |
||
| 1185 | ), |
||
| 1186 | array('variable') |
||
| 1187 | ); |
||
| 1188 | } |
||
| 1189 | } |
||
| 1190 | else |
||
| 1191 | { |
||
| 1192 | $smcFunc['db_insert']('replace', |
||
| 1193 | $db_prefix . 'settings', |
||
| 1194 | array('variable' => 'string', 'value' => 'string'), |
||
| 1195 | array('enable_sm_stats', 1), |
||
| 1196 | array('variable') |
||
| 1197 | ); |
||
| 1198 | } |
||
| 1199 | } |
||
| 1200 | // Don't remove stat collection unless we unchecked the box for real, not from the loop. |
||
| 1201 | elseif (empty($_POST['stats']) && empty($upcontext['allow_sm_stats'])) |
||
| 1202 | $smcFunc['db_query']('', ' |
||
| 1203 | DELETE FROM {db_prefix}settings |
||
| 1204 | WHERE variable = {string:enable_sm_stats}', |
||
| 1205 | array( |
||
| 1206 | 'enable_sm_stats' => 'enable_sm_stats', |
||
| 1207 | 'db_error_skip' => true, |
||
| 1208 | ) |
||
| 1209 | ); |
||
| 1210 | |||
| 1211 | // Deleting old karma stuff? |
||
| 1212 | if (!empty($_POST['delete_karma'])) |
||
| 1213 | { |
||
| 1214 | // Delete old settings vars. |
||
| 1215 | $smcFunc['db_query']('', ' |
||
| 1216 | DELETE FROM {db_prefix}settings |
||
| 1217 | WHERE variable IN ({array_string:karma_vars})', |
||
| 1218 | array( |
||
| 1219 | 'karma_vars' => array('karmaMode', 'karmaTimeRestrictAdmins', 'karmaWaitTime', 'karmaMinPosts', 'karmaLabel', 'karmaSmiteLabel', 'karmaApplaudLabel'), |
||
| 1220 | ) |
||
| 1221 | ); |
||
| 1222 | |||
| 1223 | // Cleaning up old karma member settings. |
||
| 1224 | if ($upcontext['karma_installed']['good']) |
||
| 1225 | $smcFunc['db_query']('', ' |
||
| 1226 | ALTER TABLE {db_prefix}members |
||
| 1227 | DROP karma_good', |
||
| 1228 | array() |
||
| 1229 | ); |
||
| 1230 | |||
| 1231 | // Does karma bad was enable? |
||
| 1232 | if ($upcontext['karma_installed']['bad']) |
||
| 1233 | $smcFunc['db_query']('', ' |
||
| 1234 | ALTER TABLE {db_prefix}members |
||
| 1235 | DROP karma_bad', |
||
| 1236 | array() |
||
| 1237 | ); |
||
| 1238 | |||
| 1239 | // Cleaning up old karma permissions. |
||
| 1240 | $smcFunc['db_query']('', ' |
||
| 1241 | DELETE FROM {db_prefix}permissions |
||
| 1242 | WHERE permission = {string:karma_vars}', |
||
| 1243 | array( |
||
| 1244 | 'karma_vars' => 'karma_edit', |
||
| 1245 | ) |
||
| 1246 | ); |
||
| 1247 | // Cleaning up old log_karma table |
||
| 1248 | $smcFunc['db_query']('', ' |
||
| 1249 | DROP TABLE IF EXISTS {db_prefix}log_karma', |
||
| 1250 | array() |
||
| 1251 | ); |
||
| 1252 | } |
||
| 1253 | |||
| 1254 | // Emptying the error log? |
||
| 1255 | if (!empty($_POST['empty_error'])) |
||
| 1256 | $smcFunc['db_query']('truncate_table', ' |
||
| 1257 | TRUNCATE {db_prefix}log_errors', |
||
| 1258 | array( |
||
| 1259 | ) |
||
| 1260 | ); |
||
| 1261 | |||
| 1262 | $changes = array(); |
||
| 1263 | |||
| 1264 | // Add proxy settings. |
||
| 1265 | if (!isset($GLOBALS['image_proxy_maxsize'])) |
||
| 1266 | $changes += array( |
||
| 1267 | 'image_proxy_secret' => '\'' . substr(sha1(mt_rand()), 0, 20) . '\'', |
||
| 1268 | 'image_proxy_maxsize' => 5190, |
||
| 1269 | 'image_proxy_enabled' => 0, |
||
| 1270 | ); |
||
| 1271 | |||
| 1272 | // If $boardurl reflects https, set force_ssl |
||
| 1273 | if (!function_exists('cache_put_data')) |
||
| 1274 | require_once($sourcedir . '/Load.php'); |
||
| 1275 | if (stripos($boardurl, 'https://') !== false) |
||
| 1276 | updateSettings(array('force_ssl' => '1')); |
||
| 1277 | |||
| 1278 | // If we're overriding the language follow it through. |
||
| 1279 | if (isset($upcontext['lang']) && file_exists($modSettings['theme_dir'] . '/languages/index.' . $upcontext['lang'] . '.php')) |
||
| 1280 | $changes['language'] = '\'' . $upcontext['lang'] . '\''; |
||
| 1281 | |||
| 1282 | if (!empty($_POST['maint'])) |
||
| 1283 | { |
||
| 1284 | $changes['maintenance'] = '2'; |
||
| 1285 | // Remember what it was... |
||
| 1286 | $upcontext['user']['main'] = $maintenance; |
||
| 1287 | |||
| 1288 | if (!empty($_POST['maintitle'])) |
||
| 1289 | { |
||
| 1290 | $changes['mtitle'] = '\'' . addslashes($_POST['maintitle']) . '\''; |
||
| 1291 | $changes['mmessage'] = '\'' . addslashes($_POST['mainmessage']) . '\''; |
||
| 1292 | } |
||
| 1293 | else |
||
| 1294 | { |
||
| 1295 | $changes['mtitle'] = '\'' . addslashes($txt['mtitle']) . '\''; |
||
| 1296 | $changes['mmessage'] = '\'' . addslashes($txt['mmessage']) . '\''; |
||
| 1297 | } |
||
| 1298 | } |
||
| 1299 | |||
| 1300 | if ($command_line) |
||
| 1301 | echo ' * Updating Settings.php...'; |
||
| 1302 | |||
| 1303 | // Fix some old paths. |
||
| 1304 | if (substr($boarddir, 0, 1) == '.') |
||
| 1305 | $changes['boarddir'] = '\'' . fixRelativePath($boarddir) . '\''; |
||
| 1306 | |||
| 1307 | if (substr($sourcedir, 0, 1) == '.') |
||
| 1308 | $changes['sourcedir'] = '\'' . fixRelativePath($sourcedir) . '\''; |
||
| 1309 | |||
| 1310 | if (empty($cachedir) || substr($cachedir, 0, 1) == '.') |
||
| 1311 | $changes['cachedir'] = '\'' . fixRelativePath($boarddir) . '/cache\''; |
||
| 1312 | |||
| 1313 | // If they have a "host:port" setup for the host, split that into separate values |
||
| 1314 | // You should never have a : in the hostname if you're not on MySQL, but better safe than sorry |
||
| 1315 | if (strpos($db_server, ':') !== false && $db_type == 'mysql') |
||
| 1316 | { |
||
| 1317 | list ($db_server, $db_port) = explode(':', $db_server); |
||
| 1318 | |||
| 1319 | $changes['db_server'] = '\'' . $db_server . '\''; |
||
| 1320 | |||
| 1321 | // Only set this if we're not using the default port |
||
| 1322 | if ($db_port != ini_get('mysqli.default_port')) |
||
| 1323 | $changes['db_port'] = (int) $db_port; |
||
| 1324 | } |
||
| 1325 | elseif (!empty($db_port)) |
||
| 1326 | { |
||
| 1327 | // If db_port is set and is the same as the default, set it to '' |
||
| 1328 | if ($db_type == 'mysql') |
||
| 1329 | { |
||
| 1330 | if ($db_port == ini_get('mysqli.default_port')) |
||
| 1331 | $changes['db_port'] = '\'\''; |
||
| 1332 | elseif ($db_type == 'postgresql' && $db_port == 5432) |
||
| 1333 | $changes['db_port'] = '\'\''; |
||
| 1334 | } |
||
| 1335 | } |
||
| 1336 | |||
| 1337 | // Maybe we haven't had this option yet? |
||
| 1338 | if (empty($packagesdir)) |
||
| 1339 | $changes['packagesdir'] = '\'' . fixRelativePath($boarddir) . '/Packages\''; |
||
| 1340 | |||
| 1341 | // Add support for $tasksdir var. |
||
| 1342 | if (empty($tasksdir)) |
||
| 1343 | $changes['tasksdir'] = '\'' . fixRelativePath($sourcedir) . '/tasks\''; |
||
| 1344 | |||
| 1345 | // Make sure we fix the language as well. |
||
| 1346 | if (stristr($language, '-utf8')) |
||
| 1347 | $changes['language'] = '\'' . str_ireplace('-utf8', '', $language) . '\''; |
||
| 1348 | |||
| 1349 | // @todo Maybe change the cookie name if going to 1.1, too? |
||
| 1350 | |||
| 1351 | // If we are migrating the settings, get them ready. |
||
| 1352 | if (!empty($_POST['migrateSettings'])) |
||
| 1353 | { |
||
| 1354 | // Ensure this doesn't get lost in translation. |
||
| 1355 | $changes['upgradeData'] = '"' . base64_encode(json_encode($upcontext['user'])) . '"'; |
||
| 1356 | |||
| 1357 | migrateSettingsFile($changes); |
||
| 1358 | } |
||
| 1359 | else |
||
| 1360 | { |
||
| 1361 | // Update Settings.php with the new settings. |
||
| 1362 | require_once($sourcedir . '/Subs-Admin.php'); |
||
| 1363 | updateSettingsFile($changes); |
||
| 1364 | |||
| 1365 | // Tell Settings.php to store db_last_error.php in the cache |
||
| 1366 | move_db_last_error_to_cachedir(); |
||
| 1367 | } |
||
| 1368 | |||
| 1369 | if ($command_line) |
||
| 1370 | echo ' Successful.' . "\n"; |
||
| 1371 | |||
| 1372 | // Are we doing debug? |
||
| 1373 | if (isset($_POST['debug'])) |
||
| 1374 | { |
||
| 1375 | $upcontext['upgrade_status']['debug'] = true; |
||
| 1376 | $is_debug = true; |
||
| 1377 | } |
||
| 1378 | |||
| 1379 | // If we're not backing up then jump one. |
||
| 1380 | if (empty($_POST['backup'])) |
||
| 1381 | $upcontext['current_step']++; |
||
| 1382 | |||
| 1383 | // If we've got here then let's proceed to the next step! |
||
| 1384 | return true; |
||
| 1385 | } |
||
| 1386 | |||
| 1387 | // Backup the database - why not... |
||
| 1388 | function BackupDatabase() |
||
| 1389 | { |
||
| 1390 | global $upcontext, $db_prefix, $command_line, $support_js, $file_steps, $smcFunc, $txt; |
||
| 1391 | |||
| 1392 | $upcontext['sub_template'] = isset($_GET['xml']) ? 'backup_xml' : 'backup_database'; |
||
| 1393 | $upcontext['page_title'] = $txt['backup_database']; |
||
| 1394 | |||
| 1395 | // Done it already - js wise? |
||
| 1396 | if (!empty($_POST['backup_done'])) |
||
| 1397 | return true; |
||
| 1398 | |||
| 1399 | // Some useful stuff here. |
||
| 1400 | db_extend(); |
||
| 1401 | |||
| 1402 | // Might need this as well |
||
| 1403 | db_extend('packages'); |
||
| 1404 | |||
| 1405 | // Get all the table names. |
||
| 1406 | $filter = str_replace('_', '\_', preg_match('~^`(.+?)`\.(.+?)$~', $db_prefix, $match) != 0 ? $match[2] : $db_prefix) . '%'; |
||
| 1407 | $db = preg_match('~^`(.+?)`\.(.+?)$~', $db_prefix, $match) != 0 ? strtr($match[1], array('`' => '')) : false; |
||
| 1408 | $tables = $smcFunc['db_list_tables']($db, $filter); |
||
| 1409 | |||
| 1410 | $table_names = array(); |
||
| 1411 | foreach ($tables as $table) |
||
| 1412 | if (substr($table, 0, 7) !== 'backup_') |
||
| 1413 | $table_names[] = $table; |
||
| 1414 | |||
| 1415 | $upcontext['table_count'] = count($table_names); |
||
| 1416 | $upcontext['cur_table_num'] = $_GET['substep']; |
||
| 1417 | $upcontext['cur_table_name'] = str_replace($db_prefix, '', isset($table_names[$_GET['substep']]) ? $table_names[$_GET['substep']] : $table_names[0]); |
||
| 1418 | $upcontext['step_progress'] = (int) (($upcontext['cur_table_num'] / $upcontext['table_count']) * 100); |
||
| 1419 | // For non-java auto submit... |
||
| 1420 | $file_steps = $upcontext['table_count']; |
||
| 1421 | |||
| 1422 | // What ones have we already done? |
||
| 1423 | foreach ($table_names as $id => $table) |
||
| 1424 | if ($id < $_GET['substep']) |
||
| 1425 | $upcontext['previous_tables'][] = $table; |
||
| 1426 | |||
| 1427 | if ($command_line) |
||
| 1428 | echo 'Backing Up Tables.'; |
||
| 1429 | |||
| 1430 | // If we don't support javascript we backup here. |
||
| 1431 | if (!$support_js || isset($_GET['xml'])) |
||
| 1432 | { |
||
| 1433 | // Backup each table! |
||
| 1434 | for ($substep = $_GET['substep'], $n = count($table_names); $substep < $n; $substep++) |
||
| 1435 | { |
||
| 1436 | $upcontext['cur_table_name'] = str_replace($db_prefix, '', (isset($table_names[$substep + 1]) ? $table_names[$substep + 1] : $table_names[$substep])); |
||
| 1437 | $upcontext['cur_table_num'] = $substep + 1; |
||
| 1438 | |||
| 1439 | $upcontext['step_progress'] = (int) (($upcontext['cur_table_num'] / $upcontext['table_count']) * 100); |
||
| 1440 | |||
| 1441 | // Do we need to pause? |
||
| 1442 | nextSubstep($substep); |
||
| 1443 | |||
| 1444 | backupTable($table_names[$substep]); |
||
| 1445 | |||
| 1446 | // If this is XML to keep it nice for the user do one table at a time anyway! |
||
| 1447 | if (isset($_GET['xml'])) |
||
| 1448 | return upgradeExit(); |
||
| 1449 | } |
||
| 1450 | |||
| 1451 | if ($command_line) |
||
| 1452 | { |
||
| 1453 | echo "\n" . ' Successful.\'' . "\n"; |
||
| 1454 | flush(); |
||
| 1455 | } |
||
| 1456 | $upcontext['step_progress'] = 100; |
||
| 1457 | |||
| 1458 | $_GET['substep'] = 0; |
||
| 1459 | // Make sure we move on! |
||
| 1460 | return true; |
||
| 1461 | } |
||
| 1462 | |||
| 1463 | // Either way next place to post will be database changes! |
||
| 1464 | $_GET['substep'] = 0; |
||
| 1465 | return false; |
||
| 1466 | } |
||
| 1467 | |||
| 1468 | // Backup one table... |
||
| 1469 | function backupTable($table) |
||
| 1470 | { |
||
| 1471 | global $command_line, $db_prefix, $smcFunc; |
||
| 1472 | |||
| 1473 | if ($command_line) |
||
| 1474 | { |
||
| 1475 | echo "\n" . ' +++ Backing up \"' . str_replace($db_prefix, '', $table) . '"...'; |
||
| 1476 | flush(); |
||
| 1477 | } |
||
| 1478 | |||
| 1479 | $smcFunc['db_backup_table']($table, 'backup_' . $table); |
||
| 1480 | |||
| 1481 | if ($command_line) |
||
| 1482 | echo ' done.'; |
||
| 1483 | } |
||
| 1484 | |||
| 1485 | // Step 2: Everything. |
||
| 1486 | function DatabaseChanges() |
||
| 1487 | { |
||
| 1488 | global $db_prefix, $modSettings, $smcFunc, $txt; |
||
| 1489 | global $upcontext, $support_js, $db_type; |
||
| 1490 | |||
| 1491 | // Have we just completed this? |
||
| 1492 | if (!empty($_POST['database_done'])) |
||
| 1493 | return true; |
||
| 1494 | |||
| 1495 | $upcontext['sub_template'] = isset($_GET['xml']) ? 'database_xml' : 'database_changes'; |
||
| 1496 | $upcontext['page_title'] = $txt['database_changes']; |
||
| 1497 | |||
| 1498 | // All possible files. |
||
| 1499 | // Name, < version, insert_on_complete |
||
| 1500 | $files = array( |
||
| 1501 | array('upgrade_1-0.sql', '1.1', '1.1 RC0'), |
||
| 1502 | array('upgrade_1-1.sql', '2.0', '2.0 a'), |
||
| 1503 | array('upgrade_2-0_' . $db_type . '.sql', '2.1', '2.1 dev0'), |
||
| 1504 | array('upgrade_2-1_' . $db_type . '.sql', '3.0', SMF_VERSION), |
||
| 1505 | ); |
||
| 1506 | |||
| 1507 | // How many files are there in total? |
||
| 1508 | if (isset($_GET['filecount'])) |
||
| 1509 | $upcontext['file_count'] = (int) $_GET['filecount']; |
||
| 1510 | else |
||
| 1511 | { |
||
| 1512 | $upcontext['file_count'] = 0; |
||
| 1513 | foreach ($files as $file) |
||
| 1514 | { |
||
| 1515 | if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < $file[1]) |
||
| 1516 | $upcontext['file_count']++; |
||
| 1517 | } |
||
| 1518 | } |
||
| 1519 | |||
| 1520 | // Do each file! |
||
| 1521 | $did_not_do = count($files) - $upcontext['file_count']; |
||
| 1522 | $upcontext['step_progress'] = 0; |
||
| 1523 | $upcontext['cur_file_num'] = 0; |
||
| 1524 | foreach ($files as $file) |
||
| 1525 | { |
||
| 1526 | if ($did_not_do) |
||
| 1527 | $did_not_do--; |
||
| 1528 | else |
||
| 1529 | { |
||
| 1530 | $upcontext['cur_file_num']++; |
||
| 1531 | $upcontext['cur_file_name'] = $file[0]; |
||
| 1532 | // Do we actually need to do this still? |
||
| 1533 | if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < $file[1]) |
||
| 1534 | { |
||
| 1535 | $nextFile = parse_sql(dirname(__FILE__) . '/' . $file[0]); |
||
| 1536 | if ($nextFile) |
||
| 1537 | { |
||
| 1538 | // Only update the version of this if complete. |
||
| 1539 | $smcFunc['db_insert']('replace', |
||
| 1540 | $db_prefix . 'settings', |
||
| 1541 | array('variable' => 'string', 'value' => 'string'), |
||
| 1542 | array('smfVersion', $file[2]), |
||
| 1543 | array('variable') |
||
| 1544 | ); |
||
| 1545 | |||
| 1546 | $modSettings['smfVersion'] = $file[2]; |
||
| 1547 | } |
||
| 1548 | |||
| 1549 | // If this is XML we only do this stuff once. |
||
| 1550 | if (isset($_GET['xml'])) |
||
| 1551 | { |
||
| 1552 | // Flag to move on to the next. |
||
| 1553 | $upcontext['completed_step'] = true; |
||
| 1554 | // Did we complete the whole file? |
||
| 1555 | if ($nextFile) |
||
| 1556 | $upcontext['current_debug_item_num'] = -1; |
||
| 1557 | return upgradeExit(); |
||
| 1558 | } |
||
| 1559 | elseif ($support_js) |
||
| 1560 | break; |
||
| 1561 | } |
||
| 1562 | // Set the progress bar to be right as if we had - even if we hadn't... |
||
| 1563 | $upcontext['step_progress'] = ($upcontext['cur_file_num'] / $upcontext['file_count']) * 100; |
||
| 1564 | } |
||
| 1565 | } |
||
| 1566 | |||
| 1567 | $_GET['substep'] = 0; |
||
| 1568 | // So the template knows we're done. |
||
| 1569 | if (!$support_js) |
||
| 1570 | { |
||
| 1571 | $upcontext['changes_complete'] = true; |
||
| 1572 | |||
| 1573 | return true; |
||
| 1574 | } |
||
| 1575 | return false; |
||
| 1576 | } |
||
| 1577 | |||
| 1578 | // Delete the damn thing! |
||
| 1579 | function DeleteUpgrade() |
||
| 1580 | { |
||
| 1581 | global $command_line, $language, $upcontext, $sourcedir; |
||
| 1582 | global $user_info, $maintenance, $smcFunc, $db_type, $txt, $settings; |
||
| 1583 | |||
| 1584 | // Now it's nice to have some of the basic SMF source files. |
||
| 1585 | if (!isset($_GET['ssi']) && !$command_line) |
||
| 1586 | redirectLocation('&ssi=1'); |
||
| 1587 | |||
| 1588 | $upcontext['sub_template'] = 'upgrade_complete'; |
||
| 1589 | $upcontext['page_title'] = $txt['upgrade_complete']; |
||
| 1590 | |||
| 1591 | $endl = $command_line ? "\n" : '<br>' . "\n"; |
||
| 1592 | |||
| 1593 | $changes = array( |
||
| 1594 | 'language' => '\'' . (substr($language, -4) == '.lng' ? substr($language, 0, -4) : $language) . '\'', |
||
| 1595 | 'db_error_send' => '1', |
||
| 1596 | 'upgradeData' => '\'\'', |
||
| 1597 | ); |
||
| 1598 | |||
| 1599 | // Are we in maintenance mode? |
||
| 1600 | if (isset($upcontext['user']['main'])) |
||
| 1601 | { |
||
| 1602 | if ($command_line) |
||
| 1603 | echo ' * '; |
||
| 1604 | $upcontext['removed_maintenance'] = true; |
||
| 1605 | $changes['maintenance'] = $upcontext['user']['main']; |
||
| 1606 | } |
||
| 1607 | // Otherwise if somehow we are in 2 let's go to 1. |
||
| 1608 | elseif (!empty($maintenance) && $maintenance == 2) |
||
| 1609 | $changes['maintenance'] = 1; |
||
| 1610 | |||
| 1611 | // Wipe this out... |
||
| 1612 | $upcontext['user'] = array(); |
||
| 1613 | |||
| 1614 | require_once($sourcedir . '/Subs-Admin.php'); |
||
| 1615 | updateSettingsFile($changes); |
||
| 1616 | |||
| 1617 | // Clean any old cache files away. |
||
| 1618 | upgrade_clean_cache(); |
||
| 1619 | |||
| 1620 | // Can we delete the file? |
||
| 1621 | $upcontext['can_delete_script'] = is_writable(dirname(__FILE__)) || is_writable(__FILE__); |
||
| 1622 | |||
| 1623 | // Now is the perfect time to fetch the SM files. |
||
| 1624 | if ($command_line) |
||
| 1625 | cli_scheduled_fetchSMfiles(); |
||
| 1626 | else |
||
| 1627 | { |
||
| 1628 | require_once($sourcedir . '/ScheduledTasks.php'); |
||
| 1629 | scheduled_fetchSMfiles(); // Now go get those files! |
||
| 1630 | // This is needed in case someone invokes the upgrader using https when upgrading an http forum |
||
| 1631 | if (httpsOn()) |
||
| 1632 | $settings['default_theme_url'] = strtr($settings['default_theme_url'], array('http://' => 'https://')); |
||
| 1633 | } |
||
| 1634 | |||
| 1635 | // Log what we've done. |
||
| 1636 | if (empty($user_info['id'])) |
||
| 1637 | $user_info['id'] = !empty($upcontext['user']['id']) ? $upcontext['user']['id'] : 0; |
||
| 1638 | |||
| 1639 | // Log the action manually, so CLI still works. |
||
| 1640 | $smcFunc['db_insert']('', |
||
| 1641 | '{db_prefix}log_actions', |
||
| 1642 | array( |
||
| 1643 | 'log_time' => 'int', 'id_log' => 'int', 'id_member' => 'int', 'ip' => 'inet', 'action' => 'string', |
||
| 1644 | 'id_board' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'extra' => 'string-65534', |
||
| 1645 | ), |
||
| 1646 | array( |
||
| 1647 | time(), 3, $user_info['id'], $command_line ? '127.0.0.1' : $user_info['ip'], 'upgrade', |
||
| 1648 | 0, 0, 0, json_encode(array('version' => SMF_FULL_VERSION, 'member' => $user_info['id'])), |
||
| 1649 | ), |
||
| 1650 | array('id_action') |
||
| 1651 | ); |
||
| 1652 | $user_info['id'] = 0; |
||
| 1653 | |||
| 1654 | if ($command_line) |
||
| 1655 | { |
||
| 1656 | echo $endl; |
||
| 1657 | echo 'Upgrade Complete!', $endl; |
||
| 1658 | echo 'Please delete this file as soon as possible for security reasons.', $endl; |
||
| 1659 | exit; |
||
| 1660 | } |
||
| 1661 | |||
| 1662 | // Make sure it says we're done. |
||
| 1663 | $upcontext['overall_percent'] = 100; |
||
| 1664 | if (isset($upcontext['step_progress'])) |
||
| 1665 | unset($upcontext['step_progress']); |
||
| 1666 | |||
| 1667 | $_GET['substep'] = 0; |
||
| 1668 | return false; |
||
| 1669 | } |
||
| 1670 | |||
| 1671 | // Just like the built in one, but setup for CLI to not use themes. |
||
| 1672 | function cli_scheduled_fetchSMfiles() |
||
| 1673 | { |
||
| 1674 | global $sourcedir, $language, $modSettings, $smcFunc; |
||
| 1675 | |||
| 1676 | if (empty($modSettings['time_format'])) |
||
| 1677 | $modSettings['time_format'] = '%B %d, %Y, %I:%M:%S %p'; |
||
| 1678 | |||
| 1679 | // What files do we want to get |
||
| 1680 | $request = $smcFunc['db_query']('', ' |
||
| 1681 | SELECT id_file, filename, path, parameters |
||
| 1682 | FROM {db_prefix}admin_info_files', |
||
| 1683 | array( |
||
| 1684 | ) |
||
| 1685 | ); |
||
| 1686 | |||
| 1687 | $js_files = array(); |
||
| 1688 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1689 | { |
||
| 1690 | $js_files[$row['id_file']] = array( |
||
| 1691 | 'filename' => $row['filename'], |
||
| 1692 | 'path' => $row['path'], |
||
| 1693 | 'parameters' => sprintf($row['parameters'], $language, urlencode($modSettings['time_format']), urlencode(SMF_FULL_VERSION)), |
||
| 1694 | ); |
||
| 1695 | } |
||
| 1696 | $smcFunc['db_free_result']($request); |
||
| 1697 | |||
| 1698 | // We're gonna need fetch_web_data() to pull this off. |
||
| 1699 | require_once($sourcedir . '/Subs.php'); |
||
| 1700 | |||
| 1701 | foreach ($js_files as $ID_FILE => $file) |
||
| 1702 | { |
||
| 1703 | // Create the url |
||
| 1704 | $server = empty($file['path']) || substr($file['path'], 0, 7) != 'http://' ? 'https://www.simplemachines.org' : ''; |
||
| 1705 | $url = $server . (!empty($file['path']) ? $file['path'] : $file['path']) . $file['filename'] . (!empty($file['parameters']) ? '?' . $file['parameters'] : ''); |
||
| 1706 | |||
| 1707 | // Get the file |
||
| 1708 | $file_data = fetch_web_data($url); |
||
| 1709 | |||
| 1710 | // If we got an error - give up - the site might be down. |
||
| 1711 | if ($file_data === false) |
||
| 1712 | return throw_error(sprintf('Could not retrieve the file %1$s.', $url)); |
||
| 1713 | |||
| 1714 | // Save the file to the database. |
||
| 1715 | $smcFunc['db_query']('substring', ' |
||
| 1716 | UPDATE {db_prefix}admin_info_files |
||
| 1717 | SET data = SUBSTRING({string:file_data}, 1, 65534) |
||
| 1718 | WHERE id_file = {int:id_file}', |
||
| 1719 | array( |
||
| 1720 | 'id_file' => $ID_FILE, |
||
| 1721 | 'file_data' => $file_data, |
||
| 1722 | ) |
||
| 1723 | ); |
||
| 1724 | } |
||
| 1725 | return true; |
||
| 1726 | } |
||
| 1727 | |||
| 1728 | function convertSettingsToTheme() |
||
| 1729 | { |
||
| 1730 | global $db_prefix, $modSettings, $smcFunc; |
||
| 1731 | |||
| 1732 | $values = array( |
||
| 1733 | 'show_latest_member' => @$GLOBALS['showlatestmember'], |
||
| 1734 | 'show_bbc' => isset($GLOBALS['showyabbcbutt']) ? $GLOBALS['showyabbcbutt'] : @$GLOBALS['showbbcbutt'], |
||
| 1735 | 'show_modify' => @$GLOBALS['showmodify'], |
||
| 1736 | 'show_user_images' => @$GLOBALS['showuserpic'], |
||
| 1737 | 'show_blurb' => @$GLOBALS['showusertext'], |
||
| 1738 | 'show_gender' => @$GLOBALS['showgenderimage'], |
||
| 1739 | 'show_newsfader' => @$GLOBALS['shownewsfader'], |
||
| 1740 | 'display_recent_bar' => @$GLOBALS['Show_RecentBar'], |
||
| 1741 | 'show_member_bar' => @$GLOBALS['Show_MemberBar'], |
||
| 1742 | 'linktree_link' => @$GLOBALS['curposlinks'], |
||
| 1743 | 'show_profile_buttons' => @$GLOBALS['profilebutton'], |
||
| 1744 | 'show_mark_read' => @$GLOBALS['showmarkread'], |
||
| 1745 | 'newsfader_time' => @$GLOBALS['fadertime'], |
||
| 1746 | 'use_image_buttons' => empty($GLOBALS['MenuType']) ? 1 : 0, |
||
| 1747 | 'enable_news' => @$GLOBALS['enable_news'], |
||
| 1748 | 'return_to_post' => @$modSettings['returnToPost'], |
||
| 1749 | ); |
||
| 1750 | |||
| 1751 | $themeData = array(); |
||
| 1752 | foreach ($values as $variable => $value) |
||
| 1753 | { |
||
| 1754 | if (!isset($value) || $value === null) |
||
| 1755 | $value = 0; |
||
| 1756 | |||
| 1757 | $themeData[] = array(0, 1, $variable, $value); |
||
| 1758 | } |
||
| 1759 | if (!empty($themeData)) |
||
| 1760 | { |
||
| 1761 | $smcFunc['db_insert']('ignore', |
||
| 1762 | $db_prefix . 'themes', |
||
| 1763 | array('id_member' => 'int', 'id_theme' => 'int', 'variable' => 'string', 'value' => 'string'), |
||
| 1764 | $themeData, |
||
| 1765 | array('id_member', 'id_theme', 'variable') |
||
| 1766 | ); |
||
| 1767 | } |
||
| 1768 | } |
||
| 1769 | |||
| 1770 | // This function only works with MySQL but that's fine as it is only used for v1.0. |
||
| 1771 | function convertSettingstoOptions() |
||
| 1772 | { |
||
| 1773 | global $modSettings, $smcFunc; |
||
| 1774 | |||
| 1775 | // Format: new_setting -> old_setting_name. |
||
| 1776 | $values = array( |
||
| 1777 | 'calendar_start_day' => 'cal_startmonday', |
||
| 1778 | 'view_newest_first' => 'viewNewestFirst', |
||
| 1779 | 'view_newest_pm_first' => 'viewNewestFirst', |
||
| 1780 | ); |
||
| 1781 | |||
| 1782 | foreach ($values as $variable => $value) |
||
| 1783 | { |
||
| 1784 | if (empty($modSettings[$value[0]])) |
||
| 1785 | continue; |
||
| 1786 | |||
| 1787 | $smcFunc['db_query']('', ' |
||
| 1788 | INSERT IGNORE INTO {db_prefix}themes |
||
| 1789 | (id_member, id_theme, variable, value) |
||
| 1790 | SELECT id_member, 1, {string:variable}, {string:value} |
||
| 1791 | FROM {db_prefix}members', |
||
| 1792 | array( |
||
| 1793 | 'variable' => $variable, |
||
| 1794 | 'value' => $modSettings[$value[0]], |
||
| 1795 | 'db_error_skip' => true, |
||
| 1796 | ) |
||
| 1797 | ); |
||
| 1798 | |||
| 1799 | $smcFunc['db_query']('', ' |
||
| 1800 | INSERT IGNORE INTO {db_prefix}themes |
||
| 1801 | (id_member, id_theme, variable, value) |
||
| 1802 | VALUES (-1, 1, {string:variable}, {string:value})', |
||
| 1803 | array( |
||
| 1804 | 'variable' => $variable, |
||
| 1805 | 'value' => $modSettings[$value[0]], |
||
| 1806 | 'db_error_skip' => true, |
||
| 1807 | ) |
||
| 1808 | ); |
||
| 1809 | } |
||
| 1810 | } |
||
| 1811 | |||
| 1812 | function php_version_check() |
||
| 1813 | { |
||
| 1814 | return version_compare(PHP_VERSION, $GLOBALS['required_php_version'], '>='); |
||
| 1815 | } |
||
| 1816 | |||
| 1817 | function db_version_check() |
||
| 1818 | { |
||
| 1819 | global $db_type, $databases; |
||
| 1820 | |||
| 1821 | $curver = eval($databases[$db_type]['version_check']); |
||
| 1822 | $curver = preg_replace('~\-.+?$~', '', $curver); |
||
| 1823 | |||
| 1824 | return version_compare($databases[$db_type]['version'], $curver, '<='); |
||
| 1825 | } |
||
| 1826 | |||
| 1827 | function fixRelativePath($path) |
||
| 1828 | { |
||
| 1829 | global $install_path; |
||
| 1830 | |||
| 1831 | // Fix the . at the start, clear any duplicate slashes, and fix any trailing slash... |
||
| 1832 | return addslashes(preg_replace(array('~^\.([/\\\]|$)~', '~[/]+~', '~[\\\]+~', '~[/\\\]$~'), array($install_path . '$1', '/', '\\', ''), $path)); |
||
| 1833 | } |
||
| 1834 | |||
| 1835 | function parse_sql($filename) |
||
| 1836 | { |
||
| 1837 | global $db_prefix, $db_collation, $boarddir, $boardurl, $command_line, $file_steps, $step_progress, $custom_warning; |
||
| 1838 | global $upcontext, $support_js, $is_debug, $db_type, $db_character_set; |
||
| 1839 | |||
| 1840 | /* |
||
| 1841 | Failure allowed on: |
||
| 1842 | - INSERT INTO but not INSERT IGNORE INTO. |
||
| 1843 | - UPDATE IGNORE but not UPDATE. |
||
| 1844 | - ALTER TABLE and ALTER IGNORE TABLE. |
||
| 1845 | - DROP TABLE. |
||
| 1846 | Yes, I realize that this is a bit confusing... maybe it should be done differently? |
||
| 1847 | |||
| 1848 | If a comment... |
||
| 1849 | - begins with --- it is to be output, with a break only in debug mode. (and say successful\n\n if there was one before.) |
||
| 1850 | - begins with ---# it is a debugging statement, no break - only shown at all in debug. |
||
| 1851 | - is only ---#, it is "done." and then a break - only shown in debug. |
||
| 1852 | - begins with ---{ it is a code block terminating at ---}. |
||
| 1853 | |||
| 1854 | Every block of between "--- ..."s is a step. Every "---#" section represents a substep. |
||
| 1855 | |||
| 1856 | Replaces the following variables: |
||
| 1857 | - {$boarddir} |
||
| 1858 | - {$boardurl} |
||
| 1859 | - {$db_prefix} |
||
| 1860 | - {$db_collation} |
||
| 1861 | */ |
||
| 1862 | |||
| 1863 | // May want to use extended functionality. |
||
| 1864 | db_extend(); |
||
| 1865 | db_extend('packages'); |
||
| 1866 | |||
| 1867 | // Our custom error handler - does nothing but does stop public errors from XML! |
||
| 1868 | set_error_handler( |
||
| 1869 | function($errno, $errstr, $errfile, $errline) use ($support_js) |
||
| 1870 | { |
||
| 1871 | if ($support_js) |
||
| 1872 | return true; |
||
| 1873 | else |
||
| 1874 | echo 'Error: ' . $errstr . ' File: ' . $errfile . ' Line: ' . $errline; |
||
| 1875 | } |
||
| 1876 | ); |
||
| 1877 | |||
| 1878 | // If we're on MySQL, set {db_collation}; this approach is used throughout upgrade_2-0_mysql.php to set new tables to utf8 |
||
| 1879 | // Note it is expected to be in the format: ENGINE=MyISAM{$db_collation}; |
||
| 1880 | if ($db_type == 'mysql') |
||
| 1881 | $db_collation = ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci'; |
||
| 1882 | else |
||
| 1883 | $db_collation = ''; |
||
| 1884 | |||
| 1885 | $endl = $command_line ? "\n" : '<br>' . "\n"; |
||
| 1886 | |||
| 1887 | $lines = file($filename); |
||
| 1888 | |||
| 1889 | $current_type = 'sql'; |
||
| 1890 | $current_data = ''; |
||
| 1891 | $substep = 0; |
||
| 1892 | $last_step = ''; |
||
| 1893 | |||
| 1894 | // Make sure all newly created tables will have the proper characters set; this approach is used throughout upgrade_2-1_mysql.php |
||
| 1895 | if (isset($db_character_set) && $db_character_set === 'utf8') |
||
| 1896 | $lines = str_replace(') ENGINE=MyISAM;', ') ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;', $lines); |
||
| 1897 | |||
| 1898 | // Count the total number of steps within this file - for progress. |
||
| 1899 | $file_steps = substr_count(implode('', $lines), '---#'); |
||
| 1900 | $upcontext['total_items'] = substr_count(implode('', $lines), '--- '); |
||
| 1901 | $upcontext['debug_items'] = $file_steps; |
||
| 1902 | $upcontext['current_item_num'] = 0; |
||
| 1903 | $upcontext['current_item_name'] = ''; |
||
| 1904 | $upcontext['current_debug_item_num'] = 0; |
||
| 1905 | $upcontext['current_debug_item_name'] = ''; |
||
| 1906 | // This array keeps a record of what we've done in case java is dead... |
||
| 1907 | $upcontext['actioned_items'] = array(); |
||
| 1908 | |||
| 1909 | $done_something = false; |
||
| 1910 | |||
| 1911 | foreach ($lines as $line_number => $line) |
||
| 1912 | { |
||
| 1913 | $do_current = $substep >= $_GET['substep']; |
||
| 1914 | |||
| 1915 | // Get rid of any comments in the beginning of the line... |
||
| 1916 | if (substr(trim($line), 0, 2) === '/*') |
||
| 1917 | $line = preg_replace('~/\*.+?\*/~', '', $line); |
||
| 1918 | |||
| 1919 | // Always flush. Flush, flush, flush. Flush, flush, flush, flush! FLUSH! |
||
| 1920 | if ($is_debug && !$support_js && $command_line) |
||
| 1921 | flush(); |
||
| 1922 | |||
| 1923 | if (trim($line) === '') |
||
| 1924 | continue; |
||
| 1925 | |||
| 1926 | if (trim(substr($line, 0, 3)) === '---') |
||
| 1927 | { |
||
| 1928 | $type = substr($line, 3, 1); |
||
| 1929 | |||
| 1930 | // An error?? |
||
| 1931 | if (trim($current_data) != '' && $type !== '}') |
||
| 1932 | { |
||
| 1933 | $upcontext['error_message'] = 'Error in upgrade script - line ' . $line_number . '!' . $endl; |
||
| 1934 | if ($command_line) |
||
| 1935 | echo $upcontext['error_message']; |
||
| 1936 | } |
||
| 1937 | |||
| 1938 | if ($type == ' ') |
||
| 1939 | { |
||
| 1940 | if (!$support_js && $do_current && $_GET['substep'] != 0 && $command_line) |
||
| 1941 | { |
||
| 1942 | echo ' Successful.', $endl; |
||
| 1943 | flush(); |
||
| 1944 | } |
||
| 1945 | |||
| 1946 | $last_step = htmlspecialchars(rtrim(substr($line, 4))); |
||
| 1947 | $upcontext['current_item_num']++; |
||
| 1948 | $upcontext['current_item_name'] = $last_step; |
||
| 1949 | |||
| 1950 | if ($do_current) |
||
| 1951 | { |
||
| 1952 | $upcontext['actioned_items'][] = $last_step; |
||
| 1953 | if ($command_line) |
||
| 1954 | echo ' * '; |
||
| 1955 | |||
| 1956 | // Starting a new main step in our DB changes, so it's time to reset this. |
||
| 1957 | $upcontext['skip_db_substeps'] = false; |
||
| 1958 | } |
||
| 1959 | } |
||
| 1960 | elseif ($type == '#') |
||
| 1961 | { |
||
| 1962 | $upcontext['step_progress'] += (100 / $upcontext['file_count']) / $file_steps; |
||
| 1963 | |||
| 1964 | $upcontext['current_debug_item_num']++; |
||
| 1965 | if (trim($line) != '---#') |
||
| 1966 | $upcontext['current_debug_item_name'] = htmlspecialchars(rtrim(substr($line, 4))); |
||
| 1967 | |||
| 1968 | // Have we already done something? |
||
| 1969 | if (isset($_GET['xml']) && $done_something) |
||
| 1970 | { |
||
| 1971 | restore_error_handler(); |
||
| 1972 | return $upcontext['current_debug_item_num'] >= $upcontext['debug_items'] ? true : false; |
||
| 1973 | } |
||
| 1974 | |||
| 1975 | if ($do_current) |
||
| 1976 | { |
||
| 1977 | if (trim($line) == '---#' && $command_line) |
||
| 1978 | echo ' done.', $endl; |
||
| 1979 | elseif ($command_line) |
||
| 1980 | echo ' +++ ', rtrim(substr($line, 4)); |
||
| 1981 | elseif (trim($line) != '---#') |
||
| 1982 | { |
||
| 1983 | if ($is_debug) |
||
| 1984 | $upcontext['actioned_items'][] = $upcontext['current_debug_item_name']; |
||
| 1985 | } |
||
| 1986 | } |
||
| 1987 | |||
| 1988 | if ($substep < $_GET['substep'] && $substep + 1 >= $_GET['substep']) |
||
| 1989 | { |
||
| 1990 | if ($command_line) |
||
| 1991 | echo ' * '; |
||
| 1992 | else |
||
| 1993 | $upcontext['actioned_items'][] = $last_step; |
||
| 1994 | } |
||
| 1995 | |||
| 1996 | // Small step - only if we're actually doing stuff. |
||
| 1997 | if ($do_current) |
||
| 1998 | nextSubstep(++$substep); |
||
| 1999 | else |
||
| 2000 | $substep++; |
||
| 2001 | } |
||
| 2002 | elseif ($type == '{') |
||
| 2003 | $current_type = 'code'; |
||
| 2004 | elseif ($type == '}') |
||
| 2005 | { |
||
| 2006 | $current_type = 'sql'; |
||
| 2007 | |||
| 2008 | if (!$do_current || !empty($upcontext['skip_db_substeps'])) |
||
| 2009 | { |
||
| 2010 | $current_data = ''; |
||
| 2011 | |||
| 2012 | // Avoid confusion when skipping something we normally would have done |
||
| 2013 | if ($do_current) |
||
| 2014 | $done_something = true; |
||
| 2015 | |||
| 2016 | continue; |
||
| 2017 | } |
||
| 2018 | |||
| 2019 | // @todo Update this to a try/catch for PHP 7+, because eval() now throws an exception for parse errors instead of returning false |
||
| 2020 | if (eval('global $db_prefix, $modSettings, $smcFunc, $txt, $upcontext; ' . $current_data) === false) |
||
| 2021 | { |
||
| 2022 | $upcontext['error_message'] = 'Error in upgrade script ' . basename($filename) . ' on line ' . $line_number . '!' . $endl; |
||
| 2023 | if ($command_line) |
||
| 2024 | echo $upcontext['error_message']; |
||
| 2025 | } |
||
| 2026 | |||
| 2027 | // Done with code! |
||
| 2028 | $current_data = ''; |
||
| 2029 | $done_something = true; |
||
| 2030 | } |
||
| 2031 | |||
| 2032 | continue; |
||
| 2033 | } |
||
| 2034 | |||
| 2035 | $current_data .= $line; |
||
| 2036 | if (substr(rtrim($current_data), -1) === ';' && $current_type === 'sql') |
||
| 2037 | { |
||
| 2038 | if ((!$support_js || isset($_GET['xml']))) |
||
| 2039 | { |
||
| 2040 | if (!$do_current || !empty($upcontext['skip_db_substeps'])) |
||
| 2041 | { |
||
| 2042 | $current_data = ''; |
||
| 2043 | |||
| 2044 | if ($do_current) |
||
| 2045 | $done_something = true; |
||
| 2046 | |||
| 2047 | continue; |
||
| 2048 | } |
||
| 2049 | |||
| 2050 | $current_data = strtr(substr(rtrim($current_data), 0, -1), array('{$db_prefix}' => $db_prefix, '{$boarddir}' => $boarddir, '{$sboarddir}' => addslashes($boarddir), '{$boardurl}' => $boardurl, '{$db_collation}' => $db_collation)); |
||
| 2051 | |||
| 2052 | upgrade_query($current_data); |
||
| 2053 | |||
| 2054 | // @todo This will be how it kinda does it once mysql all stripped out - needed for postgre (etc). |
||
| 2055 | /* |
||
| 2056 | $result = $smcFunc['db_query']('', $current_data, false, false); |
||
| 2057 | // Went wrong? |
||
| 2058 | if (!$result) |
||
| 2059 | { |
||
| 2060 | // Bit of a bodge - do we want the error? |
||
| 2061 | if (!empty($upcontext['return_error'])) |
||
| 2062 | { |
||
| 2063 | $upcontext['error_message'] = $smcFunc['db_error']($db_connection); |
||
| 2064 | return false; |
||
| 2065 | } |
||
| 2066 | }*/ |
||
| 2067 | $done_something = true; |
||
| 2068 | } |
||
| 2069 | $current_data = ''; |
||
| 2070 | } |
||
| 2071 | // If this is xml based and we're just getting the item name then that's grand. |
||
| 2072 | elseif ($support_js && !isset($_GET['xml']) && $upcontext['current_debug_item_name'] != '' && $do_current) |
||
| 2073 | { |
||
| 2074 | restore_error_handler(); |
||
| 2075 | return false; |
||
| 2076 | } |
||
| 2077 | |||
| 2078 | // Clean up by cleaning any step info. |
||
| 2079 | $step_progress = array(); |
||
| 2080 | $custom_warning = ''; |
||
| 2081 | } |
||
| 2082 | |||
| 2083 | // Put back the error handler. |
||
| 2084 | restore_error_handler(); |
||
| 2085 | |||
| 2086 | if ($command_line) |
||
| 2087 | { |
||
| 2088 | echo ' Successful.' . "\n"; |
||
| 2089 | flush(); |
||
| 2090 | } |
||
| 2091 | |||
| 2092 | $_GET['substep'] = 0; |
||
| 2093 | return true; |
||
| 2094 | } |
||
| 2095 | |||
| 2096 | function upgrade_query($string, $unbuffered = false) |
||
| 2097 | { |
||
| 2098 | global $db_connection, $db_server, $db_user, $db_passwd, $db_type; |
||
| 2099 | global $command_line, $upcontext, $upgradeurl, $modSettings; |
||
| 2100 | global $db_name, $db_unbuffered, $smcFunc, $txt; |
||
| 2101 | |||
| 2102 | // Get the query result - working around some SMF specific security - just this once! |
||
| 2103 | $modSettings['disableQueryCheck'] = true; |
||
| 2104 | $db_unbuffered = $unbuffered; |
||
| 2105 | $ignore_insert_error = false; |
||
| 2106 | |||
| 2107 | // If we got an old pg version and use a insert ignore query |
||
| 2108 | if ($db_type == 'postgresql' && !$smcFunc['db_native_replace']() && strpos($string, 'ON CONFLICT DO NOTHING') !== false) |
||
| 2109 | { |
||
| 2110 | $ignore_insert_error = true; |
||
| 2111 | $string = str_replace('ON CONFLICT DO NOTHING', '', $string); |
||
| 2112 | } |
||
| 2113 | $result = $smcFunc['db_query']('', $string, array('security_override' => true, 'db_error_skip' => true)); |
||
| 2114 | $db_unbuffered = false; |
||
| 2115 | |||
| 2116 | // Failure?! |
||
| 2117 | if ($result !== false) |
||
| 2118 | return $result; |
||
| 2119 | |||
| 2120 | $db_error_message = $smcFunc['db_error']($db_connection); |
||
| 2121 | // If MySQL we do something more clever. |
||
| 2122 | if ($db_type == 'mysql') |
||
| 2123 | { |
||
| 2124 | $mysqli_errno = mysqli_errno($db_connection); |
||
| 2125 | $error_query = in_array(substr(trim($string), 0, 11), array('INSERT INTO', 'UPDATE IGNO', 'ALTER TABLE', 'DROP TABLE ', 'ALTER IGNOR')); |
||
| 2126 | |||
| 2127 | // Error numbers: |
||
| 2128 | // 1016: Can't open file '....MYI' |
||
| 2129 | // 1050: Table already exists. |
||
| 2130 | // 1054: Unknown column name. |
||
| 2131 | // 1060: Duplicate column name. |
||
| 2132 | // 1061: Duplicate key name. |
||
| 2133 | // 1062: Duplicate entry for unique key. |
||
| 2134 | // 1068: Multiple primary keys. |
||
| 2135 | // 1072: Key column '%s' doesn't exist in table. |
||
| 2136 | // 1091: Can't drop key, doesn't exist. |
||
| 2137 | // 1146: Table doesn't exist. |
||
| 2138 | // 2013: Lost connection to server during query. |
||
| 2139 | |||
| 2140 | if ($mysqli_errno == 1016) |
||
| 2141 | { |
||
| 2142 | if (preg_match('~\'([^\.\']+)~', $db_error_message, $match) != 0 && !empty($match[1])) |
||
| 2143 | { |
||
| 2144 | mysqli_query($db_connection, 'REPAIR TABLE `' . $match[1] . '`'); |
||
| 2145 | $result = mysqli_query($db_connection, $string); |
||
| 2146 | if ($result !== false) |
||
| 2147 | return $result; |
||
| 2148 | } |
||
| 2149 | } |
||
| 2150 | elseif ($mysqli_errno == 2013) |
||
| 2151 | { |
||
| 2152 | $db_connection = mysqli_connect($db_server, $db_user, $db_passwd); |
||
| 2153 | mysqli_select_db($db_connection, $db_name); |
||
| 2154 | if ($db_connection) |
||
| 2155 | { |
||
| 2156 | $result = mysqli_query($db_connection, $string); |
||
| 2157 | if ($result !== false) |
||
| 2158 | return $result; |
||
| 2159 | } |
||
| 2160 | } |
||
| 2161 | // Duplicate column name... should be okay ;). |
||
| 2162 | elseif (in_array($mysqli_errno, array(1060, 1061, 1068, 1091))) |
||
| 2163 | return false; |
||
| 2164 | // Duplicate insert... make sure it's the proper type of query ;). |
||
| 2165 | elseif (in_array($mysqli_errno, array(1054, 1062, 1146)) && $error_query) |
||
| 2166 | return false; |
||
| 2167 | // Creating an index on a non-existent column. |
||
| 2168 | elseif ($mysqli_errno == 1072) |
||
| 2169 | return false; |
||
| 2170 | elseif ($mysqli_errno == 1050 && substr(trim($string), 0, 12) == 'RENAME TABLE') |
||
| 2171 | return false; |
||
| 2172 | } |
||
| 2173 | // If a table already exists don't go potty. |
||
| 2174 | else |
||
| 2175 | { |
||
| 2176 | if (in_array(substr(trim($string), 0, 8), array('CREATE T', 'CREATE S', 'DROP TABL', 'ALTER TA', 'CREATE I', 'CREATE U'))) |
||
| 2177 | { |
||
| 2178 | if (strpos($db_error_message, 'exist') !== false) |
||
| 2179 | return true; |
||
| 2180 | } |
||
| 2181 | elseif (strpos(trim($string), 'INSERT ') !== false) |
||
| 2182 | { |
||
| 2183 | if (strpos($db_error_message, 'duplicate') !== false || $ignore_insert_error) |
||
| 2184 | return true; |
||
| 2185 | } |
||
| 2186 | } |
||
| 2187 | |||
| 2188 | // Get the query string so we pass everything. |
||
| 2189 | $query_string = ''; |
||
| 2190 | foreach ($_GET as $k => $v) |
||
| 2191 | $query_string .= ';' . $k . '=' . $v; |
||
| 2192 | if (strlen($query_string) != 0) |
||
| 2193 | $query_string = '?' . substr($query_string, 1); |
||
| 2194 | |||
| 2195 | if ($command_line) |
||
| 2196 | { |
||
| 2197 | echo 'Unsuccessful! Database error message:', "\n", $db_error_message, "\n"; |
||
| 2198 | die; |
||
| 2199 | } |
||
| 2200 | |||
| 2201 | // Bit of a bodge - do we want the error? |
||
| 2202 | if (!empty($upcontext['return_error'])) |
||
| 2203 | { |
||
| 2204 | $upcontext['error_message'] = $db_error_message; |
||
| 2205 | $upcontext['error_string'] = $string; |
||
| 2206 | return false; |
||
| 2207 | } |
||
| 2208 | |||
| 2209 | // Otherwise we have to display this somewhere appropriate if possible. |
||
| 2210 | $upcontext['forced_error_message'] = ' |
||
| 2211 | <strong>' . $txt['upgrade_unsuccessful'] . '</strong><br> |
||
| 2212 | |||
| 2213 | <div style="margin: 2ex;"> |
||
| 2214 | ' . $txt['upgrade_thisquery'] . ' |
||
| 2215 | <blockquote><pre>' . nl2br(htmlspecialchars(trim($string))) . ';</pre></blockquote> |
||
| 2216 | |||
| 2217 | ' . $txt['upgrade_causerror'] . ' |
||
| 2218 | <blockquote>' . nl2br(htmlspecialchars($db_error_message)) . '</blockquote> |
||
| 2219 | </div> |
||
| 2220 | |||
| 2221 | <form action="' . $upgradeurl . $query_string . '" method="post"> |
||
| 2222 | <input type="submit" value="' . $txt['upgrade_respondtime_clickhere'] . '" class="button"> |
||
| 2223 | </form> |
||
| 2224 | </div>'; |
||
| 2225 | |||
| 2226 | upgradeExit(); |
||
| 2227 | } |
||
| 2228 | |||
| 2229 | // This performs a table alter, but does it unbuffered so the script can time out professionally. |
||
| 2230 | function protected_alter($change, $substep, $is_test = false) |
||
| 2231 | { |
||
| 2232 | global $db_prefix, $smcFunc; |
||
| 2233 | |||
| 2234 | db_extend('packages'); |
||
| 2235 | |||
| 2236 | // Firstly, check whether the current index/column exists. |
||
| 2237 | $found = false; |
||
| 2238 | if ($change['type'] === 'column') |
||
| 2239 | { |
||
| 2240 | $columns = $smcFunc['db_list_columns']('{db_prefix}' . $change['table'], true); |
||
| 2241 | foreach ($columns as $column) |
||
| 2242 | { |
||
| 2243 | // Found it? |
||
| 2244 | if ($column['name'] === $change['name']) |
||
| 2245 | { |
||
| 2246 | $found |= 1; |
||
| 2247 | // Do some checks on the data if we have it set. |
||
| 2248 | if (isset($change['col_type'])) |
||
| 2249 | $found &= $change['col_type'] === $column['type']; |
||
| 2250 | if (isset($change['null_allowed'])) |
||
| 2251 | $found &= $column['null'] == $change['null_allowed']; |
||
| 2252 | if (isset($change['default'])) |
||
| 2253 | $found &= $change['default'] === $column['default']; |
||
| 2254 | } |
||
| 2255 | } |
||
| 2256 | } |
||
| 2257 | elseif ($change['type'] === 'index') |
||
| 2258 | { |
||
| 2259 | $request = upgrade_query(' |
||
| 2260 | SHOW INDEX |
||
| 2261 | FROM ' . $db_prefix . $change['table']); |
||
| 2262 | if ($request !== false) |
||
| 2263 | { |
||
| 2264 | $cur_index = array(); |
||
| 2265 | |||
| 2266 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 2267 | if ($row['Key_name'] === $change['name']) |
||
| 2268 | $cur_index[(int) $row['Seq_in_index']] = $row['Column_name']; |
||
| 2269 | |||
| 2270 | ksort($cur_index, SORT_NUMERIC); |
||
| 2271 | $found = array_values($cur_index) === $change['target_columns']; |
||
| 2272 | |||
| 2273 | $smcFunc['db_free_result']($request); |
||
| 2274 | } |
||
| 2275 | } |
||
| 2276 | |||
| 2277 | // If we're trying to add and it's added, we're done. |
||
| 2278 | if ($found && in_array($change['method'], array('add', 'change'))) |
||
| 2279 | return true; |
||
| 2280 | // Otherwise if we're removing and it wasn't found we're also done. |
||
| 2281 | elseif (!$found && in_array($change['method'], array('remove', 'change_remove'))) |
||
| 2282 | return true; |
||
| 2283 | // Otherwise is it just a test? |
||
| 2284 | elseif ($is_test) |
||
| 2285 | return false; |
||
| 2286 | |||
| 2287 | // Not found it yet? Bummer! How about we see if we're currently doing it? |
||
| 2288 | $running = false; |
||
| 2289 | $found = false; |
||
| 2290 | while (1 == 1) |
||
| 2291 | { |
||
| 2292 | $request = upgrade_query(' |
||
| 2293 | SHOW FULL PROCESSLIST'); |
||
| 2294 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 2295 | { |
||
| 2296 | if (strpos($row['Info'], 'ALTER TABLE ' . $db_prefix . $change['table']) !== false && strpos($row['Info'], $change['text']) !== false) |
||
| 2297 | $found = true; |
||
| 2298 | } |
||
| 2299 | |||
| 2300 | // Can't find it? Then we need to run it fools! |
||
| 2301 | if (!$found && !$running) |
||
| 2302 | { |
||
| 2303 | $smcFunc['db_free_result']($request); |
||
| 2304 | |||
| 2305 | $success = upgrade_query(' |
||
| 2306 | ALTER TABLE ' . $db_prefix . $change['table'] . ' |
||
| 2307 | ' . $change['text'], true) !== false; |
||
| 2308 | |||
| 2309 | if (!$success) |
||
| 2310 | return false; |
||
| 2311 | |||
| 2312 | // Return |
||
| 2313 | $running = true; |
||
| 2314 | } |
||
| 2315 | // What if we've not found it, but we'd ran it already? Must of completed. |
||
| 2316 | elseif (!$found) |
||
| 2317 | { |
||
| 2318 | $smcFunc['db_free_result']($request); |
||
| 2319 | return true; |
||
| 2320 | } |
||
| 2321 | |||
| 2322 | // Pause execution for a sec or three. |
||
| 2323 | sleep(3); |
||
| 2324 | |||
| 2325 | // Can never be too well protected. |
||
| 2326 | nextSubstep($substep); |
||
| 2327 | } |
||
| 2328 | |||
| 2329 | // Protect it. |
||
| 2330 | nextSubstep($substep); |
||
| 2331 | } |
||
| 2332 | |||
| 2333 | /** |
||
| 2334 | * Alter a text column definition preserving its character set. |
||
| 2335 | * |
||
| 2336 | * @param array $change |
||
| 2337 | * @param int $substep |
||
| 2338 | */ |
||
| 2339 | function textfield_alter($change, $substep) |
||
| 2340 | { |
||
| 2341 | global $db_prefix, $smcFunc; |
||
| 2342 | |||
| 2343 | $request = $smcFunc['db_query']('', ' |
||
| 2344 | SHOW FULL COLUMNS |
||
| 2345 | FROM {db_prefix}' . $change['table'] . ' |
||
| 2346 | LIKE {string:column}', |
||
| 2347 | array( |
||
| 2348 | 'column' => $change['column'], |
||
| 2349 | 'db_error_skip' => true, |
||
| 2350 | ) |
||
| 2351 | ); |
||
| 2352 | if ($smcFunc['db_num_rows']($request) === 0) |
||
| 2353 | die('Unable to find column ' . $change['column'] . ' inside table ' . $db_prefix . $change['table']); |
||
| 2354 | $table_row = $smcFunc['db_fetch_assoc']($request); |
||
| 2355 | $smcFunc['db_free_result']($request); |
||
| 2356 | |||
| 2357 | // If something of the current column definition is different, fix it. |
||
| 2358 | $column_fix = $table_row['Type'] !== $change['type'] || (strtolower($table_row['Null']) === 'yes') !== $change['null_allowed'] || ($table_row['Default'] === null) !== !isset($change['default']) || (isset($change['default']) && $change['default'] !== $table_row['Default']); |
||
| 2359 | |||
| 2360 | // Columns that previously allowed null, need to be converted first. |
||
| 2361 | $null_fix = strtolower($table_row['Null']) === 'yes' && !$change['null_allowed']; |
||
| 2362 | |||
| 2363 | // Get the character set that goes with the collation of the column. |
||
| 2364 | if ($column_fix && !empty($table_row['Collation'])) |
||
| 2365 | { |
||
| 2366 | $request = $smcFunc['db_query']('', ' |
||
| 2367 | SHOW COLLATION |
||
| 2368 | LIKE {string:collation}', |
||
| 2369 | array( |
||
| 2370 | 'collation' => $table_row['Collation'], |
||
| 2371 | 'db_error_skip' => true, |
||
| 2372 | ) |
||
| 2373 | ); |
||
| 2374 | // No results? Just forget it all together. |
||
| 2375 | if ($smcFunc['db_num_rows']($request) === 0) |
||
| 2376 | unset($table_row['Collation']); |
||
| 2377 | else |
||
| 2378 | $collation_info = $smcFunc['db_fetch_assoc']($request); |
||
| 2379 | $smcFunc['db_free_result']($request); |
||
| 2380 | } |
||
| 2381 | |||
| 2382 | if ($column_fix) |
||
| 2383 | { |
||
| 2384 | // Make sure there are no NULL's left. |
||
| 2385 | if ($null_fix) |
||
| 2386 | $smcFunc['db_query']('', ' |
||
| 2387 | UPDATE {db_prefix}' . $change['table'] . ' |
||
| 2388 | SET ' . $change['column'] . ' = {string:default} |
||
| 2389 | WHERE ' . $change['column'] . ' IS NULL', |
||
| 2390 | array( |
||
| 2391 | 'default' => isset($change['default']) ? $change['default'] : '', |
||
| 2392 | 'db_error_skip' => true, |
||
| 2393 | ) |
||
| 2394 | ); |
||
| 2395 | |||
| 2396 | // Do the actual alteration. |
||
| 2397 | $smcFunc['db_query']('', ' |
||
| 2398 | ALTER TABLE {db_prefix}' . $change['table'] . ' |
||
| 2399 | CHANGE COLUMN ' . $change['column'] . ' ' . $change['column'] . ' ' . $change['type'] . (isset($collation_info['Charset']) ? ' CHARACTER SET ' . $collation_info['Charset'] . ' COLLATE ' . $collation_info['Collation'] : '') . ($change['null_allowed'] ? '' : ' NOT NULL') . (isset($change['default']) ? ' default {string:default}' : ''), |
||
| 2400 | array( |
||
| 2401 | 'default' => isset($change['default']) ? $change['default'] : '', |
||
| 2402 | 'db_error_skip' => true, |
||
| 2403 | ) |
||
| 2404 | ); |
||
| 2405 | } |
||
| 2406 | nextSubstep($substep); |
||
| 2407 | } |
||
| 2408 | |||
| 2409 | // Check if we need to alter this query. |
||
| 2410 | function checkChange(&$change) |
||
| 2411 | { |
||
| 2412 | global $smcFunc, $db_type, $databases; |
||
| 2413 | static $database_version, $where_field_support; |
||
| 2414 | |||
| 2415 | // Attempt to find a database_version. |
||
| 2416 | if (empty($database_version)) |
||
| 2417 | { |
||
| 2418 | $database_version = $databases[$db_type]['version_check']; |
||
| 2419 | $where_field_support = $db_type == 'mysql' && version_compare('5.0', $database_version, '<='); |
||
| 2420 | } |
||
| 2421 | |||
| 2422 | // Not a column we need to check on? |
||
| 2423 | if (!in_array($change['name'], array('memberGroups', 'passwordSalt'))) |
||
| 2424 | return; |
||
| 2425 | |||
| 2426 | // Break it up you (six|seven). |
||
| 2427 | $temp = explode(' ', str_replace('NOT NULL', 'NOT_NULL', $change['text'])); |
||
| 2428 | |||
| 2429 | // Can we support a shortcut method? |
||
| 2430 | if ($where_field_support) |
||
| 2431 | { |
||
| 2432 | // Get the details about this change. |
||
| 2433 | $request = $smcFunc['db_query']('', ' |
||
| 2434 | SHOW FIELDS |
||
| 2435 | FROM {db_prefix}{raw:table} |
||
| 2436 | WHERE Field = {string:old_name} OR Field = {string:new_name}', |
||
| 2437 | array( |
||
| 2438 | 'table' => $change['table'], |
||
| 2439 | 'old_name' => $temp[1], |
||
| 2440 | 'new_name' => $temp[2], |
||
| 2441 | ) |
||
| 2442 | ); |
||
| 2443 | // !!! This doesn't technically work because we don't pass request into it, but it hasn't broke anything yet. |
||
| 2444 | if ($smcFunc['db_num_rows'] != 1) |
||
| 2445 | return; |
||
| 2446 | |||
| 2447 | list (, $current_type) = $smcFunc['db_fetch_assoc']($request); |
||
| 2448 | $smcFunc['db_free_result']($request); |
||
| 2449 | } |
||
| 2450 | else |
||
| 2451 | { |
||
| 2452 | // Do this the old fashion, sure method way. |
||
| 2453 | $request = $smcFunc['db_query']('', ' |
||
| 2454 | SHOW FIELDS |
||
| 2455 | FROM {db_prefix}{raw:table}', |
||
| 2456 | array( |
||
| 2457 | 'table' => $change['table'], |
||
| 2458 | ) |
||
| 2459 | ); |
||
| 2460 | // Mayday! |
||
| 2461 | // !!! This doesn't technically work because we don't pass request into it, but it hasn't broke anything yet. |
||
| 2462 | if ($smcFunc['db_num_rows'] == 0) |
||
| 2463 | return; |
||
| 2464 | |||
| 2465 | // Oh where, oh where has my little field gone. Oh where can it be... |
||
| 2466 | while ($row = $smcFunc['db_query']($request)) |
||
| 2467 | if ($row['Field'] == $temp[1] || $row['Field'] == $temp[2]) |
||
| 2468 | { |
||
| 2469 | $current_type = $row['Type']; |
||
| 2470 | break; |
||
| 2471 | } |
||
| 2472 | } |
||
| 2473 | |||
| 2474 | // If this doesn't match, the column may of been altered for a reason. |
||
| 2475 | if (trim($current_type) != trim($temp[3])) |
||
| 2476 | $temp[3] = $current_type; |
||
| 2477 | |||
| 2478 | // Piece this back together. |
||
| 2479 | $change['text'] = str_replace('NOT_NULL', 'NOT NULL', implode(' ', $temp)); |
||
| 2480 | } |
||
| 2481 | |||
| 2482 | // The next substep. |
||
| 2483 | function nextSubstep($substep) |
||
| 2484 | { |
||
| 2485 | global $start_time, $timeLimitThreshold, $command_line, $custom_warning; |
||
| 2486 | global $step_progress, $is_debug, $upcontext; |
||
| 2487 | |||
| 2488 | if ($_GET['substep'] < $substep) |
||
| 2489 | $_GET['substep'] = $substep; |
||
| 2490 | |||
| 2491 | if ($command_line) |
||
| 2492 | { |
||
| 2493 | if (time() - $start_time > 1 && empty($is_debug)) |
||
| 2494 | { |
||
| 2495 | echo '.'; |
||
| 2496 | $start_time = time(); |
||
| 2497 | } |
||
| 2498 | return; |
||
| 2499 | } |
||
| 2500 | |||
| 2501 | @set_time_limit(300); |
||
| 2502 | if (function_exists('apache_reset_timeout')) |
||
| 2503 | @apache_reset_timeout(); |
||
| 2504 | |||
| 2505 | if (time() - $start_time <= $timeLimitThreshold) |
||
| 2506 | return; |
||
| 2507 | |||
| 2508 | // Do we have some custom step progress stuff? |
||
| 2509 | if (!empty($step_progress)) |
||
| 2510 | { |
||
| 2511 | $upcontext['substep_progress'] = 0; |
||
| 2512 | $upcontext['substep_progress_name'] = $step_progress['name']; |
||
| 2513 | if ($step_progress['current'] > $step_progress['total']) |
||
| 2514 | $upcontext['substep_progress'] = 99.9; |
||
| 2515 | else |
||
| 2516 | $upcontext['substep_progress'] = ($step_progress['current'] / $step_progress['total']) * 100; |
||
| 2517 | |||
| 2518 | // Make it nicely rounded. |
||
| 2519 | $upcontext['substep_progress'] = round($upcontext['substep_progress'], 1); |
||
| 2520 | } |
||
| 2521 | |||
| 2522 | // If this is XML we just exit right away! |
||
| 2523 | if (isset($_GET['xml'])) |
||
| 2524 | return upgradeExit(); |
||
| 2525 | |||
| 2526 | // We're going to pause after this! |
||
| 2527 | $upcontext['pause'] = true; |
||
| 2528 | |||
| 2529 | $upcontext['query_string'] = ''; |
||
| 2530 | foreach ($_GET as $k => $v) |
||
| 2531 | { |
||
| 2532 | if ($k != 'data' && $k != 'substep' && $k != 'step') |
||
| 2533 | $upcontext['query_string'] .= ';' . $k . '=' . $v; |
||
| 2534 | } |
||
| 2535 | |||
| 2536 | // Custom warning? |
||
| 2537 | if (!empty($custom_warning)) |
||
| 2538 | $upcontext['custom_warning'] = $custom_warning; |
||
| 2539 | |||
| 2540 | upgradeExit(); |
||
| 2541 | } |
||
| 2542 | |||
| 2543 | function cmdStep0() |
||
| 2544 | { |
||
| 2545 | global $boarddir, $sourcedir, $modSettings, $start_time, $cachedir, $databases, $db_type, $smcFunc, $upcontext; |
||
| 2546 | global $is_debug; |
||
| 2547 | $start_time = time(); |
||
| 2548 | |||
| 2549 | ob_end_clean(); |
||
| 2550 | ob_implicit_flush(true); |
||
| 2551 | @set_time_limit(600); |
||
| 2552 | |||
| 2553 | if (!isset($_SERVER['argv'])) |
||
| 2554 | $_SERVER['argv'] = array(); |
||
| 2555 | $_GET['maint'] = 1; |
||
| 2556 | |||
| 2557 | foreach ($_SERVER['argv'] as $i => $arg) |
||
| 2558 | { |
||
| 2559 | if (preg_match('~^--language=(.+)$~', $arg, $match) != 0) |
||
| 2560 | $upcontext['lang'] = $match[1]; |
||
| 2561 | elseif (preg_match('~^--path=(.+)$~', $arg) != 0) |
||
| 2562 | continue; |
||
| 2563 | elseif ($arg == '--no-maintenance') |
||
| 2564 | $_GET['maint'] = 0; |
||
| 2565 | elseif ($arg == '--debug') |
||
| 2566 | $is_debug = true; |
||
| 2567 | elseif ($arg == '--backup') |
||
| 2568 | $_POST['backup'] = 1; |
||
| 2569 | elseif ($arg == '--template' && (file_exists($boarddir . '/template.php') || file_exists($boarddir . '/template.html') && !file_exists($modSettings['theme_dir'] . '/converted'))) |
||
| 2570 | $_GET['conv'] = 1; |
||
| 2571 | elseif ($i != 0) |
||
| 2572 | { |
||
| 2573 | echo 'SMF Command-line Upgrader |
||
| 2574 | Usage: /path/to/php -f ' . basename(__FILE__) . ' -- [OPTION]... |
||
| 2575 | |||
| 2576 | --language=LANG Reset the forum\'s language to LANG. |
||
| 2577 | --no-maintenance Don\'t put the forum into maintenance mode. |
||
| 2578 | --debug Output debugging information. |
||
| 2579 | --backup Create backups of tables with "backup_" prefix.'; |
||
| 2580 | echo "\n"; |
||
| 2581 | exit; |
||
| 2582 | } |
||
| 2583 | } |
||
| 2584 | |||
| 2585 | if (!php_version_check()) |
||
| 2586 | print_error('Error: PHP ' . PHP_VERSION . ' does not match version requirements.', true); |
||
| 2587 | if (!db_version_check()) |
||
| 2588 | print_error('Error: ' . $databases[$db_type]['name'] . ' ' . $databases[$db_type]['version'] . ' does not match minimum requirements.', true); |
||
| 2589 | |||
| 2590 | // Do some checks to make sure they have proper privileges |
||
| 2591 | db_extend('packages'); |
||
| 2592 | |||
| 2593 | // CREATE |
||
| 2594 | $create = $smcFunc['db_create_table']('{db_prefix}priv_check', array(array('name' => 'id_test', 'type' => 'int', 'size' => 10, 'unsigned' => true, 'auto' => true)), array(array('columns' => array('id_test'), 'primary' => true)), array(), 'overwrite'); |
||
| 2595 | |||
| 2596 | // ALTER |
||
| 2597 | $alter = $smcFunc['db_add_column']('{db_prefix}priv_check', array('name' => 'txt', 'type' => 'varchar', 'size' => 4, 'null' => false, 'default' => '')); |
||
| 2598 | |||
| 2599 | // DROP |
||
| 2600 | $drop = $smcFunc['db_drop_table']('{db_prefix}priv_check'); |
||
| 2601 | |||
| 2602 | // Sorry... we need CREATE, ALTER and DROP |
||
| 2603 | if (!$create || !$alter || !$drop) |
||
| 2604 | print_error("The " . $databases[$db_type]['name'] . " user you have set in Settings.php does not have proper privileges.\n\nPlease ask your host to give this user the ALTER, CREATE, and DROP privileges.", true); |
||
| 2605 | |||
| 2606 | $check = @file_exists($modSettings['theme_dir'] . '/index.template.php') |
||
| 2607 | && @file_exists($sourcedir . '/QueryString.php') |
||
| 2608 | && @file_exists($sourcedir . '/ManageBoards.php'); |
||
| 2609 | if (!$check && !isset($modSettings['smfVersion'])) |
||
| 2610 | print_error('Error: Some files are missing or out-of-date.', true); |
||
| 2611 | |||
| 2612 | // Do a quick version spot check. |
||
| 2613 | $temp = substr(@implode('', @file($boarddir . '/index.php')), 0, 4096); |
||
| 2614 | preg_match('~\*\s@version\s+(.+)[\s]{2}~i', $temp, $match); |
||
| 2615 | if (empty($match[1]) || (trim($match[1]) != SMF_VERSION)) |
||
| 2616 | print_error('Error: Some files have not yet been updated properly.'); |
||
| 2617 | |||
| 2618 | // Make sure Settings.php is writable. |
||
| 2619 | quickFileWritable($boarddir . '/Settings.php'); |
||
| 2620 | if (!is_writable($boarddir . '/Settings.php')) |
||
| 2621 | print_error('Error: Unable to obtain write access to "Settings.php".', true); |
||
| 2622 | |||
| 2623 | // Make sure Settings_bak.php is writable. |
||
| 2624 | quickFileWritable($boarddir . '/Settings_bak.php'); |
||
| 2625 | if (!is_writable($boarddir . '/Settings_bak.php')) |
||
| 2626 | print_error('Error: Unable to obtain write access to "Settings_bak.php".'); |
||
| 2627 | |||
| 2628 | if (isset($modSettings['agreement']) && (!is_writable($boarddir) || file_exists($boarddir . '/agreement.txt')) && !is_writable($boarddir . '/agreement.txt')) |
||
| 2629 | print_error('Error: Unable to obtain write access to "agreement.txt".'); |
||
| 2630 | elseif (isset($modSettings['agreement'])) |
||
| 2631 | { |
||
| 2632 | $fp = fopen($boarddir . '/agreement.txt', 'w'); |
||
| 2633 | fwrite($fp, $modSettings['agreement']); |
||
| 2634 | fclose($fp); |
||
| 2635 | } |
||
| 2636 | |||
| 2637 | // Make sure Themes is writable. |
||
| 2638 | quickFileWritable($modSettings['theme_dir']); |
||
| 2639 | |||
| 2640 | if (!is_writable($modSettings['theme_dir']) && !isset($modSettings['smfVersion'])) |
||
| 2641 | print_error('Error: Unable to obtain write access to "Themes".'); |
||
| 2642 | |||
| 2643 | // Make sure cache directory exists and is writable! |
||
| 2644 | $cachedir_temp = empty($cachedir) ? $boarddir . '/cache' : $cachedir; |
||
| 2645 | if (!file_exists($cachedir_temp)) |
||
| 2646 | @mkdir($cachedir_temp); |
||
| 2647 | |||
| 2648 | // Make sure the cache temp dir is writable. |
||
| 2649 | quickFileWritable($cachedir_temp); |
||
| 2650 | |||
| 2651 | if (!is_writable($cachedir_temp)) |
||
| 2652 | print_error('Error: Unable to obtain write access to "cache".', true); |
||
| 2653 | |||
| 2654 | // Make sure db_last_error.php is writable. |
||
| 2655 | quickFileWritable($cachedir_temp . '/db_last_error.php'); |
||
| 2656 | if (!is_writable($cachedir_temp . '/db_last_error.php')) |
||
| 2657 | print_error('Error: Unable to obtain write access to "db_last_error.php".'); |
||
| 2658 | |||
| 2659 | if (!file_exists($modSettings['theme_dir'] . '/languages/index.' . $upcontext['language'] . '.php')) |
||
| 2660 | print_error('Error: Unable to find language files!', true); |
||
| 2661 | else |
||
| 2662 | { |
||
| 2663 | $temp = substr(@implode('', @file($modSettings['theme_dir'] . '/languages/index.' . $upcontext['language'] . '.php')), 0, 4096); |
||
| 2664 | preg_match('~(?://|/\*)\s*Version:\s+(.+?);\s*index(?:[\s]{2}|\*/)~i', $temp, $match); |
||
| 2665 | |||
| 2666 | if (empty($match[1]) || $match[1] != SMF_LANG_VERSION) |
||
| 2667 | print_error('Error: Language files out of date.', true); |
||
| 2668 | if (!file_exists($modSettings['theme_dir'] . '/languages/Install.' . $upcontext['language'] . '.php')) |
||
| 2669 | print_error('Error: Install language is missing for selected language.', true); |
||
| 2670 | |||
| 2671 | // Otherwise include it! |
||
| 2672 | require_once($modSettings['theme_dir'] . '/languages/Install.' . $upcontext['language'] . '.php'); |
||
| 2673 | } |
||
| 2674 | |||
| 2675 | // Make sure we skip the HTML for login. |
||
| 2676 | $_POST['upcont'] = true; |
||
| 2677 | $upcontext['current_step'] = 1; |
||
| 2678 | } |
||
| 2679 | |||
| 2680 | /** |
||
| 2681 | * Handles converting your database to UTF-8 |
||
| 2682 | */ |
||
| 2683 | function ConvertUtf8() |
||
| 2684 | { |
||
| 2685 | global $upcontext, $db_character_set, $sourcedir, $smcFunc, $modSettings, $language; |
||
| 2686 | global $db_prefix, $db_type, $command_line, $support_js, $txt; |
||
| 2687 | |||
| 2688 | // Done it already? |
||
| 2689 | if (!empty($_POST['utf8_done'])) |
||
| 2690 | return true; |
||
| 2691 | |||
| 2692 | // First make sure they aren't already on UTF-8 before we go anywhere... |
||
| 2693 | if ($db_type == 'postgresql' || ($db_character_set === 'utf8' && !empty($modSettings['global_character_set']) && $modSettings['global_character_set'] === 'UTF-8')) |
||
| 2694 | { |
||
| 2695 | $smcFunc['db_insert']('replace', |
||
| 2696 | '{db_prefix}settings', |
||
| 2697 | array('variable' => 'string', 'value' => 'string'), |
||
| 2698 | array(array('global_character_set', 'UTF-8')), |
||
| 2699 | array('variable') |
||
| 2700 | ); |
||
| 2701 | |||
| 2702 | return true; |
||
| 2703 | } |
||
| 2704 | else |
||
| 2705 | { |
||
| 2706 | $upcontext['page_title'] = $txt['converting_utf8']; |
||
| 2707 | $upcontext['sub_template'] = isset($_GET['xml']) ? 'convert_xml' : 'convert_utf8'; |
||
| 2708 | |||
| 2709 | // The character sets used in SMF's language files with their db equivalent. |
||
| 2710 | $charsets = array( |
||
| 2711 | // Armenian |
||
| 2712 | 'armscii8' => 'armscii8', |
||
| 2713 | // Chinese-traditional. |
||
| 2714 | 'big5' => 'big5', |
||
| 2715 | // Chinese-simplified. |
||
| 2716 | 'gbk' => 'gbk', |
||
| 2717 | // West European. |
||
| 2718 | 'ISO-8859-1' => 'latin1', |
||
| 2719 | // Romanian. |
||
| 2720 | 'ISO-8859-2' => 'latin2', |
||
| 2721 | // Turkish. |
||
| 2722 | 'ISO-8859-9' => 'latin5', |
||
| 2723 | // Latvian |
||
| 2724 | 'ISO-8859-13' => 'latin7', |
||
| 2725 | // West European with Euro sign. |
||
| 2726 | 'ISO-8859-15' => 'latin9', |
||
| 2727 | // Thai. |
||
| 2728 | 'tis-620' => 'tis620', |
||
| 2729 | // Persian, Chinese, etc. |
||
| 2730 | 'UTF-8' => 'utf8', |
||
| 2731 | // Russian. |
||
| 2732 | 'windows-1251' => 'cp1251', |
||
| 2733 | // Greek. |
||
| 2734 | 'windows-1253' => 'utf8', |
||
| 2735 | // Hebrew. |
||
| 2736 | 'windows-1255' => 'utf8', |
||
| 2737 | // Arabic. |
||
| 2738 | 'windows-1256' => 'cp1256', |
||
| 2739 | ); |
||
| 2740 | |||
| 2741 | // Get a list of character sets supported by your MySQL server. |
||
| 2742 | $request = $smcFunc['db_query']('', ' |
||
| 2743 | SHOW CHARACTER SET', |
||
| 2744 | array( |
||
| 2745 | ) |
||
| 2746 | ); |
||
| 2747 | $db_charsets = array(); |
||
| 2748 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 2749 | $db_charsets[] = $row['Charset']; |
||
| 2750 | |||
| 2751 | $smcFunc['db_free_result']($request); |
||
| 2752 | |||
| 2753 | // Character sets supported by both MySQL and SMF's language files. |
||
| 2754 | $charsets = array_intersect($charsets, $db_charsets); |
||
| 2755 | |||
| 2756 | // Use the messages.body column as indicator for the database charset. |
||
| 2757 | $request = $smcFunc['db_query']('', ' |
||
| 2758 | SHOW FULL COLUMNS |
||
| 2759 | FROM {db_prefix}messages |
||
| 2760 | LIKE {string:body_like}', |
||
| 2761 | array( |
||
| 2762 | 'body_like' => 'body', |
||
| 2763 | ) |
||
| 2764 | ); |
||
| 2765 | $column_info = $smcFunc['db_fetch_assoc']($request); |
||
| 2766 | $smcFunc['db_free_result']($request); |
||
| 2767 | |||
| 2768 | // A collation looks like latin1_swedish. We only need the character set. |
||
| 2769 | list($upcontext['database_charset']) = explode('_', $column_info['Collation']); |
||
| 2770 | $upcontext['database_charset'] = in_array($upcontext['database_charset'], $charsets) ? array_search($upcontext['database_charset'], $charsets) : $upcontext['database_charset']; |
||
| 2771 | |||
| 2772 | // Detect whether a fulltext index is set. |
||
| 2773 | $request = $smcFunc['db_query']('', ' |
||
| 2774 | SHOW INDEX |
||
| 2775 | FROM {db_prefix}messages', |
||
| 2776 | array( |
||
| 2777 | ) |
||
| 2778 | ); |
||
| 2779 | |||
| 2780 | $upcontext['dropping_index'] = false; |
||
| 2781 | |||
| 2782 | // If there's a fulltext index, we need to drop it first... |
||
| 2783 | if ($request !== false || $smcFunc['db_num_rows']($request) != 0) |
||
| 2784 | { |
||
| 2785 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 2786 | if ($row['Column_name'] == 'body' && (isset($row['Index_type']) && $row['Index_type'] == 'FULLTEXT' || isset($row['Comment']) && $row['Comment'] == 'FULLTEXT')) |
||
| 2787 | $upcontext['fulltext_index'][] = $row['Key_name']; |
||
| 2788 | $smcFunc['db_free_result']($request); |
||
| 2789 | |||
| 2790 | if (isset($upcontext['fulltext_index'])) |
||
| 2791 | $upcontext['fulltext_index'] = array_unique($upcontext['fulltext_index']); |
||
| 2792 | } |
||
| 2793 | |||
| 2794 | // Drop it and make a note... |
||
| 2795 | if (!empty($upcontext['fulltext_index'])) |
||
| 2796 | { |
||
| 2797 | $upcontext['dropping_index'] = true; |
||
| 2798 | |||
| 2799 | $smcFunc['db_query']('', ' |
||
| 2800 | ALTER TABLE {db_prefix}messages |
||
| 2801 | DROP INDEX ' . implode(', |
||
| 2802 | DROP INDEX ', $upcontext['fulltext_index']), |
||
| 2803 | array( |
||
| 2804 | 'db_error_skip' => true, |
||
| 2805 | ) |
||
| 2806 | ); |
||
| 2807 | |||
| 2808 | // Update the settings table |
||
| 2809 | $smcFunc['db_insert']('replace', |
||
| 2810 | '{db_prefix}settings', |
||
| 2811 | array('variable' => 'string', 'value' => 'string'), |
||
| 2812 | array('db_search_index', ''), |
||
| 2813 | array('variable') |
||
| 2814 | ); |
||
| 2815 | } |
||
| 2816 | |||
| 2817 | // Figure out what charset we should be converting from... |
||
| 2818 | $lang_charsets = array( |
||
| 2819 | 'arabic' => 'windows-1256', |
||
| 2820 | 'armenian_east' => 'armscii-8', |
||
| 2821 | 'armenian_west' => 'armscii-8', |
||
| 2822 | 'azerbaijani_latin' => 'ISO-8859-9', |
||
| 2823 | 'bangla' => 'UTF-8', |
||
| 2824 | 'belarusian' => 'ISO-8859-5', |
||
| 2825 | 'bulgarian' => 'windows-1251', |
||
| 2826 | 'cambodian' => 'UTF-8', |
||
| 2827 | 'chinese_simplified' => 'gbk', |
||
| 2828 | 'chinese_traditional' => 'big5', |
||
| 2829 | 'croation' => 'ISO-8859-2', |
||
| 2830 | 'czech' => 'ISO-8859-2', |
||
| 2831 | 'czech_informal' => 'ISO-8859-2', |
||
| 2832 | 'english_pirate' => 'UTF-8', |
||
| 2833 | 'esperanto' => 'ISO-8859-3', |
||
| 2834 | 'estonian' => 'ISO-8859-15', |
||
| 2835 | 'filipino_tagalog' => 'UTF-8', |
||
| 2836 | 'filipino_vasayan' => 'UTF-8', |
||
| 2837 | 'georgian' => 'UTF-8', |
||
| 2838 | 'greek' => 'ISO-8859-3', |
||
| 2839 | 'hebrew' => 'windows-1255', |
||
| 2840 | 'hungarian' => 'ISO-8859-2', |
||
| 2841 | 'irish' => 'UTF-8', |
||
| 2842 | 'japanese' => 'UTF-8', |
||
| 2843 | 'khmer' => 'UTF-8', |
||
| 2844 | 'korean' => 'UTF-8', |
||
| 2845 | 'kurdish_kurmanji' => 'ISO-8859-9', |
||
| 2846 | 'kurdish_sorani' => 'windows-1256', |
||
| 2847 | 'lao' => 'tis-620', |
||
| 2848 | 'latvian' => 'ISO-8859-13', |
||
| 2849 | 'lithuanian' => 'ISO-8859-4', |
||
| 2850 | 'macedonian' => 'UTF-8', |
||
| 2851 | 'malayalam' => 'UTF-8', |
||
| 2852 | 'mongolian' => 'UTF-8', |
||
| 2853 | 'nepali' => 'UTF-8', |
||
| 2854 | 'persian' => 'UTF-8', |
||
| 2855 | 'polish' => 'ISO-8859-2', |
||
| 2856 | 'romanian' => 'ISO-8859-2', |
||
| 2857 | 'russian' => 'windows-1252', |
||
| 2858 | 'sakha' => 'UTF-8', |
||
| 2859 | 'serbian_cyrillic' => 'ISO-8859-5', |
||
| 2860 | 'serbian_latin' => 'ISO-8859-2', |
||
| 2861 | 'sinhala' => 'UTF-8', |
||
| 2862 | 'slovak' => 'ISO-8859-2', |
||
| 2863 | 'slovenian' => 'ISO-8859-2', |
||
| 2864 | 'telugu' => 'UTF-8', |
||
| 2865 | 'thai' => 'tis-620', |
||
| 2866 | 'turkish' => 'ISO-8859-9', |
||
| 2867 | 'turkmen' => 'ISO-8859-9', |
||
| 2868 | 'ukranian' => 'windows-1251', |
||
| 2869 | 'urdu' => 'UTF-8', |
||
| 2870 | 'uzbek_cyrillic' => 'ISO-8859-5', |
||
| 2871 | 'uzbek_latin' => 'ISO-8859-5', |
||
| 2872 | 'vietnamese' => 'UTF-8', |
||
| 2873 | 'yoruba' => 'UTF-8' |
||
| 2874 | ); |
||
| 2875 | |||
| 2876 | // Default to ISO-8859-1 unless we detected another supported charset |
||
| 2877 | $upcontext['charset_detected'] = (isset($lang_charsets[$language]) && isset($charsets[strtr(strtolower($upcontext['charset_detected']), array('utf' => 'UTF', 'iso' => 'ISO'))])) ? $lang_charsets[$language] : 'ISO-8859-1'; |
||
| 2878 | |||
| 2879 | $upcontext['charset_list'] = array_keys($charsets); |
||
| 2880 | |||
| 2881 | // Translation table for the character sets not native for MySQL. |
||
| 2882 | $translation_tables = array( |
||
| 2883 | 'windows-1255' => array( |
||
| 2884 | '0x81' => '\'\'', '0x8A' => '\'\'', '0x8C' => '\'\'', |
||
| 2885 | '0x8D' => '\'\'', '0x8E' => '\'\'', '0x8F' => '\'\'', |
||
| 2886 | '0x90' => '\'\'', '0x9A' => '\'\'', '0x9C' => '\'\'', |
||
| 2887 | '0x9D' => '\'\'', '0x9E' => '\'\'', '0x9F' => '\'\'', |
||
| 2888 | '0xCA' => '\'\'', '0xD9' => '\'\'', '0xDA' => '\'\'', |
||
| 2889 | '0xDB' => '\'\'', '0xDC' => '\'\'', '0xDD' => '\'\'', |
||
| 2890 | '0xDE' => '\'\'', '0xDF' => '\'\'', '0xFB' => '0xD792', |
||
| 2891 | '0xFC' => '0xE282AC', '0xFF' => '0xD6B2', '0xC2' => '0xFF', |
||
| 2892 | '0x80' => '0xFC', '0xE2' => '0xFB', '0xA0' => '0xC2A0', |
||
| 2893 | '0xA1' => '0xC2A1', '0xA2' => '0xC2A2', '0xA3' => '0xC2A3', |
||
| 2894 | '0xA5' => '0xC2A5', '0xA6' => '0xC2A6', '0xA7' => '0xC2A7', |
||
| 2895 | '0xA8' => '0xC2A8', '0xA9' => '0xC2A9', '0xAB' => '0xC2AB', |
||
| 2896 | '0xAC' => '0xC2AC', '0xAD' => '0xC2AD', '0xAE' => '0xC2AE', |
||
| 2897 | '0xAF' => '0xC2AF', '0xB0' => '0xC2B0', '0xB1' => '0xC2B1', |
||
| 2898 | '0xB2' => '0xC2B2', '0xB3' => '0xC2B3', '0xB4' => '0xC2B4', |
||
| 2899 | '0xB5' => '0xC2B5', '0xB6' => '0xC2B6', '0xB7' => '0xC2B7', |
||
| 2900 | '0xB8' => '0xC2B8', '0xB9' => '0xC2B9', '0xBB' => '0xC2BB', |
||
| 2901 | '0xBC' => '0xC2BC', '0xBD' => '0xC2BD', '0xBE' => '0xC2BE', |
||
| 2902 | '0xBF' => '0xC2BF', '0xD7' => '0xD7B3', '0xD1' => '0xD781', |
||
| 2903 | '0xD4' => '0xD7B0', '0xD5' => '0xD7B1', '0xD6' => '0xD7B2', |
||
| 2904 | '0xE0' => '0xD790', '0xEA' => '0xD79A', '0xEC' => '0xD79C', |
||
| 2905 | '0xED' => '0xD79D', '0xEE' => '0xD79E', '0xEF' => '0xD79F', |
||
| 2906 | '0xF0' => '0xD7A0', '0xF1' => '0xD7A1', '0xF2' => '0xD7A2', |
||
| 2907 | '0xF3' => '0xD7A3', '0xF5' => '0xD7A5', '0xF6' => '0xD7A6', |
||
| 2908 | '0xF7' => '0xD7A7', '0xF8' => '0xD7A8', '0xF9' => '0xD7A9', |
||
| 2909 | '0x82' => '0xE2809A', '0x84' => '0xE2809E', '0x85' => '0xE280A6', |
||
| 2910 | '0x86' => '0xE280A0', '0x87' => '0xE280A1', '0x89' => '0xE280B0', |
||
| 2911 | '0x8B' => '0xE280B9', '0x93' => '0xE2809C', '0x94' => '0xE2809D', |
||
| 2912 | '0x95' => '0xE280A2', '0x97' => '0xE28094', '0x99' => '0xE284A2', |
||
| 2913 | '0xC0' => '0xD6B0', '0xC1' => '0xD6B1', '0xC3' => '0xD6B3', |
||
| 2914 | '0xC4' => '0xD6B4', '0xC5' => '0xD6B5', '0xC6' => '0xD6B6', |
||
| 2915 | '0xC7' => '0xD6B7', '0xC8' => '0xD6B8', '0xC9' => '0xD6B9', |
||
| 2916 | '0xCB' => '0xD6BB', '0xCC' => '0xD6BC', '0xCD' => '0xD6BD', |
||
| 2917 | '0xCE' => '0xD6BE', '0xCF' => '0xD6BF', '0xD0' => '0xD780', |
||
| 2918 | '0xD2' => '0xD782', '0xE3' => '0xD793', '0xE4' => '0xD794', |
||
| 2919 | '0xE5' => '0xD795', '0xE7' => '0xD797', '0xE9' => '0xD799', |
||
| 2920 | '0xFD' => '0xE2808E', '0xFE' => '0xE2808F', '0x92' => '0xE28099', |
||
| 2921 | '0x83' => '0xC692', '0xD3' => '0xD783', '0x88' => '0xCB86', |
||
| 2922 | '0x98' => '0xCB9C', '0x91' => '0xE28098', '0x96' => '0xE28093', |
||
| 2923 | '0xBA' => '0xC3B7', '0x9B' => '0xE280BA', '0xAA' => '0xC397', |
||
| 2924 | '0xA4' => '0xE282AA', '0xE1' => '0xD791', '0xE6' => '0xD796', |
||
| 2925 | '0xE8' => '0xD798', '0xEB' => '0xD79B', '0xF4' => '0xD7A4', |
||
| 2926 | '0xFA' => '0xD7AA', |
||
| 2927 | ), |
||
| 2928 | 'windows-1253' => array( |
||
| 2929 | '0x81' => '\'\'', '0x88' => '\'\'', '0x8A' => '\'\'', |
||
| 2930 | '0x8C' => '\'\'', '0x8D' => '\'\'', '0x8E' => '\'\'', |
||
| 2931 | '0x8F' => '\'\'', '0x90' => '\'\'', '0x98' => '\'\'', |
||
| 2932 | '0x9A' => '\'\'', '0x9C' => '\'\'', '0x9D' => '\'\'', |
||
| 2933 | '0x9E' => '\'\'', '0x9F' => '\'\'', '0xAA' => '\'\'', |
||
| 2934 | '0xD2' => '0xE282AC', '0xFF' => '0xCE92', '0xCE' => '0xCE9E', |
||
| 2935 | '0xB8' => '0xCE88', '0xBA' => '0xCE8A', '0xBC' => '0xCE8C', |
||
| 2936 | '0xBE' => '0xCE8E', '0xBF' => '0xCE8F', '0xC0' => '0xCE90', |
||
| 2937 | '0xC8' => '0xCE98', '0xCA' => '0xCE9A', '0xCC' => '0xCE9C', |
||
| 2938 | '0xCD' => '0xCE9D', '0xCF' => '0xCE9F', '0xDA' => '0xCEAA', |
||
| 2939 | '0xE8' => '0xCEB8', '0xEA' => '0xCEBA', '0xEC' => '0xCEBC', |
||
| 2940 | '0xEE' => '0xCEBE', '0xEF' => '0xCEBF', '0xC2' => '0xFF', |
||
| 2941 | '0xBD' => '0xC2BD', '0xED' => '0xCEBD', '0xB2' => '0xC2B2', |
||
| 2942 | '0xA0' => '0xC2A0', '0xA3' => '0xC2A3', '0xA4' => '0xC2A4', |
||
| 2943 | '0xA5' => '0xC2A5', '0xA6' => '0xC2A6', '0xA7' => '0xC2A7', |
||
| 2944 | '0xA8' => '0xC2A8', '0xA9' => '0xC2A9', '0xAB' => '0xC2AB', |
||
| 2945 | '0xAC' => '0xC2AC', '0xAD' => '0xC2AD', '0xAE' => '0xC2AE', |
||
| 2946 | '0xB0' => '0xC2B0', '0xB1' => '0xC2B1', '0xB3' => '0xC2B3', |
||
| 2947 | '0xB5' => '0xC2B5', '0xB6' => '0xC2B6', '0xB7' => '0xC2B7', |
||
| 2948 | '0xBB' => '0xC2BB', '0xE2' => '0xCEB2', '0x80' => '0xD2', |
||
| 2949 | '0x82' => '0xE2809A', '0x84' => '0xE2809E', '0x85' => '0xE280A6', |
||
| 2950 | '0x86' => '0xE280A0', '0xA1' => '0xCE85', '0xA2' => '0xCE86', |
||
| 2951 | '0x87' => '0xE280A1', '0x89' => '0xE280B0', '0xB9' => '0xCE89', |
||
| 2952 | '0x8B' => '0xE280B9', '0x91' => '0xE28098', '0x99' => '0xE284A2', |
||
| 2953 | '0x92' => '0xE28099', '0x93' => '0xE2809C', '0x94' => '0xE2809D', |
||
| 2954 | '0x95' => '0xE280A2', '0x96' => '0xE28093', '0x97' => '0xE28094', |
||
| 2955 | '0x9B' => '0xE280BA', '0xAF' => '0xE28095', '0xB4' => '0xCE84', |
||
| 2956 | '0xC1' => '0xCE91', '0xC3' => '0xCE93', '0xC4' => '0xCE94', |
||
| 2957 | '0xC5' => '0xCE95', '0xC6' => '0xCE96', '0x83' => '0xC692', |
||
| 2958 | '0xC7' => '0xCE97', '0xC9' => '0xCE99', '0xCB' => '0xCE9B', |
||
| 2959 | '0xD0' => '0xCEA0', '0xD1' => '0xCEA1', '0xD3' => '0xCEA3', |
||
| 2960 | '0xD4' => '0xCEA4', '0xD5' => '0xCEA5', '0xD6' => '0xCEA6', |
||
| 2961 | '0xD7' => '0xCEA7', '0xD8' => '0xCEA8', '0xD9' => '0xCEA9', |
||
| 2962 | '0xDB' => '0xCEAB', '0xDC' => '0xCEAC', '0xDD' => '0xCEAD', |
||
| 2963 | '0xDE' => '0xCEAE', '0xDF' => '0xCEAF', '0xE0' => '0xCEB0', |
||
| 2964 | '0xE1' => '0xCEB1', '0xE3' => '0xCEB3', '0xE4' => '0xCEB4', |
||
| 2965 | '0xE5' => '0xCEB5', '0xE6' => '0xCEB6', '0xE7' => '0xCEB7', |
||
| 2966 | '0xE9' => '0xCEB9', '0xEB' => '0xCEBB', '0xF0' => '0xCF80', |
||
| 2967 | '0xF1' => '0xCF81', '0xF2' => '0xCF82', '0xF3' => '0xCF83', |
||
| 2968 | '0xF4' => '0xCF84', '0xF5' => '0xCF85', '0xF6' => '0xCF86', |
||
| 2969 | '0xF7' => '0xCF87', '0xF8' => '0xCF88', '0xF9' => '0xCF89', |
||
| 2970 | '0xFA' => '0xCF8A', '0xFB' => '0xCF8B', '0xFC' => '0xCF8C', |
||
| 2971 | '0xFD' => '0xCF8D', '0xFE' => '0xCF8E', |
||
| 2972 | ), |
||
| 2973 | ); |
||
| 2974 | |||
| 2975 | // Make some preparations. |
||
| 2976 | if (isset($translation_tables[$upcontext['charset_detected']])) |
||
| 2977 | { |
||
| 2978 | $replace = '%field%'; |
||
| 2979 | |||
| 2980 | // Build a huge REPLACE statement... |
||
| 2981 | foreach ($translation_tables[$upcontext['charset_detected']] as $from => $to) |
||
| 2982 | $replace = 'REPLACE(' . $replace . ', ' . $from . ', ' . $to . ')'; |
||
| 2983 | } |
||
| 2984 | |||
| 2985 | // Get a list of table names ahead of time... This makes it easier to set our substep and such |
||
| 2986 | db_extend(); |
||
| 2987 | $queryTables = $smcFunc['db_list_tables'](false, $db_prefix . '%'); |
||
| 2988 | |||
| 2989 | $upcontext['table_count'] = count($queryTables); |
||
| 2990 | |||
| 2991 | // What ones have we already done? |
||
| 2992 | foreach ($queryTables as $id => $table) |
||
| 2993 | if ($id < $_GET['substep']) |
||
| 2994 | $upcontext['previous_tables'][] = $table; |
||
| 2995 | |||
| 2996 | $upcontext['cur_table_num'] = $_GET['substep']; |
||
| 2997 | $upcontext['cur_table_name'] = str_replace($db_prefix, '', $queryTables[$_GET['substep']]); |
||
| 2998 | $upcontext['step_progress'] = (int) (($upcontext['cur_table_num'] / $upcontext['table_count']) * 100); |
||
| 2999 | |||
| 3000 | // Make sure we're ready & have painted the template before proceeding |
||
| 3001 | if ($support_js && !isset($_GET['xml'])) |
||
| 3002 | { |
||
| 3003 | $_GET['substep'] = 0; |
||
| 3004 | return false; |
||
| 3005 | } |
||
| 3006 | |||
| 3007 | // We want to start at the first table. |
||
| 3008 | for ($substep = $_GET['substep'], $n = count($queryTables); $substep < $n; $substep++) |
||
| 3009 | { |
||
| 3010 | $table = $queryTables[$substep]; |
||
| 3011 | |||
| 3012 | $getTableStatus = $smcFunc['db_query']('', ' |
||
| 3013 | SHOW TABLE STATUS |
||
| 3014 | LIKE {string:table_name}', |
||
| 3015 | array( |
||
| 3016 | 'table_name' => str_replace('_', '\_', $table) |
||
| 3017 | ) |
||
| 3018 | ); |
||
| 3019 | |||
| 3020 | // Only one row so we can just fetch_assoc and free the result... |
||
| 3021 | $table_info = $smcFunc['db_fetch_assoc']($getTableStatus); |
||
| 3022 | $smcFunc['db_free_result']($getTableStatus); |
||
| 3023 | |||
| 3024 | $upcontext['cur_table_name'] = str_replace($db_prefix, '', (isset($queryTables[$substep + 1]) ? $queryTables[$substep + 1] : $queryTables[$substep])); |
||
| 3025 | $upcontext['cur_table_num'] = $substep + 1; |
||
| 3026 | $upcontext['step_progress'] = (int) (($upcontext['cur_table_num'] / $upcontext['table_count']) * 100); |
||
| 3027 | |||
| 3028 | // Do we need to pause? |
||
| 3029 | nextSubstep($substep); |
||
| 3030 | |||
| 3031 | // Just to make sure it doesn't time out. |
||
| 3032 | if (function_exists('apache_reset_timeout')) |
||
| 3033 | @apache_reset_timeout(); |
||
| 3034 | |||
| 3035 | $table_charsets = array(); |
||
| 3036 | |||
| 3037 | // Loop through each column. |
||
| 3038 | $queryColumns = $smcFunc['db_query']('', ' |
||
| 3039 | SHOW FULL COLUMNS |
||
| 3040 | FROM ' . $table_info['Name'], |
||
| 3041 | array( |
||
| 3042 | ) |
||
| 3043 | ); |
||
| 3044 | while ($column_info = $smcFunc['db_fetch_assoc']($queryColumns)) |
||
| 3045 | { |
||
| 3046 | // Only text'ish columns have a character set and need converting. |
||
| 3047 | if (strpos($column_info['Type'], 'text') !== false || strpos($column_info['Type'], 'char') !== false) |
||
| 3048 | { |
||
| 3049 | $collation = empty($column_info['Collation']) || $column_info['Collation'] === 'NULL' ? $table_info['Collation'] : $column_info['Collation']; |
||
| 3050 | if (!empty($collation) && $collation !== 'NULL') |
||
| 3051 | { |
||
| 3052 | list($charset) = explode('_', $collation); |
||
| 3053 | |||
| 3054 | // Build structure of columns to operate on organized by charset; only operate on columns not yet utf8 |
||
| 3055 | if ($charset != 'utf8') |
||
| 3056 | { |
||
| 3057 | if (!isset($table_charsets[$charset])) |
||
| 3058 | $table_charsets[$charset] = array(); |
||
| 3059 | |||
| 3060 | $table_charsets[$charset][] = $column_info; |
||
| 3061 | } |
||
| 3062 | } |
||
| 3063 | } |
||
| 3064 | } |
||
| 3065 | $smcFunc['db_free_result']($queryColumns); |
||
| 3066 | |||
| 3067 | // Only change the non-utf8 columns identified above |
||
| 3068 | if (count($table_charsets) > 0) |
||
| 3069 | { |
||
| 3070 | $updates_blob = ''; |
||
| 3071 | $updates_text = ''; |
||
| 3072 | foreach ($table_charsets as $charset => $columns) |
||
| 3073 | { |
||
| 3074 | if ($charset !== $charsets[$upcontext['charset_detected']]) |
||
| 3075 | { |
||
| 3076 | foreach ($columns as $column) |
||
| 3077 | { |
||
| 3078 | $updates_blob .= ' |
||
| 3079 | CHANGE COLUMN `' . $column['Field'] . '` `' . $column['Field'] . '` ' . strtr($column['Type'], array('text' => 'blob', 'char' => 'binary')) . ($column['Null'] === 'YES' ? ' NULL' : ' NOT NULL') . (strpos($column['Type'], 'char') === false ? '' : ' default \'' . $column['Default'] . '\'') . ','; |
||
| 3080 | $updates_text .= ' |
||
| 3081 | CHANGE COLUMN `' . $column['Field'] . '` `' . $column['Field'] . '` ' . $column['Type'] . ' CHARACTER SET ' . $charsets[$upcontext['charset_detected']] . ($column['Null'] === 'YES' ? '' : ' NOT NULL') . (strpos($column['Type'], 'char') === false ? '' : ' default \'' . $column['Default'] . '\'') . ','; |
||
| 3082 | } |
||
| 3083 | } |
||
| 3084 | } |
||
| 3085 | |||
| 3086 | // Change the columns to binary form. |
||
| 3087 | $smcFunc['db_query']('', ' |
||
| 3088 | ALTER TABLE {raw:table_name}{raw:updates_blob}', |
||
| 3089 | array( |
||
| 3090 | 'table_name' => $table_info['Name'], |
||
| 3091 | 'updates_blob' => substr($updates_blob, 0, -1), |
||
| 3092 | ) |
||
| 3093 | ); |
||
| 3094 | |||
| 3095 | // Convert the character set if MySQL has no native support for it. |
||
| 3096 | if (isset($translation_tables[$upcontext['charset_detected']])) |
||
| 3097 | { |
||
| 3098 | $update = ''; |
||
| 3099 | foreach ($table_charsets as $charset => $columns) |
||
| 3100 | foreach ($columns as $column) |
||
| 3101 | $update .= ' |
||
| 3102 | ' . $column['Field'] . ' = ' . strtr($replace, array('%field%' => $column['Field'])) . ','; |
||
| 3103 | |||
| 3104 | $smcFunc['db_query']('', ' |
||
| 3105 | UPDATE {raw:table_name} |
||
| 3106 | SET {raw:updates}', |
||
| 3107 | array( |
||
| 3108 | 'table_name' => $table_info['Name'], |
||
| 3109 | 'updates' => substr($update, 0, -1), |
||
| 3110 | ) |
||
| 3111 | ); |
||
| 3112 | } |
||
| 3113 | |||
| 3114 | // Change the columns back, but with the proper character set. |
||
| 3115 | $smcFunc['db_query']('', ' |
||
| 3116 | ALTER TABLE {raw:table_name}{raw:updates_text}', |
||
| 3117 | array( |
||
| 3118 | 'table_name' => $table_info['Name'], |
||
| 3119 | 'updates_text' => substr($updates_text, 0, -1), |
||
| 3120 | ) |
||
| 3121 | ); |
||
| 3122 | } |
||
| 3123 | |||
| 3124 | // Now do the actual conversion (if still needed). |
||
| 3125 | if ($charsets[$upcontext['charset_detected']] !== 'utf8') |
||
| 3126 | { |
||
| 3127 | if ($command_line) |
||
| 3128 | echo 'Converting table ' . $table_info['Name'] . ' to UTF-8...'; |
||
| 3129 | |||
| 3130 | $smcFunc['db_query']('', ' |
||
| 3131 | ALTER TABLE {raw:table_name} |
||
| 3132 | CONVERT TO CHARACTER SET utf8', |
||
| 3133 | array( |
||
| 3134 | 'table_name' => $table_info['Name'], |
||
| 3135 | ) |
||
| 3136 | ); |
||
| 3137 | |||
| 3138 | if ($command_line) |
||
| 3139 | echo " done.\n"; |
||
| 3140 | } |
||
| 3141 | // If this is XML to keep it nice for the user do one table at a time anyway! |
||
| 3142 | if (isset($_GET['xml']) && $upcontext['cur_table_num'] < $upcontext['table_count']) |
||
| 3143 | return upgradeExit(); |
||
| 3144 | } |
||
| 3145 | |||
| 3146 | $prev_charset = empty($translation_tables[$upcontext['charset_detected']]) ? $charsets[$upcontext['charset_detected']] : $translation_tables[$upcontext['charset_detected']]; |
||
| 3147 | |||
| 3148 | $smcFunc['db_insert']('replace', |
||
| 3149 | '{db_prefix}settings', |
||
| 3150 | array('variable' => 'string', 'value' => 'string'), |
||
| 3151 | array(array('global_character_set', 'UTF-8'), array('previousCharacterSet', $prev_charset)), |
||
| 3152 | array('variable') |
||
| 3153 | ); |
||
| 3154 | |||
| 3155 | // Store it in Settings.php too because it's needed before db connection. |
||
| 3156 | // Hopefully this works... |
||
| 3157 | require_once($sourcedir . '/Subs-Admin.php'); |
||
| 3158 | updateSettingsFile(array('db_character_set' => '\'utf8\'')); |
||
| 3159 | |||
| 3160 | // The conversion might have messed up some serialized strings. Fix them! |
||
| 3161 | $request = $smcFunc['db_query']('', ' |
||
| 3162 | SELECT id_action, extra |
||
| 3163 | FROM {db_prefix}log_actions |
||
| 3164 | WHERE action IN ({string:remove}, {string:delete})', |
||
| 3165 | array( |
||
| 3166 | 'remove' => 'remove', |
||
| 3167 | 'delete' => 'delete', |
||
| 3168 | ) |
||
| 3169 | ); |
||
| 3170 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 3171 | { |
||
| 3172 | if (@safe_unserialize($row['extra']) === false && preg_match('~^(a:3:{s:5:"topic";i:\d+;s:7:"subject";s:)(\d+):"(.+)"(;s:6:"member";s:5:"\d+";})$~', $row['extra'], $matches) === 1) |
||
| 3173 | $smcFunc['db_query']('', ' |
||
| 3174 | UPDATE {db_prefix}log_actions |
||
| 3175 | SET extra = {string:extra} |
||
| 3176 | WHERE id_action = {int:current_action}', |
||
| 3177 | array( |
||
| 3178 | 'current_action' => $row['id_action'], |
||
| 3179 | 'extra' => $matches[1] . strlen($matches[3]) . ':"' . $matches[3] . '"' . $matches[4], |
||
| 3180 | ) |
||
| 3181 | ); |
||
| 3182 | } |
||
| 3183 | $smcFunc['db_free_result']($request); |
||
| 3184 | |||
| 3185 | if ($upcontext['dropping_index'] && $command_line) |
||
| 3186 | { |
||
| 3187 | echo "\n" . '', $txt['upgrade_fulltext_error'], ''; |
||
| 3188 | flush(); |
||
| 3189 | } |
||
| 3190 | } |
||
| 3191 | $_GET['substep'] = 0; |
||
| 3192 | return false; |
||
| 3193 | } |
||
| 3194 | |||
| 3195 | /** |
||
| 3196 | * Attempts to repair corrupted serialized data strings |
||
| 3197 | * |
||
| 3198 | * @param string $string Serialized data that has been corrupted |
||
| 3199 | * @return string|bool A working version of the serialized data, or the original if the repair failed |
||
| 3200 | */ |
||
| 3201 | function fix_serialized_data($string) |
||
| 3202 | { |
||
| 3203 | // If its not broken, don't fix it. |
||
| 3204 | if (!is_string($string) || !preg_match('/^[bidsa]:/', $string) || @safe_unserialize($string) !== false) |
||
| 3205 | return $string; |
||
| 3206 | |||
| 3207 | // This bit fixes incorrect string lengths, which can happen if the character encoding was changed (e.g. conversion to UTF-8) |
||
| 3208 | $new_string = preg_replace_callback('~\bs:(\d+):"(.*?)";(?=$|[bidsa]:|[{}]|N;)~s', function ($matches) {return 's:' . strlen($matches[2]) . ':"' . $matches[2] . '";';}, $string); |
||
| 3209 | |||
| 3210 | // @todo Add more possible fixes here. For example, fix incorrect array lengths, try to handle truncated strings gracefully, etc. |
||
| 3211 | |||
| 3212 | // Did it work? |
||
| 3213 | if (@safe_unserialize($new_string) !== false) |
||
| 3214 | return $new_string; |
||
| 3215 | else |
||
| 3216 | return $string; |
||
| 3217 | } |
||
| 3218 | |||
| 3219 | function serialize_to_json() |
||
| 3220 | { |
||
| 3221 | global $command_line, $smcFunc, $modSettings, $sourcedir, $upcontext, $support_js, $txt; |
||
| 3222 | |||
| 3223 | $upcontext['sub_template'] = isset($_GET['xml']) ? 'serialize_json_xml' : 'serialize_json'; |
||
| 3224 | // First thing's first - did we already do this? |
||
| 3225 | if (!empty($modSettings['json_done'])) |
||
| 3226 | { |
||
| 3227 | if ($command_line) |
||
| 3228 | return ConvertUtf8(); |
||
| 3229 | else |
||
| 3230 | return true; |
||
| 3231 | } |
||
| 3232 | |||
| 3233 | // Done it already - js wise? |
||
| 3234 | if (!empty($_POST['json_done'])) |
||
| 3235 | return true; |
||
| 3236 | |||
| 3237 | // List of tables affected by this function |
||
| 3238 | // name => array('key', col1[,col2|true[,col3]]) |
||
| 3239 | // If 3rd item in array is true, it indicates that col1 could be empty... |
||
| 3240 | $tables = array( |
||
| 3241 | 'background_tasks' => array('id_task', 'task_data'), |
||
| 3242 | 'log_actions' => array('id_action', 'extra'), |
||
| 3243 | 'log_online' => array('session', 'url'), |
||
| 3244 | 'log_packages' => array('id_install', 'db_changes', 'failed_steps', 'credits'), |
||
| 3245 | 'log_spider_hits' => array('id_hit', 'url'), |
||
| 3246 | 'log_subscribed' => array('id_sublog', 'pending_details'), |
||
| 3247 | 'pm_rules' => array('id_rule', 'criteria', 'actions'), |
||
| 3248 | 'qanda' => array('id_question', 'answers'), |
||
| 3249 | 'subscriptions' => array('id_subscribe', 'cost'), |
||
| 3250 | 'user_alerts' => array('id_alert', 'extra', true), |
||
| 3251 | 'user_drafts' => array('id_draft', 'to_list', true), |
||
| 3252 | // These last two are a bit different - we'll handle those separately |
||
| 3253 | 'settings' => array(), |
||
| 3254 | 'themes' => array() |
||
| 3255 | ); |
||
| 3256 | |||
| 3257 | // Set up some context stuff... |
||
| 3258 | // Because we're not using numeric indices, we need this to figure out the current table name... |
||
| 3259 | $keys = array_keys($tables); |
||
| 3260 | |||
| 3261 | $upcontext['page_title'] = $txt['converting_json']; |
||
| 3262 | $upcontext['table_count'] = count($keys); |
||
| 3263 | $upcontext['cur_table_num'] = $_GET['substep']; |
||
| 3264 | $upcontext['cur_table_name'] = isset($keys[$_GET['substep']]) ? $keys[$_GET['substep']] : $keys[0]; |
||
| 3265 | $upcontext['step_progress'] = (int) (($upcontext['cur_table_num'] / $upcontext['table_count']) * 100); |
||
| 3266 | |||
| 3267 | foreach ($keys as $id => $table) |
||
| 3268 | if ($id < $_GET['substep']) |
||
| 3269 | $upcontext['previous_tables'][] = $table; |
||
| 3270 | |||
| 3271 | if ($command_line) |
||
| 3272 | echo 'Converting data from serialize() to json_encode().'; |
||
| 3273 | |||
| 3274 | if (!$support_js || isset($_GET['xml'])) |
||
| 3275 | { |
||
| 3276 | // Fix the data in each table |
||
| 3277 | for ($substep = $_GET['substep']; $substep < $upcontext['table_count']; $substep++) |
||
| 3278 | { |
||
| 3279 | $upcontext['cur_table_name'] = isset($keys[$substep + 1]) ? $keys[$substep + 1] : $keys[$substep]; |
||
| 3280 | $upcontext['cur_table_num'] = $substep + 1; |
||
| 3281 | |||
| 3282 | $upcontext['step_progress'] = (int) (($upcontext['cur_table_num'] / $upcontext['table_count']) * 100); |
||
| 3283 | |||
| 3284 | // Do we need to pause? |
||
| 3285 | nextSubstep($substep); |
||
| 3286 | |||
| 3287 | // Initialize a few things... |
||
| 3288 | $where = ''; |
||
| 3289 | $vars = array(); |
||
| 3290 | $table = $keys[$substep]; |
||
| 3291 | $info = $tables[$table]; |
||
| 3292 | |||
| 3293 | // Now the fun - build our queries and all that fun stuff |
||
| 3294 | if ($table == 'settings') |
||
| 3295 | { |
||
| 3296 | // Now a few settings... |
||
| 3297 | $serialized_settings = array( |
||
| 3298 | 'attachment_basedirectories', |
||
| 3299 | 'attachmentUploadDir', |
||
| 3300 | 'cal_today_birthday', |
||
| 3301 | 'cal_today_event', |
||
| 3302 | 'cal_today_holiday', |
||
| 3303 | 'displayFields', |
||
| 3304 | 'last_attachments_directory', |
||
| 3305 | 'memberlist_cache', |
||
| 3306 | 'search_custom_index_config', |
||
| 3307 | 'spider_name_cache' |
||
| 3308 | ); |
||
| 3309 | |||
| 3310 | // Loop through and fix these... |
||
| 3311 | $new_settings = array(); |
||
| 3312 | if ($command_line) |
||
| 3313 | echo "\n" . 'Fixing some settings...'; |
||
| 3314 | |||
| 3315 | foreach ($serialized_settings as $var) |
||
| 3316 | { |
||
| 3317 | if (isset($modSettings[$var])) |
||
| 3318 | { |
||
| 3319 | // Attempt to unserialize the setting |
||
| 3320 | $temp = @safe_unserialize($modSettings[$var]); |
||
| 3321 | // Maybe conversion to UTF-8 corrupted it |
||
| 3322 | if ($temp === false) |
||
| 3323 | $temp = @safe_unserialize(fix_serialized_data($modSettings[$var])); |
||
| 3324 | |||
| 3325 | if (!$temp && $command_line) |
||
| 3326 | echo "\n - Failed to unserialize the '" . $var . "' setting. Skipping."; |
||
| 3327 | elseif ($temp !== false) |
||
| 3328 | $new_settings[$var] = json_encode($temp); |
||
| 3329 | } |
||
| 3330 | } |
||
| 3331 | |||
| 3332 | // Update everything at once |
||
| 3333 | if (!function_exists('cache_put_data')) |
||
| 3334 | require_once($sourcedir . '/Load.php'); |
||
| 3335 | updateSettings($new_settings, true); |
||
| 3336 | |||
| 3337 | if ($command_line) |
||
| 3338 | echo ' done.'; |
||
| 3339 | } |
||
| 3340 | elseif ($table == 'themes') |
||
| 3341 | { |
||
| 3342 | // Finally, fix the admin prefs. Unfortunately this is stored per theme, but hopefully they only have one theme installed at this point... |
||
| 3343 | $query = $smcFunc['db_query']('', ' |
||
| 3344 | SELECT id_member, id_theme, value FROM {db_prefix}themes |
||
| 3345 | WHERE variable = {string:admin_prefs}', |
||
| 3346 | array( |
||
| 3347 | 'admin_prefs' => 'admin_preferences' |
||
| 3348 | ) |
||
| 3349 | ); |
||
| 3350 | |||
| 3351 | if ($smcFunc['db_num_rows']($query) != 0) |
||
| 3352 | { |
||
| 3353 | while ($row = $smcFunc['db_fetch_assoc']($query)) |
||
| 3354 | { |
||
| 3355 | $temp = @safe_unserialize($row['value']); |
||
| 3356 | if ($temp === false) |
||
| 3357 | $temp = @safe_unserialize(fix_serialized_data($row['value'])); |
||
| 3358 | |||
| 3359 | if ($command_line) |
||
| 3360 | { |
||
| 3361 | if ($temp === false) |
||
| 3362 | echo "\n" . 'Unserialize of admin_preferences for user ' . $row['id_member'] . ' failed. Skipping.'; |
||
| 3363 | else |
||
| 3364 | echo "\n" . 'Fixing admin preferences...'; |
||
| 3365 | } |
||
| 3366 | |||
| 3367 | if ($temp !== false) |
||
| 3368 | { |
||
| 3369 | $row['value'] = json_encode($temp); |
||
| 3370 | |||
| 3371 | // Even though we have all values from the table, UPDATE is still faster than REPLACE |
||
| 3372 | $smcFunc['db_query']('', ' |
||
| 3373 | UPDATE {db_prefix}themes |
||
| 3374 | SET value = {string:prefs} |
||
| 3375 | WHERE id_theme = {int:theme} |
||
| 3376 | AND id_member = {int:member} |
||
| 3377 | AND variable = {string:admin_prefs}', |
||
| 3378 | array( |
||
| 3379 | 'prefs' => $row['value'], |
||
| 3380 | 'theme' => $row['id_theme'], |
||
| 3381 | 'member' => $row['id_member'], |
||
| 3382 | 'admin_prefs' => 'admin_preferences' |
||
| 3383 | ) |
||
| 3384 | ); |
||
| 3385 | |||
| 3386 | if ($command_line) |
||
| 3387 | echo ' done.'; |
||
| 3388 | } |
||
| 3389 | } |
||
| 3390 | |||
| 3391 | $smcFunc['db_free_result']($query); |
||
| 3392 | } |
||
| 3393 | } |
||
| 3394 | else |
||
| 3395 | { |
||
| 3396 | // First item is always the key... |
||
| 3397 | $key = $info[0]; |
||
| 3398 | unset($info[0]); |
||
| 3399 | |||
| 3400 | // Now we know what columns we have and such... |
||
| 3401 | if (count($info) == 2 && $info[2] === true) |
||
| 3402 | { |
||
| 3403 | $col_select = $info[1]; |
||
| 3404 | $where = ' WHERE ' . $info[1] . ' != {empty}'; |
||
| 3405 | } |
||
| 3406 | else |
||
| 3407 | { |
||
| 3408 | $col_select = implode(', ', $info); |
||
| 3409 | } |
||
| 3410 | |||
| 3411 | $query = $smcFunc['db_query']('', ' |
||
| 3412 | SELECT ' . $key . ', ' . $col_select . ' |
||
| 3413 | FROM {db_prefix}' . $table . $where, |
||
| 3414 | array() |
||
| 3415 | ); |
||
| 3416 | |||
| 3417 | if ($smcFunc['db_num_rows']($query) != 0) |
||
| 3418 | { |
||
| 3419 | if ($command_line) |
||
| 3420 | { |
||
| 3421 | echo "\n" . ' +++ Fixing the "' . $table . '" table...'; |
||
| 3422 | flush(); |
||
| 3423 | } |
||
| 3424 | |||
| 3425 | while ($row = $smcFunc['db_fetch_assoc']($query)) |
||
| 3426 | { |
||
| 3427 | $update = ''; |
||
| 3428 | |||
| 3429 | // We already know what our key is... |
||
| 3430 | foreach ($info as $col) |
||
| 3431 | { |
||
| 3432 | if ($col !== true && $row[$col] != '') |
||
| 3433 | { |
||
| 3434 | $temp = @safe_unserialize($row[$col]); |
||
| 3435 | |||
| 3436 | // Maybe we can fix the data? |
||
| 3437 | if ($temp === false) |
||
| 3438 | $temp = @safe_unserialize(fix_serialized_data($row[$col])); |
||
| 3439 | |||
| 3440 | // Maybe the data is already JSON? |
||
| 3441 | if ($temp === false) |
||
| 3442 | $temp = smf_json_decode($row[$col], true, false); |
||
| 3443 | |||
| 3444 | // Oh well... |
||
| 3445 | if ($temp === null) |
||
| 3446 | { |
||
| 3447 | $temp = array(); |
||
| 3448 | |||
| 3449 | if ($command_line) |
||
| 3450 | echo "\nFailed to unserialize " . $row[$col] . ". Setting to empty value.\n"; |
||
| 3451 | } |
||
| 3452 | |||
| 3453 | $row[$col] = json_encode($temp); |
||
| 3454 | |||
| 3455 | // Build our SET string and variables array |
||
| 3456 | $update .= (empty($update) ? '' : ', ') . $col . ' = {string:' . $col . '}'; |
||
| 3457 | $vars[$col] = $row[$col]; |
||
| 3458 | } |
||
| 3459 | } |
||
| 3460 | |||
| 3461 | $vars[$key] = $row[$key]; |
||
| 3462 | |||
| 3463 | // In a few cases, we might have empty data, so don't try to update in those situations... |
||
| 3464 | if (!empty($update)) |
||
| 3465 | { |
||
| 3466 | $smcFunc['db_query']('', ' |
||
| 3467 | UPDATE {db_prefix}' . $table . ' |
||
| 3468 | SET ' . $update . ' |
||
| 3469 | WHERE ' . $key . ' = {' . ($key == 'session' ? 'string' : 'int') . ':' . $key . '}', |
||
| 3470 | $vars |
||
| 3471 | ); |
||
| 3472 | } |
||
| 3473 | } |
||
| 3474 | |||
| 3475 | if ($command_line) |
||
| 3476 | echo ' done.'; |
||
| 3477 | |||
| 3478 | // Free up some memory... |
||
| 3479 | $smcFunc['db_free_result']($query); |
||
| 3480 | } |
||
| 3481 | } |
||
| 3482 | // If this is XML to keep it nice for the user do one table at a time anyway! |
||
| 3483 | if (isset($_GET['xml'])) |
||
| 3484 | return upgradeExit(); |
||
| 3485 | } |
||
| 3486 | |||
| 3487 | if ($command_line) |
||
| 3488 | { |
||
| 3489 | echo "\n" . 'Successful.' . "\n"; |
||
| 3490 | flush(); |
||
| 3491 | } |
||
| 3492 | $upcontext['step_progress'] = 100; |
||
| 3493 | |||
| 3494 | // Last but not least, insert a dummy setting so we don't have to do this again in the future... |
||
| 3495 | updateSettings(array('json_done' => true)); |
||
| 3496 | |||
| 3497 | $_GET['substep'] = 0; |
||
| 3498 | // Make sure we move on! |
||
| 3499 | if ($command_line) |
||
| 3500 | return ConvertUtf8(); |
||
| 3501 | |||
| 3502 | return true; |
||
| 3503 | } |
||
| 3504 | |||
| 3505 | // If this fails we just move on to deleting the upgrade anyway... |
||
| 3506 | $_GET['substep'] = 0; |
||
| 3507 | return false; |
||
| 3508 | } |
||
| 3509 | |||
| 3510 | /** |
||
| 3511 | * As of 2.1, we want to store db_last_error.php in the cache |
||
| 3512 | * To make that happen, Settings.php needs to ensure the $cachedir path is correct before trying to write to db_last_error.php |
||
| 3513 | */ |
||
| 3514 | function move_db_last_error_to_cachedir() |
||
| 3515 | { |
||
| 3516 | $settings = file_get_contents(dirname(__FILE__) . '/Settings.php'); |
||
| 3517 | |||
| 3518 | $regex = <<<'EOT' |
||
| 3519 | (\s*#\s*Make\s+sure\s+the\s+paths\s+are\s+correct\.\.\.\s+at\s+least\s+try\s+to\s+fix\s+them\.\s+)?if\s*\(\!file_exists\(\$boarddir\)\s+&&\s+file_exists\(dirname\(__FILE__\)\s+\.\s+'/agreement\.txt'\)\)\s+\$boarddir\s*\=\s*dirname\(__FILE__\);\s+if\s*\(\!file_exists\(\$sourcedir\)\s+&&\s+file_exists\(\$boarddir\s*\.\s*'/Sources'\)\)\s+\$sourcedir\s*\=\s*\$boarddir\s*\.\s*'/Sources';\s+if\s*\(\!file_exists\(\$cachedir\)\s+&&\s+file_exists\(\$boarddir\s*\.\s*'/cache'\)\)\s+\$cachedir\s*\=\s*\$boarddir\s*\.\s*'/cache'; |
||
| 3520 | EOT; |
||
| 3521 | |||
| 3522 | $replacement = <<<'EOT' |
||
| 3523 | # Make sure the paths are correct... at least try to fix them. |
||
| 3524 | if (!file_exists($boarddir) && file_exists(dirname(__FILE__) . '/agreement.txt')) |
||
| 3525 | $boarddir = dirname(__FILE__); |
||
| 3526 | if (!file_exists($sourcedir) && file_exists($boarddir . '/Sources')) |
||
| 3527 | $sourcedir = $boarddir . '/Sources'; |
||
| 3528 | if (!file_exists($cachedir) && file_exists($boarddir . '/cache')) |
||
| 3529 | $cachedir = $boarddir . '/cache'; |
||
| 3530 | |||
| 3531 | |||
| 3532 | EOT; |
||
| 3533 | |||
| 3534 | if (preg_match('~' . $regex . '~', $settings) && preg_match('~(#+\s*Error-Catching\s*#+)~', $settings)) |
||
| 3535 | { |
||
| 3536 | $settings = preg_replace('~' . $regex . '~', '', $settings); |
||
| 3537 | $settings = preg_replace('~(#+\s*Error-Catching\s*#+)~', $replacement . '$1', $settings); |
||
| 3538 | $settings = preg_replace('~dirname(__FILE__) . \'/db_last_error.php\'~', '(isset($cachedir) ? $cachedir : dirname(__FILE__)) . \'/db_last_error.php\'', $settings); |
||
| 3539 | |||
| 3540 | // Blank out the file - done to fix a oddity with some servers. |
||
| 3541 | file_put_contents(dirname(__FILE__) . '/Settings.php', ''); |
||
| 3542 | |||
| 3543 | file_put_contents(dirname(__FILE__) . '/Settings.php', $settings); |
||
| 3544 | } |
||
| 3545 | } |
||
| 3546 | |||
| 3547 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||
| 3548 | Templates are below this point |
||
| 3549 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ |
||
| 3550 | |||
| 3551 | // This is what is displayed if there's any chmod to be done. If not it returns nothing... |
||
| 3552 | function template_chmod() |
||
| 3553 | { |
||
| 3554 | global $upcontext, $txt, $settings; |
||
| 3555 | |||
| 3556 | // Don't call me twice! |
||
| 3557 | if (!empty($upcontext['chmod_called'])) |
||
| 3558 | return; |
||
| 3559 | |||
| 3560 | $upcontext['chmod_called'] = true; |
||
| 3561 | |||
| 3562 | // Nothing? |
||
| 3563 | if (empty($upcontext['chmod']['files']) && empty($upcontext['chmod']['ftp_error'])) |
||
| 3564 | return; |
||
| 3565 | |||
| 3566 | // Was it a problem with Windows? |
||
| 3567 | if (!empty($upcontext['chmod']['ftp_error']) && $upcontext['chmod']['ftp_error'] == 'total_mess') |
||
| 3568 | { |
||
| 3569 | echo ' |
||
| 3570 | <div class="error"> |
||
| 3571 | <p>', $txt['upgrade_writable_files'], '</p> |
||
| 3572 | <ul class="error_content"> |
||
| 3573 | <li>' . implode('</li> |
||
| 3574 | <li>', $upcontext['chmod']['files']) . '</li> |
||
| 3575 | </ul> |
||
| 3576 | </div>'; |
||
| 3577 | |||
| 3578 | return false; |
||
| 3579 | } |
||
| 3580 | |||
| 3581 | echo ' |
||
| 3582 | <div class="panel"> |
||
| 3583 | <h2>', $txt['upgrade_ftp_login'], '</h2> |
||
| 3584 | <h3>', $txt['upgrade_ftp_perms'], '</h3> |
||
| 3585 | <script> |
||
| 3586 | function warning_popup() |
||
| 3587 | { |
||
| 3588 | popup = window.open(\'\',\'popup\',\'height=150,width=400,scrollbars=yes\'); |
||
| 3589 | var content = popup.document; |
||
| 3590 | content.write(\'<!DOCTYPE html>\n\'); |
||
| 3591 | content.write(\'<html', $txt['lang_rtl'] == true ? ' dir="rtl"' : '', '>\n\t<head>\n\t\t<meta name="robots" content="noindex">\n\t\t\'); |
||
| 3592 | content.write(\'<title>', $txt['upgrade_ftp_warning'], '</title>\n\t\t<link rel="stylesheet" href="', $settings['default_theme_url'], '/css/index.css">\n\t</head>\n\t<body id="popup">\n\t\t\'); |
||
| 3593 | content.write(\'<div class="windowbg description">\n\t\t\t<h4>', $txt['upgrade_ftp_files'], '</h4>\n\t\t\t\'); |
||
| 3594 | content.write(\'<p>', implode('<br>\n\t\t\t', $upcontext['chmod']['files']), '</p>\n\t\t\t\');'; |
||
| 3595 | |||
| 3596 | if (isset($upcontext['systemos']) && $upcontext['systemos'] == 'linux') |
||
| 3597 | echo ' |
||
| 3598 | content.write(\'<hr>\n\t\t\t\'); |
||
| 3599 | content.write(\'<p>', $txt['upgrade_ftp_shell'], '</p>\n\t\t\t\'); |
||
| 3600 | content.write(\'<tt># chmod a+w ', implode(' ', $upcontext['chmod']['files']), '</tt>\n\t\t\t\');'; |
||
| 3601 | |||
| 3602 | echo ' |
||
| 3603 | content.write(\'<a href="javascript:self.close();">close</a>\n\t\t</div>\n\t</body>\n</html>\'); |
||
| 3604 | content.close(); |
||
| 3605 | } |
||
| 3606 | </script>'; |
||
| 3607 | |||
| 3608 | if (!empty($upcontext['chmod']['ftp_error'])) |
||
| 3609 | echo ' |
||
| 3610 | <div class="error"> |
||
| 3611 | <p>', $txt['upgrade_ftp_error'], '<p> |
||
| 3612 | <code>', $upcontext['chmod']['ftp_error'], '</code> |
||
| 3613 | </div>'; |
||
| 3614 | |||
| 3615 | if (empty($upcontext['chmod_in_form'])) |
||
| 3616 | echo ' |
||
| 3617 | <form action="', $upcontext['form_url'], '" method="post">'; |
||
| 3618 | |||
| 3619 | echo ' |
||
| 3620 | <dl class="settings"> |
||
| 3621 | <dt> |
||
| 3622 | <label for="ftp_server">', $txt['ftp_server'], ':</label> |
||
| 3623 | </dt> |
||
| 3624 | <dd> |
||
| 3625 | <div class="floatright"> |
||
| 3626 | <label for="ftp_port" class="textbox"><strong>', $txt['ftp_port'], ':</strong></label> |
||
| 3627 | <input type="text" size="3" name="ftp_port" id="ftp_port" value="', isset($upcontext['chmod']['port']) ? $upcontext['chmod']['port'] : '21', '"> |
||
| 3628 | </div> |
||
| 3629 | <input type="text" size="30" name="ftp_server" id="ftp_server" value="', isset($upcontext['chmod']['server']) ? $upcontext['chmod']['server'] : 'localhost', '"> |
||
| 3630 | <div class="smalltext">', $txt['ftp_server_info'], '</div> |
||
| 3631 | </dd> |
||
| 3632 | <dt> |
||
| 3633 | <label for="ftp_username">', $txt['ftp_username'], ':</label> |
||
| 3634 | </dt> |
||
| 3635 | <dd> |
||
| 3636 | <input type="text" size="30" name="ftp_username" id="ftp_username" value="', isset($upcontext['chmod']['username']) ? $upcontext['chmod']['username'] : '', '"> |
||
| 3637 | <div class="smalltext">', $txt['ftp_username_info'], '</div> |
||
| 3638 | </dd> |
||
| 3639 | <dt> |
||
| 3640 | <label for="ftp_password">', $txt['ftp_password'], ':</label> |
||
| 3641 | </dt> |
||
| 3642 | <dd> |
||
| 3643 | <input type="password" size="30" name="ftp_password" id="ftp_password"> |
||
| 3644 | <div class="smalltext">', $txt['ftp_password_info'], '</div> |
||
| 3645 | </dd> |
||
| 3646 | <dt> |
||
| 3647 | <label for="ftp_path">', $txt['ftp_path'], ':</label> |
||
| 3648 | </dt> |
||
| 3649 | <dd> |
||
| 3650 | <input type="text" size="30" name="ftp_path" id="ftp_path" value="', isset($upcontext['chmod']['path']) ? $upcontext['chmod']['path'] : '', '"> |
||
| 3651 | <div class="smalltext">', !empty($upcontext['chmod']['path']) ? $txt['ftp_path_found_info'] : $txt['ftp_path_info'], '</div> |
||
| 3652 | </dd> |
||
| 3653 | </dl> |
||
| 3654 | |||
| 3655 | <div class="righttext buttons"> |
||
| 3656 | <input type="submit" value="', $txt['ftp_connect'], '" class="button"> |
||
| 3657 | </div>'; |
||
| 3658 | |||
| 3659 | if (empty($upcontext['chmod_in_form'])) |
||
| 3660 | echo ' |
||
| 3661 | </form>'; |
||
| 3662 | |||
| 3663 | echo ' |
||
| 3664 | </div><!-- .panel -->'; |
||
| 3665 | } |
||
| 3666 | |||
| 3667 | function template_upgrade_above() |
||
| 3668 | { |
||
| 3669 | global $modSettings, $txt, $settings, $upcontext, $upgradeurl; |
||
| 3670 | |||
| 3671 | echo '<!DOCTYPE html> |
||
| 3672 | <html', $txt['lang_rtl'] == true ? ' dir="rtl"' : '', '> |
||
| 3673 | <head> |
||
| 3674 | <meta charset="', isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8', '"> |
||
| 3675 | <meta name="robots" content="noindex"> |
||
| 3676 | <title>', $txt['upgrade_upgrade_utility'], '</title> |
||
| 3677 | <link rel="stylesheet" href="', $settings['default_theme_url'], '/css/index.css"> |
||
| 3678 | <link rel="stylesheet" href="', $settings['default_theme_url'], '/css/install.css"> |
||
| 3679 | ', $txt['lang_rtl'] == true ? '<link rel="stylesheet" href="' . $settings['default_theme_url'] . '/css/rtl.css">' : '', ' |
||
| 3680 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> |
||
| 3681 | <script src="', $settings['default_theme_url'], '/scripts/script.js"></script> |
||
| 3682 | <script> |
||
| 3683 | var smf_scripturl = \'', $upgradeurl, '\'; |
||
| 3684 | var smf_charset = \'', (empty($modSettings['global_character_set']) ? (empty($txt['lang_character_set']) ? 'UTF-8' : $txt['lang_character_set']) : $modSettings['global_character_set']), '\'; |
||
| 3685 | var startPercent = ', $upcontext['overall_percent'], '; |
||
| 3686 | |||
| 3687 | // This function dynamically updates the step progress bar - and overall one as required. |
||
| 3688 | function updateStepProgress(current, max, overall_weight) |
||
| 3689 | { |
||
| 3690 | // What out the actual percent. |
||
| 3691 | var width = parseInt((current / max) * 100); |
||
| 3692 | if (document.getElementById(\'step_progress\')) |
||
| 3693 | { |
||
| 3694 | document.getElementById(\'step_progress\').style.width = width + "%"; |
||
| 3695 | setInnerHTML(document.getElementById(\'step_text\'), width + "%"); |
||
| 3696 | } |
||
| 3697 | if (overall_weight && document.getElementById(\'overall_progress\')) |
||
| 3698 | { |
||
| 3699 | overall_width = parseInt(startPercent + width * (overall_weight / 100)); |
||
| 3700 | document.getElementById(\'overall_progress\').style.width = overall_width + "%"; |
||
| 3701 | setInnerHTML(document.getElementById(\'overall_text\'), overall_width + "%"); |
||
| 3702 | } |
||
| 3703 | } |
||
| 3704 | </script> |
||
| 3705 | </head> |
||
| 3706 | <body> |
||
| 3707 | <div id="footerfix"> |
||
| 3708 | <div id="header"> |
||
| 3709 | <h1 class="forumtitle">', $txt['upgrade_upgrade_utility'], '</h1> |
||
| 3710 | <img id="smflogo" src="', $settings['default_theme_url'], '/images/smflogo.svg" alt="Simple Machines Forum" title="Simple Machines Forum"> |
||
| 3711 | </div> |
||
| 3712 | <div id="wrapper"> |
||
| 3713 | <div id="content_section"> |
||
| 3714 | <div id="main_content_section"> |
||
| 3715 | <div id="main_steps"> |
||
| 3716 | <h2>', $txt['upgrade_progress'], '</h2> |
||
| 3717 | <ul class="steps_list">'; |
||
| 3718 | |||
| 3719 | foreach ($upcontext['steps'] as $num => $step) |
||
| 3720 | echo ' |
||
| 3721 | <li', $num == $upcontext['current_step'] ? ' class="stepcurrent"' : '', '> |
||
| 3722 | ', $txt['upgrade_step'], ' ', $step[0], ': ', $txt[$step[1]], ' |
||
| 3723 | </li>'; |
||
| 3724 | |||
| 3725 | echo ' |
||
| 3726 | </ul> |
||
| 3727 | </div><!-- #main_steps --> |
||
| 3728 | |||
| 3729 | <div id="install_progress"> |
||
| 3730 | <div id="progress_bar" class="progress_bar progress_green"> |
||
| 3731 | <h3>', $txt['upgrade_overall_progress'], '</h3> |
||
| 3732 | <div id="overall_progress" class="bar" style="width: ', $upcontext['overall_percent'], '%;"></div> |
||
| 3733 | <span id="overall_text">', $upcontext['overall_percent'], '%</span> |
||
| 3734 | </div>'; |
||
| 3735 | |||
| 3736 | if (isset($upcontext['step_progress'])) |
||
| 3737 | echo ' |
||
| 3738 | <div id="progress_bar_step" class="progress_bar progress_yellow"> |
||
| 3739 | <h3>', $txt['upgrade_step_progress'], '</h3> |
||
| 3740 | <div id="step_progress" class="bar" style="width: ', $upcontext['step_progress'], '%;"></div> |
||
| 3741 | <span id="step_text">', $upcontext['step_progress'], '%</span> |
||
| 3742 | </div>'; |
||
| 3743 | |||
| 3744 | echo ' |
||
| 3745 | <div id="substep_bar_div" class="progress_bar ', isset($upcontext['substep_progress']) ? '' : 'hidden', '"> |
||
| 3746 | <h3 id="substep_name">', isset($upcontext['substep_progress_name']) ? trim(strtr($upcontext['substep_progress_name'], array('.' => ''))) : '', '</h3> |
||
| 3747 | <div id="substep_progress" class="bar" style="width: ', isset($upcontext['substep_progress']) ? $upcontext['substep_progress'] : 0, '%;"></div> |
||
| 3748 | <span id="substep_text">', isset($upcontext['substep_progress']) ? $upcontext['substep_progress'] : 0, '%</span> |
||
| 3749 | </div>'; |
||
| 3750 | |||
| 3751 | // How long have we been running this? |
||
| 3752 | $elapsed = time() - $upcontext['started']; |
||
| 3753 | $mins = (int) ($elapsed / 60); |
||
| 3754 | $seconds = $elapsed - $mins * 60; |
||
| 3755 | echo ' |
||
| 3756 | <div class="smalltext time_elapsed"> |
||
| 3757 | ', $txt['upgrade_time_elapsed'], ': |
||
| 3758 | <span id="mins_elapsed">', $mins, '</span> ', $txt['upgrade_time_mins'], ', <span id="secs_elapsed">', $seconds, '</span> ', $txt['upgrade_time_secs'], '. |
||
| 3759 | </div>'; |
||
| 3760 | echo ' |
||
| 3761 | </div><!-- #install_progress --> |
||
| 3762 | <div id="main_screen" class="clear"> |
||
| 3763 | <h2>', $upcontext['page_title'], '</h2> |
||
| 3764 | <div class="panel">'; |
||
| 3765 | } |
||
| 3766 | |||
| 3767 | function template_upgrade_below() |
||
| 3768 | { |
||
| 3769 | global $upcontext, $txt; |
||
| 3770 | |||
| 3771 | if (!empty($upcontext['pause'])) |
||
| 3772 | echo ' |
||
| 3773 | <em>', $txt['upgrade_incomplete'], '.</em><br> |
||
| 3774 | |||
| 3775 | <h2 style="margin-top: 2ex;">', $txt['upgrade_not_quite_done'], '</h2> |
||
| 3776 | <h3> |
||
| 3777 | ', $txt['upgrade_paused_overload'], ' |
||
| 3778 | </h3>'; |
||
| 3779 | |||
| 3780 | if (!empty($upcontext['custom_warning'])) |
||
| 3781 | echo ' |
||
| 3782 | <div class="errorbox"> |
||
| 3783 | <h3>', $txt['upgrade_note'], '</h3> |
||
| 3784 | ', $upcontext['custom_warning'], ' |
||
| 3785 | </div>'; |
||
| 3786 | |||
| 3787 | echo ' |
||
| 3788 | <div class="righttext buttons">'; |
||
| 3789 | |||
| 3790 | if (!empty($upcontext['continue'])) |
||
| 3791 | echo ' |
||
| 3792 | <input type="submit" id="contbutt" name="contbutt" value="', $txt['upgrade_continue'], '"', $upcontext['continue'] == 2 ? ' disabled' : '', ' class="button">'; |
||
| 3793 | if (!empty($upcontext['skip'])) |
||
| 3794 | echo ' |
||
| 3795 | <input type="submit" id="skip" name="skip" value="', $txt['upgrade_skip'], '" onclick="dontSubmit = true; document.getElementById(\'contbutt\').disabled = \'disabled\'; return true;" class="button">'; |
||
| 3796 | |||
| 3797 | echo ' |
||
| 3798 | </div> |
||
| 3799 | </form> |
||
| 3800 | </div><!-- .panel --> |
||
| 3801 | </div><!-- #main_screen --> |
||
| 3802 | </div><!-- #main_content_section --> |
||
| 3803 | </div><!-- #content_section --> |
||
| 3804 | </div><!-- #wrapper --> |
||
| 3805 | </div><!-- #footerfix --> |
||
| 3806 | <div id="footer"> |
||
| 3807 | <ul> |
||
| 3808 | <li class="copyright"><a href="https://www.simplemachines.org/" title="Simple Machines Forum" target="_blank" rel="noopener">SMF © ' . SMF_SOFTWARE_YEAR . ', Simple Machines</a></li> |
||
| 3809 | </ul> |
||
| 3810 | </div>'; |
||
| 3811 | |||
| 3812 | // Are we on a pause? |
||
| 3813 | if (!empty($upcontext['pause'])) |
||
| 3814 | { |
||
| 3815 | echo ' |
||
| 3816 | <script> |
||
| 3817 | window.onload = doAutoSubmit; |
||
| 3818 | var countdown = 3; |
||
| 3819 | var dontSubmit = false; |
||
| 3820 | |||
| 3821 | function doAutoSubmit() |
||
| 3822 | { |
||
| 3823 | if (countdown == 0 && !dontSubmit) |
||
| 3824 | document.upform.submit(); |
||
| 3825 | else if (countdown == -1) |
||
| 3826 | return; |
||
| 3827 | |||
| 3828 | document.getElementById(\'contbutt\').value = "', $txt['upgrade_continue'], ' (" + countdown + ")"; |
||
| 3829 | countdown--; |
||
| 3830 | |||
| 3831 | setTimeout("doAutoSubmit();", 1000); |
||
| 3832 | } |
||
| 3833 | </script>'; |
||
| 3834 | } |
||
| 3835 | |||
| 3836 | echo ' |
||
| 3837 | </body> |
||
| 3838 | </html>'; |
||
| 3839 | } |
||
| 3840 | |||
| 3841 | function template_xml_above() |
||
| 3842 | { |
||
| 3843 | global $upcontext; |
||
| 3844 | |||
| 3845 | echo '<', '?xml version="1.0" encoding="UTF-8"?', '> |
||
| 3846 | <smf>'; |
||
| 3847 | |||
| 3848 | if (!empty($upcontext['get_data'])) |
||
| 3849 | foreach ($upcontext['get_data'] as $k => $v) |
||
| 3850 | echo ' |
||
| 3851 | <get key="', $k, '">', $v, '</get>'; |
||
| 3852 | } |
||
| 3853 | |||
| 3854 | function template_xml_below() |
||
| 3855 | { |
||
| 3856 | echo ' |
||
| 3857 | </smf>'; |
||
| 3858 | } |
||
| 3859 | |||
| 3860 | function template_error_message() |
||
| 3861 | { |
||
| 3862 | global $upcontext; |
||
| 3863 | |||
| 3864 | echo ' |
||
| 3865 | <div class="error"> |
||
| 3866 | ', $upcontext['error_msg'], ' |
||
| 3867 | <br> |
||
| 3868 | <a href="', $_SERVER['PHP_SELF'], '">Click here to try again.</a> |
||
| 3869 | </div>'; |
||
| 3870 | } |
||
| 3871 | |||
| 3872 | function template_welcome_message() |
||
| 3873 | { |
||
| 3874 | global $upcontext, $disable_security, $settings, $txt; |
||
| 3875 | |||
| 3876 | echo ' |
||
| 3877 | <script src="https://www.simplemachines.org/smf/current-version.js?version=' . SMF_VERSION . '"></script> |
||
| 3878 | |||
| 3879 | <h3>', sprintf($txt['upgrade_ready_proceed'], SMF_VERSION), '</h3> |
||
| 3880 | <form action="', $upcontext['form_url'], '" method="post" name="upform" id="upform"> |
||
| 3881 | <input type="hidden" name="', $upcontext['login_token_var'], '" value="', $upcontext['login_token'], '"> |
||
| 3882 | |||
| 3883 | <div id="version_warning" class="noticebox hidden"> |
||
| 3884 | <h3>', $txt['upgrade_warning'], '</h3> |
||
| 3885 | ', sprintf($txt['upgrade_warning_out_of_date'], SMF_VERSION, 'https://www.simplemachines.org'), ' |
||
| 3886 | </div>'; |
||
| 3887 | |||
| 3888 | $upcontext['chmod_in_form'] = true; |
||
| 3889 | template_chmod(); |
||
| 3890 | |||
| 3891 | // For large, pre 1.1 RC2 forums give them a warning about the possible impact of this upgrade! |
||
| 3892 | if ($upcontext['is_large_forum']) |
||
| 3893 | echo ' |
||
| 3894 | <div class="errorbox"> |
||
| 3895 | <h3>', $txt['upgrade_warning'], '</h3> |
||
| 3896 | ', $txt['upgrade_warning_lots_data'], ' |
||
| 3897 | </div>'; |
||
| 3898 | |||
| 3899 | // A warning message? |
||
| 3900 | if (!empty($upcontext['warning'])) |
||
| 3901 | echo ' |
||
| 3902 | <div class="errorbox"> |
||
| 3903 | <h3>', $txt['upgrade_warning'], '</h3> |
||
| 3904 | ', $upcontext['warning'], ' |
||
| 3905 | </div>'; |
||
| 3906 | |||
| 3907 | // Paths are incorrect? |
||
| 3908 | echo ' |
||
| 3909 | <div class="errorbox', (file_exists($settings['default_theme_dir'] . '/scripts/script.js') ? ' hidden' : ''), '" id="js_script_missing_error"> |
||
| 3910 | <h3>', $txt['upgrade_critical_error'], '</h3> |
||
| 3911 | ', sprintf($txt['upgrade_error_script_js'], 'https://www.simplemachines.org'), ' |
||
| 3912 | </div>'; |
||
| 3913 | |||
| 3914 | // Is there someone already doing this? |
||
| 3915 | if (!empty($upcontext['user']['id']) && (time() - $upcontext['started'] < 72600 || time() - $upcontext['updated'] < 3600)) |
||
| 3916 | { |
||
| 3917 | $ago = time() - $upcontext['started']; |
||
| 3918 | $ago_hours = floor($ago / 3600); |
||
| 3919 | $ago_minutes = intval(($ago / 60) % 60); |
||
| 3920 | $ago_seconds = intval($ago % 60); |
||
| 3921 | $agoTxt = $ago < 60 ? 'upgrade_time_ago_s' : ($ago < 3600 ? 'upgrade_time_ago_ms' : 'upgrade_time_ago_hms'); |
||
| 3922 | |||
| 3923 | $updated = time() - $upcontext['updated']; |
||
| 3924 | $updated_hours = floor($updated / 3600); |
||
| 3925 | $updated_minutes = intval(($updated / 60) % 60); |
||
| 3926 | $updated_seconds = intval($updated % 60); |
||
| 3927 | $updatedTxt = $updated < 60 ? 'upgrade_time_updated_s' : ($updated < 3600 ? 'upgrade_time_updated_hm' : 'upgrade_time_updated_hms'); |
||
| 3928 | |||
| 3929 | echo ' |
||
| 3930 | <div class="errorbox"> |
||
| 3931 | <h3>', $txt['upgrade_warning'], '</h3> |
||
| 3932 | <p>', sprintf($txt['upgrade_time_user'], $upcontext['user']['name']), '</p> |
||
| 3933 | <p>', sprintf($txt[$agoTxt], $ago_seconds, $ago_minutes, $ago_hours), '</p> |
||
| 3934 | <p>', sprintf($txt[$updatedTxt], $updated_seconds, $updated_minutes, $updated_hours), '</p>'; |
||
| 3935 | |||
| 3936 | if ($updated < 600) |
||
| 3937 | echo ' |
||
| 3938 | <p>', $txt['upgrade_run_script'], ' ', $upcontext['user']['name'], ' ', $txt['upgrade_run_script2'], '</p>'; |
||
| 3939 | |||
| 3940 | if ($updated > $upcontext['inactive_timeout']) |
||
| 3941 | echo ' |
||
| 3942 | <p>', $txt['upgrade_run'], '</p>'; |
||
| 3943 | else |
||
| 3944 | echo ' |
||
| 3945 | <p>', $txt['upgrade_script_timeout'], ' ', $upcontext['user']['name'], ' ', $txt['upgrade_script_timeout2'], ' ', ($upcontext['inactive_timeout'] > 120 ? round($upcontext['inactive_timeout'] / 60, 1) . ' minutes!' : $upcontext['inactive_timeout'] . ' seconds!'), '</p>'; |
||
| 3946 | |||
| 3947 | echo ' |
||
| 3948 | </div>'; |
||
| 3949 | } |
||
| 3950 | |||
| 3951 | echo ' |
||
| 3952 | <strong>', $txt['upgrade_admin_login'], ' ', $disable_security ? '(DISABLED)' : '', '</strong> |
||
| 3953 | <h3>', $txt['upgrade_sec_login'], '</h3> |
||
| 3954 | <dl class="settings adminlogin"> |
||
| 3955 | <dt> |
||
| 3956 | <label for="user"', $disable_security ? ' disabled' : '', '>', $txt['upgrade_username'], '</label> |
||
| 3957 | </dt> |
||
| 3958 | <dd> |
||
| 3959 | <input type="text" name="user" value="', !empty($upcontext['username']) ? $upcontext['username'] : '', '"', $disable_security ? ' disabled' : '', '>'; |
||
| 3960 | |||
| 3961 | if (!empty($upcontext['username_incorrect'])) |
||
| 3962 | echo ' |
||
| 3963 | <div class="smalltext red">', $txt['upgrade_wrong_username'], '</div>'; |
||
| 3964 | |||
| 3965 | echo ' |
||
| 3966 | </dd> |
||
| 3967 | <dt> |
||
| 3968 | <label for="passwrd"', $disable_security ? ' disabled' : '', '>', $txt['upgrade_password'], '</label> |
||
| 3969 | </dt> |
||
| 3970 | <dd> |
||
| 3971 | <input type="password" name="passwrd" value=""', $disable_security ? ' disabled' : '', '> |
||
| 3972 | <input type="hidden" name="hash_passwrd" value="">'; |
||
| 3973 | |||
| 3974 | if (!empty($upcontext['password_failed'])) |
||
| 3975 | echo ' |
||
| 3976 | <div class="smalltext red">', $txt['upgrade_wrong_password'], '</div>'; |
||
| 3977 | |||
| 3978 | echo ' |
||
| 3979 | </dd>'; |
||
| 3980 | |||
| 3981 | // Can they continue? |
||
| 3982 | if (!empty($upcontext['user']['id']) && time() - $upcontext['user']['updated'] >= $upcontext['inactive_timeout'] && $upcontext['user']['step'] > 1) |
||
| 3983 | { |
||
| 3984 | echo ' |
||
| 3985 | <dd> |
||
| 3986 | <label for="cont"><input type="checkbox" id="cont" name="cont" checked>', $txt['upgrade_continue_step'], '</label> |
||
| 3987 | </dd>'; |
||
| 3988 | } |
||
| 3989 | |||
| 3990 | echo ' |
||
| 3991 | </dl> |
||
| 3992 | <span class="smalltext"> |
||
| 3993 | ', $txt['upgrade_bypass'], ' |
||
| 3994 | </span> |
||
| 3995 | <input type="hidden" name="login_attempt" id="login_attempt" value="1"> |
||
| 3996 | <input type="hidden" name="js_works" id="js_works" value="0">'; |
||
| 3997 | |||
| 3998 | // Say we want the continue button! |
||
| 3999 | $upcontext['continue'] = !empty($upcontext['user']['id']) && time() - $upcontext['user']['updated'] < $upcontext['inactive_timeout'] ? 2 : 1; |
||
| 4000 | |||
| 4001 | // This defines whether javascript is going to work elsewhere :D |
||
| 4002 | echo ' |
||
| 4003 | <script> |
||
| 4004 | if (\'XMLHttpRequest\' in window && document.getElementById(\'js_works\')) |
||
| 4005 | document.getElementById(\'js_works\').value = 1; |
||
| 4006 | |||
| 4007 | // Latest version? |
||
| 4008 | function smfCurrentVersion() |
||
| 4009 | { |
||
| 4010 | var smfVer, yourVer; |
||
| 4011 | |||
| 4012 | if (!(\'smfVersion\' in window)) |
||
| 4013 | return; |
||
| 4014 | |||
| 4015 | window.smfVersion = window.smfVersion.replace(/SMF\s?/g, \'\'); |
||
| 4016 | |||
| 4017 | smfVer = document.getElementById(\'smfVersion\'); |
||
| 4018 | yourVer = document.getElementById(\'yourVersion\'); |
||
| 4019 | |||
| 4020 | setInnerHTML(smfVer, window.smfVersion); |
||
| 4021 | |||
| 4022 | var currentVersion = getInnerHTML(yourVer); |
||
| 4023 | if (currentVersion < window.smfVersion) |
||
| 4024 | document.getElementById(\'version_warning\').classList.remove(\'hidden\'); |
||
| 4025 | } |
||
| 4026 | addLoadEvent(smfCurrentVersion); |
||
| 4027 | |||
| 4028 | // This checks that the script file even exists! |
||
| 4029 | if (typeof(smfSelectText) == \'undefined\') |
||
| 4030 | document.getElementById(\'js_script_missing_error\').classList.remove(\'hidden\'); |
||
| 4031 | |||
| 4032 | </script>'; |
||
| 4033 | } |
||
| 4034 | |||
| 4035 | function template_upgrade_options() |
||
| 4036 | { |
||
| 4037 | global $upcontext, $modSettings, $db_prefix, $mmessage, $mtitle, $txt; |
||
| 4038 | |||
| 4039 | echo ' |
||
| 4040 | <h3>', $txt['upgrade_areyouready'], '</h3> |
||
| 4041 | <form action="', $upcontext['form_url'], '" method="post" name="upform" id="upform">'; |
||
| 4042 | |||
| 4043 | // Warning message? |
||
| 4044 | if (!empty($upcontext['upgrade_options_warning'])) |
||
| 4045 | echo ' |
||
| 4046 | <div class="errorbox"> |
||
| 4047 | <h3>', $txt['upgrade_warning'], '</h3> |
||
| 4048 | ', $upcontext['upgrade_options_warning'], ' |
||
| 4049 | </div>'; |
||
| 4050 | |||
| 4051 | echo ' |
||
| 4052 | <ul class="upgrade_settings"> |
||
| 4053 | <li> |
||
| 4054 | <input type="checkbox" name="backup" id="backup" value="1"> |
||
| 4055 | <label for="backup">', $txt['upgrade_backup_table'], ' "backup_' . $db_prefix . '".</label> |
||
| 4056 | (', $txt['upgrade_recommended'], ') |
||
| 4057 | </li> |
||
| 4058 | <li> |
||
| 4059 | <input type="checkbox" name="maint" id="maint" value="1" checked> |
||
| 4060 | <label for="maint">', $txt['upgrade_maintenance'], '</label> |
||
| 4061 | <span class="smalltext">(<a href="javascript:void(0)" onclick="document.getElementById(\'mainmess\').classList.toggle(\'hidden\')">', $txt['upgrade_customize'], '</a>)</span> |
||
| 4062 | <div id="mainmess" class="hidden"> |
||
| 4063 | <strong class="smalltext">', $txt['upgrade_maintenance_title'], ' </strong><br> |
||
| 4064 | <input type="text" name="maintitle" size="30" value="', htmlspecialchars($mtitle), '"><br> |
||
| 4065 | <strong class="smalltext">', $txt['upgrade_maintenance_message'], ' </strong><br> |
||
| 4066 | <textarea name="mainmessage" rows="3" cols="50">', htmlspecialchars($mmessage), '</textarea> |
||
| 4067 | </div> |
||
| 4068 | </li> |
||
| 4069 | <li> |
||
| 4070 | <input type="checkbox" name="debug" id="debug" value="1"> |
||
| 4071 | <label for="debug">'.$txt['upgrade_debug_info'], '</label> |
||
| 4072 | </li> |
||
| 4073 | <li> |
||
| 4074 | <input type="checkbox" name="empty_error" id="empty_error" value="1"> |
||
| 4075 | <label for="empty_error">', $txt['upgrade_empty_errorlog'], '</label> |
||
| 4076 | </li>'; |
||
| 4077 | |||
| 4078 | if (!empty($upcontext['karma_installed']['good']) || !empty($upcontext['karma_installed']['bad'])) |
||
| 4079 | echo ' |
||
| 4080 | <li> |
||
| 4081 | <input type="checkbox" name="delete_karma" id="delete_karma" value="1"> |
||
| 4082 | <label for="delete_karma">', $txt['upgrade_delete_karma'], '</label> |
||
| 4083 | </li>'; |
||
| 4084 | |||
| 4085 | echo ' |
||
| 4086 | <li> |
||
| 4087 | <input type="checkbox" name="stats" id="stats" value="1"', empty($modSettings['allow_sm_stats']) && empty($modSettings['enable_sm_stats']) ? '' : ' checked="checked"', '> |
||
| 4088 | <label for="stat"> |
||
| 4089 | ', $txt['upgrade_stats_collection'], '<br> |
||
| 4090 | <span class="smalltext">', sprintf($txt['upgrade_stats_info'], 'https://www.simplemachines.org/about/stats.php'), '</a></span> |
||
| 4091 | </label> |
||
| 4092 | </li> |
||
| 4093 | <li> |
||
| 4094 | <input type="checkbox" name="migrateSettings" id="migrateSettings" value="1"', empty($upcontext['migrateSettingsNeeded']) ? '' : ' checked="checked"', '> |
||
| 4095 | <label for="migrateSettings"> |
||
| 4096 | ', $txt['upgrade_migrate_settings_file'], ' |
||
| 4097 | </label> |
||
| 4098 | </li> |
||
| 4099 | </ul> |
||
| 4100 | <input type="hidden" name="upcont" value="1">'; |
||
| 4101 | |||
| 4102 | // We need a normal continue button here! |
||
| 4103 | $upcontext['continue'] = 1; |
||
| 4104 | } |
||
| 4105 | |||
| 4106 | // Template for the database backup tool/ |
||
| 4107 | function template_backup_database() |
||
| 4108 | { |
||
| 4109 | global $upcontext, $support_js, $is_debug, $txt; |
||
| 4110 | |||
| 4111 | echo ' |
||
| 4112 | <h3>', $txt['upgrade_wait'], '</h3>'; |
||
| 4113 | |||
| 4114 | echo ' |
||
| 4115 | <form action="', $upcontext['form_url'], '" name="upform" id="upform" method="post"> |
||
| 4116 | <input type="hidden" name="backup_done" id="backup_done" value="0"> |
||
| 4117 | <strong>', sprintf($txt['upgrade_completedtables_outof'], $upcontext['cur_table_num'], $upcontext['table_count']), '</strong> |
||
| 4118 | <div id="debug_section"> |
||
| 4119 | <span id="debuginfo"></span> |
||
| 4120 | </div>'; |
||
| 4121 | |||
| 4122 | // Dont any tables so far? |
||
| 4123 | if (!empty($upcontext['previous_tables'])) |
||
| 4124 | foreach ($upcontext['previous_tables'] as $table) |
||
| 4125 | echo ' |
||
| 4126 | <br>', $txt['upgrade_completed_table'], ' "', $table, '".'; |
||
| 4127 | |||
| 4128 | echo ' |
||
| 4129 | <h3 id="current_tab"> |
||
| 4130 | ', $txt['upgrade_current_table'], ' "<span id="current_table">', $upcontext['cur_table_name'], '</span>" |
||
| 4131 | </h3> |
||
| 4132 | <p id="commess" class="', $upcontext['cur_table_num'] == $upcontext['table_count'] ? 'inline_block' : 'hidden', '">Backup Complete! Click Continue to Proceed.</p>'; |
||
| 4133 | |||
| 4134 | // Continue please! |
||
| 4135 | $upcontext['continue'] = $support_js ? 2 : 1; |
||
| 4136 | |||
| 4137 | // If javascript allows we want to do this using XML. |
||
| 4138 | if ($support_js) |
||
| 4139 | { |
||
| 4140 | echo ' |
||
| 4141 | <script> |
||
| 4142 | var lastTable = ', $upcontext['cur_table_num'], '; |
||
| 4143 | function getNextTables() |
||
| 4144 | { |
||
| 4145 | getXMLDocument(\'', $upcontext['form_url'], '&xml&substep=\' + lastTable, onBackupUpdate); |
||
| 4146 | } |
||
| 4147 | |||
| 4148 | // Got an update! |
||
| 4149 | function onBackupUpdate(oXMLDoc) |
||
| 4150 | { |
||
| 4151 | var sCurrentTableName = ""; |
||
| 4152 | var iTableNum = 0; |
||
| 4153 | var sCompletedTableName = getInnerHTML(document.getElementById(\'current_table\')); |
||
| 4154 | for (var i = 0; i < oXMLDoc.getElementsByTagName("table")[0].childNodes.length; i++) |
||
| 4155 | sCurrentTableName += oXMLDoc.getElementsByTagName("table")[0].childNodes[i].nodeValue; |
||
| 4156 | iTableNum = oXMLDoc.getElementsByTagName("table")[0].getAttribute("num"); |
||
| 4157 | |||
| 4158 | // Update the page. |
||
| 4159 | setInnerHTML(document.getElementById(\'tab_done\'), iTableNum); |
||
| 4160 | setInnerHTML(document.getElementById(\'current_table\'), sCurrentTableName); |
||
| 4161 | lastTable = iTableNum; |
||
| 4162 | updateStepProgress(iTableNum, ', $upcontext['table_count'], ', ', $upcontext['step_weight'] * ((100 - $upcontext['step_progress']) / 100), ');'; |
||
| 4163 | |||
| 4164 | // If debug flood the screen. |
||
| 4165 | if ($is_debug) |
||
| 4166 | echo ' |
||
| 4167 | setOuterHTML(document.getElementById(\'debuginfo\'), \'<br>Completed Table: "\' + sCompletedTableName + \'".<span id="debuginfo"><\' + \'/span>\'); |
||
| 4168 | |||
| 4169 | if (document.getElementById(\'debug_section\').scrollHeight) |
||
| 4170 | document.getElementById(\'debug_section\').scrollTop = document.getElementById(\'debug_section\').scrollHeight'; |
||
| 4171 | |||
| 4172 | echo ' |
||
| 4173 | // Get the next update... |
||
| 4174 | if (iTableNum == ', $upcontext['table_count'], ') |
||
| 4175 | { |
||
| 4176 | document.getElementById(\'commess\').classList.remove("hidden"); |
||
| 4177 | document.getElementById(\'current_tab\').classList.add("hidden"); |
||
| 4178 | document.getElementById(\'contbutt\').disabled = 0; |
||
| 4179 | document.getElementById(\'backup_done\').value = 1; |
||
| 4180 | } |
||
| 4181 | else |
||
| 4182 | getNextTables(); |
||
| 4183 | } |
||
| 4184 | getNextTables(); |
||
| 4185 | //# sourceURL=dynamicScript-bkup.js |
||
| 4186 | </script>'; |
||
| 4187 | } |
||
| 4188 | } |
||
| 4189 | |||
| 4190 | function template_backup_xml() |
||
| 4191 | { |
||
| 4192 | global $upcontext; |
||
| 4193 | |||
| 4194 | echo ' |
||
| 4195 | <table num="', $upcontext['cur_table_num'], '">', $upcontext['cur_table_name'], '</table>'; |
||
| 4196 | } |
||
| 4197 | |||
| 4198 | // Here is the actual "make the changes" template! |
||
| 4199 | function template_database_changes() |
||
| 4200 | { |
||
| 4201 | global $upcontext, $support_js, $is_debug, $timeLimitThreshold, $txt; |
||
| 4202 | |||
| 4203 | if (empty($is_debug) && !empty($upcontext['upgrade_status']['debug'])) |
||
| 4204 | $is_debug = true; |
||
| 4205 | |||
| 4206 | echo ' |
||
| 4207 | <h3>', $txt['upgrade_db_changes'], '</h3> |
||
| 4208 | <h4><em>', $txt['upgrade_db_patient'], '</em></h4>'; |
||
| 4209 | |||
| 4210 | echo ' |
||
| 4211 | <form action="', $upcontext['form_url'], '&filecount=', $upcontext['file_count'], '" name="upform" id="upform" method="post"> |
||
| 4212 | <input type="hidden" name="database_done" id="database_done" value="0">'; |
||
| 4213 | |||
| 4214 | // No javascript looks rubbish! |
||
| 4215 | if (!$support_js) |
||
| 4216 | { |
||
| 4217 | foreach ($upcontext['actioned_items'] as $num => $item) |
||
| 4218 | { |
||
| 4219 | if ($num != 0) |
||
| 4220 | echo ' Successful!'; |
||
| 4221 | echo '<br>' . $item; |
||
| 4222 | } |
||
| 4223 | |||
| 4224 | // Only tell deubbers how much time they wasted waiting for the upgrade because they don't have javascript. |
||
| 4225 | if (!empty($upcontext['changes_complete'])) |
||
| 4226 | { |
||
| 4227 | if ($is_debug) |
||
| 4228 | { |
||
| 4229 | $active = time() - $upcontext['started']; |
||
| 4230 | $hours = floor($active / 3600); |
||
| 4231 | $minutes = intval(($active / 60) % 60); |
||
| 4232 | $seconds = intval($active % 60); |
||
| 4233 | |||
| 4234 | echo '', sprintf($txt['upgrade_success_time_db'], $seconds, $minutes, $hours), '<br>'; |
||
| 4235 | } |
||
| 4236 | else |
||
| 4237 | echo '', $txt['upgrade_success'], '<br>'; |
||
| 4238 | |||
| 4239 | echo ' |
||
| 4240 | <p id="commess">', $txt['upgrade_db_complete'], '</p>'; |
||
| 4241 | } |
||
| 4242 | } |
||
| 4243 | else |
||
| 4244 | { |
||
| 4245 | // Tell them how many files we have in total. |
||
| 4246 | if ($upcontext['file_count'] > 1) |
||
| 4247 | echo ' |
||
| 4248 | <strong id="info1">', $txt['upgrade_script'], ' <span id="file_done">', $upcontext['cur_file_num'], '</span> of ', $upcontext['file_count'], '.</strong>'; |
||
| 4249 | |||
| 4250 | echo ' |
||
| 4251 | <h3 id="info2"> |
||
| 4252 | <strong>', $txt['upgrade_executing'], '</strong> "<span id="cur_item_name">', $upcontext['current_item_name'], '</span>" (<span id="item_num">', $upcontext['current_item_num'], '</span> ', $txt['upgrade_of'], ' <span id="total_items"><span id="item_count">', $upcontext['total_items'], '</span>', $upcontext['file_count'] > 1 ? ' - of this script' : '', ')</span> |
||
| 4253 | </h3> |
||
| 4254 | <p id="commess" class="', !empty($upcontext['changes_complete']) || $upcontext['current_debug_item_num'] == $upcontext['debug_items'] ? 'inline_block' : 'hidden', '">', $txt['upgrade_db_complete2'], '</p>'; |
||
| 4255 | |||
| 4256 | if ($is_debug) |
||
| 4257 | { |
||
| 4258 | // Let our debuggers know how much time was spent, but not wasted since JS handled refreshing the page! |
||
| 4259 | if ($upcontext['current_debug_item_num'] == $upcontext['debug_items']) |
||
| 4260 | { |
||
| 4261 | $active = time() - $upcontext['started']; |
||
| 4262 | $hours = floor($active / 3600); |
||
| 4263 | $minutes = intval(($active / 60) % 60); |
||
| 4264 | $seconds = intval($active % 60); |
||
| 4265 | |||
| 4266 | echo ' |
||
| 4267 | <p id="upgradeCompleted">', sprintf($txt['upgrade_success_time_db'], $seconds, $minutes, $hours), '</p>'; |
||
| 4268 | } |
||
| 4269 | else |
||
| 4270 | echo ' |
||
| 4271 | <p id="upgradeCompleted"></p>'; |
||
| 4272 | |||
| 4273 | echo ' |
||
| 4274 | <div id="debug_section"> |
||
| 4275 | <span id="debuginfo"></span> |
||
| 4276 | </div>'; |
||
| 4277 | } |
||
| 4278 | } |
||
| 4279 | |||
| 4280 | // Place for the XML error message. |
||
| 4281 | echo ' |
||
| 4282 | <div id="error_block" class="errorbox', empty($upcontext['error_message']) ? ' hidden' : '', '"> |
||
| 4283 | <h3>', $txt['upgrade_error'], '</h3> |
||
| 4284 | <div id="error_message">', isset($upcontext['error_message']) ? $upcontext['error_message'] : $txt['upgrade_unknown_error'], '</div> |
||
| 4285 | </div>'; |
||
| 4286 | |||
| 4287 | // We want to continue at some point! |
||
| 4288 | $upcontext['continue'] = $support_js ? 2 : 1; |
||
| 4289 | |||
| 4290 | // If javascript allows we want to do this using XML. |
||
| 4291 | if ($support_js) |
||
| 4292 | { |
||
| 4293 | echo ' |
||
| 4294 | <script> |
||
| 4295 | var lastItem = ', $upcontext['current_debug_item_num'], '; |
||
| 4296 | var sLastString = "', strtr($upcontext['current_debug_item_name'], array('"' => '"')), '"; |
||
| 4297 | var iLastSubStepProgress = -1; |
||
| 4298 | var curFile = ', $upcontext['cur_file_num'], '; |
||
| 4299 | var totalItems = 0; |
||
| 4300 | var prevFile = 0; |
||
| 4301 | var retryCount = 0; |
||
| 4302 | var testvar = 0; |
||
| 4303 | var timeOutID = 0; |
||
| 4304 | var getData = ""; |
||
| 4305 | var debugItems = ', $upcontext['debug_items'], ';'; |
||
| 4306 | |||
| 4307 | if ($is_debug) |
||
| 4308 | echo ' |
||
| 4309 | var upgradeStartTime = ' . $upcontext['started'] . ';'; |
||
| 4310 | |||
| 4311 | echo ' |
||
| 4312 | function getNextItem() |
||
| 4313 | { |
||
| 4314 | // We want to track this... |
||
| 4315 | if (timeOutID) |
||
| 4316 | clearTimeout(timeOutID); |
||
| 4317 | timeOutID = window.setTimeout("retTimeout()", ', (10 * $timeLimitThreshold), '000); |
||
| 4318 | |||
| 4319 | getXMLDocument(\'', $upcontext['form_url'], '&xml&filecount=', $upcontext['file_count'], '&substep=\' + lastItem + getData, onItemUpdate); |
||
| 4320 | } |
||
| 4321 | |||
| 4322 | // Got an update! |
||
| 4323 | function onItemUpdate(oXMLDoc) |
||
| 4324 | { |
||
| 4325 | var sItemName = ""; |
||
| 4326 | var sDebugName = ""; |
||
| 4327 | var iItemNum = 0; |
||
| 4328 | var iSubStepProgress = -1; |
||
| 4329 | var iDebugNum = 0; |
||
| 4330 | var bIsComplete = 0; |
||
| 4331 | var bSkipped = 0; |
||
| 4332 | getData = ""; |
||
| 4333 | |||
| 4334 | // We\'ve got something - so reset the timeout! |
||
| 4335 | if (timeOutID) |
||
| 4336 | clearTimeout(timeOutID); |
||
| 4337 | |||
| 4338 | // Assume no error at this time... |
||
| 4339 | document.getElementById("error_block").classList.add("hidden"); |
||
| 4340 | |||
| 4341 | // Are we getting some duff info? |
||
| 4342 | if (!oXMLDoc.getElementsByTagName("item")[0]) |
||
| 4343 | { |
||
| 4344 | // Too many errors? |
||
| 4345 | if (retryCount > 15) |
||
| 4346 | { |
||
| 4347 | document.getElementById("error_block").classList.remove("hidden"); |
||
| 4348 | setInnerHTML(document.getElementById("error_message"), "Error retrieving information on step: " + (sDebugName == "" ? sLastString : sDebugName));'; |
||
| 4349 | |||
| 4350 | if ($is_debug) |
||
| 4351 | echo ' |
||
| 4352 | setOuterHTML(document.getElementById(\'debuginfo\'), \'<span class="red">failed<\' + \'/span><span id="debuginfo"><\' + \'/span>\');'; |
||
| 4353 | |||
| 4354 | echo ' |
||
| 4355 | } |
||
| 4356 | else |
||
| 4357 | { |
||
| 4358 | retryCount++; |
||
| 4359 | getNextItem(); |
||
| 4360 | } |
||
| 4361 | return false; |
||
| 4362 | } |
||
| 4363 | |||
| 4364 | // Never allow loops. |
||
| 4365 | if (curFile == prevFile) |
||
| 4366 | { |
||
| 4367 | retryCount++; |
||
| 4368 | if (retryCount > 10) |
||
| 4369 | { |
||
| 4370 | document.getElementById("error_block").classList.remove("hidden"); |
||
| 4371 | setInnerHTML(document.getElementById("error_message"), "', $txt['upgrade_loop'], '" + sDebugName);'; |
||
| 4372 | |||
| 4373 | if ($is_debug) |
||
| 4374 | echo ' |
||
| 4375 | setOuterHTML(document.getElementById(\'debuginfo\'), \'<span class="red">failed<\' + \'/span><span id="debuginfo"><\' + \'/span>\');'; |
||
| 4376 | |||
| 4377 | echo ' |
||
| 4378 | } |
||
| 4379 | } |
||
| 4380 | retryCount = 0; |
||
| 4381 | |||
| 4382 | for (var i = 0; i < oXMLDoc.getElementsByTagName("item")[0].childNodes.length; i++) |
||
| 4383 | sItemName += oXMLDoc.getElementsByTagName("item")[0].childNodes[i].nodeValue; |
||
| 4384 | for (var i = 0; i < oXMLDoc.getElementsByTagName("debug")[0].childNodes.length; i++) |
||
| 4385 | sDebugName += oXMLDoc.getElementsByTagName("debug")[0].childNodes[i].nodeValue; |
||
| 4386 | for (var i = 0; i < oXMLDoc.getElementsByTagName("get").length; i++) |
||
| 4387 | { |
||
| 4388 | getData += "&" + oXMLDoc.getElementsByTagName("get")[i].getAttribute("key") + "="; |
||
| 4389 | for (var j = 0; j < oXMLDoc.getElementsByTagName("get")[i].childNodes.length; j++) |
||
| 4390 | { |
||
| 4391 | getData += oXMLDoc.getElementsByTagName("get")[i].childNodes[j].nodeValue; |
||
| 4392 | } |
||
| 4393 | } |
||
| 4394 | |||
| 4395 | iItemNum = oXMLDoc.getElementsByTagName("item")[0].getAttribute("num"); |
||
| 4396 | iDebugNum = parseInt(oXMLDoc.getElementsByTagName("debug")[0].getAttribute("num")); |
||
| 4397 | bIsComplete = parseInt(oXMLDoc.getElementsByTagName("debug")[0].getAttribute("complete")); |
||
| 4398 | bSkipped = parseInt(oXMLDoc.getElementsByTagName("debug")[0].getAttribute("skipped")); |
||
| 4399 | iSubStepProgress = parseFloat(oXMLDoc.getElementsByTagName("debug")[0].getAttribute("percent")); |
||
| 4400 | sLastString = sDebugName + " (Item: " + iDebugNum + ")"; |
||
| 4401 | |||
| 4402 | curFile = parseInt(oXMLDoc.getElementsByTagName("file")[0].getAttribute("num")); |
||
| 4403 | debugItems = parseInt(oXMLDoc.getElementsByTagName("file")[0].getAttribute("debug_items")); |
||
| 4404 | totalItems = parseInt(oXMLDoc.getElementsByTagName("file")[0].getAttribute("items")); |
||
| 4405 | |||
| 4406 | // If we have an error we haven\'t completed! |
||
| 4407 | if (oXMLDoc.getElementsByTagName("error")[0] && bIsComplete) |
||
| 4408 | iDebugNum = lastItem; |
||
| 4409 | |||
| 4410 | // Do we have the additional progress bar? |
||
| 4411 | if (iSubStepProgress != -1) |
||
| 4412 | { |
||
| 4413 | document.getElementById("substep_bar_div").classList.remove("hidden"); |
||
| 4414 | document.getElementById("substep_progress").style.width = iSubStepProgress + "%"; |
||
| 4415 | setInnerHTML(document.getElementById("substep_text"), iSubStepProgress + "%"); |
||
| 4416 | setInnerHTML(document.getElementById("substep_name"), sDebugName.replace(/\./g, "")); |
||
| 4417 | } |
||
| 4418 | else |
||
| 4419 | { |
||
| 4420 | document.getElementById("substep_bar_div").classList.add("hidden"); |
||
| 4421 | } |
||
| 4422 | |||
| 4423 | // Move onto the next item? |
||
| 4424 | if (bIsComplete) |
||
| 4425 | lastItem = iDebugNum; |
||
| 4426 | else |
||
| 4427 | lastItem = iDebugNum - 1; |
||
| 4428 | |||
| 4429 | // Are we finished? |
||
| 4430 | if (bIsComplete && iDebugNum == -1 && curFile >= ', $upcontext['file_count'], ') |
||
| 4431 | {'; |
||
| 4432 | |||
| 4433 | // Database Changes, tell us how much time we spen to do this. If this gets updated via JS. |
||
| 4434 | if ($is_debug) |
||
| 4435 | echo ' |
||
| 4436 | document.getElementById(\'debug_section\').classList.add("hidden"); |
||
| 4437 | |||
| 4438 | var upgradeFinishedTime = parseInt(oXMLDoc.getElementsByTagName("curtime")[0].childNodes[0].nodeValue); |
||
| 4439 | var diffTime = upgradeFinishedTime - upgradeStartTime; |
||
| 4440 | var diffHours = Math.floor(diffTime / 3600); |
||
| 4441 | var diffMinutes = parseInt((diffTime / 60) % 60); |
||
| 4442 | var diffSeconds = parseInt(diffTime % 60); |
||
| 4443 | |||
| 4444 | var completedTxt = "', $txt['upgrade_success_time_db'], '"; |
||
| 4445 | console.log(completedTxt, upgradeFinishedTime, diffTime, diffHours, diffMinutes, diffSeconds); |
||
| 4446 | |||
| 4447 | completedTxt = completedTxt.replace("%1$d", diffSeconds).replace("%2$d", diffMinutes).replace("%3$d", diffHours); |
||
| 4448 | console.log(completedTxt, upgradeFinishedTime, diffTime, diffHours, diffMinutes, diffSeconds); |
||
| 4449 | setInnerHTML(document.getElementById("upgradeCompleted"), completedTxt);'; |
||
| 4450 | |||
| 4451 | echo ' |
||
| 4452 | |||
| 4453 | document.getElementById(\'commess\').classList.remove("hidden"); |
||
| 4454 | document.getElementById(\'contbutt\').disabled = 0; |
||
| 4455 | document.getElementById(\'database_done\').value = 1;'; |
||
| 4456 | |||
| 4457 | if ($upcontext['file_count'] > 1) |
||
| 4458 | echo ' |
||
| 4459 | document.getElementById(\'info1\').classList.add(\'hidden\');'; |
||
| 4460 | |||
| 4461 | echo ' |
||
| 4462 | document.getElementById(\'info2\').classList.add(\'hidden\'); |
||
| 4463 | updateStepProgress(100, 100, ', $upcontext['step_weight'] * ((100 - $upcontext['step_progress']) / 100), '); |
||
| 4464 | return true; |
||
| 4465 | } |
||
| 4466 | // Was it the last step in the file? |
||
| 4467 | else if (bIsComplete && iDebugNum == -1) |
||
| 4468 | { |
||
| 4469 | lastItem = 0; |
||
| 4470 | prevFile = curFile;'; |
||
| 4471 | |||
| 4472 | if ($is_debug) |
||
| 4473 | echo ' |
||
| 4474 | setOuterHTML(document.getElementById(\'debuginfo\'), \'Moving to next script file...done<br><span id="debuginfo"><\' + \'/span>\');'; |
||
| 4475 | |||
| 4476 | echo ' |
||
| 4477 | getNextItem(); |
||
| 4478 | return true; |
||
| 4479 | }'; |
||
| 4480 | |||
| 4481 | // If debug scroll the screen. |
||
| 4482 | if ($is_debug) |
||
| 4483 | echo ' |
||
| 4484 | if (iLastSubStepProgress == -1) |
||
| 4485 | { |
||
| 4486 | // Give it consistent dots. |
||
| 4487 | dots = sDebugName.match(/\./g); |
||
| 4488 | numDots = dots ? dots.length : 0; |
||
| 4489 | for (var i = numDots; i < 3; i++) |
||
| 4490 | sDebugName += "."; |
||
| 4491 | setOuterHTML(document.getElementById(\'debuginfo\'), sDebugName + \'<span id="debuginfo"><\' + \'/span>\'); |
||
| 4492 | } |
||
| 4493 | iLastSubStepProgress = iSubStepProgress; |
||
| 4494 | |||
| 4495 | if (bIsComplete && bSkipped) |
||
| 4496 | setOuterHTML(document.getElementById(\'debuginfo\'), \'skipped<br><span id="debuginfo"><\' + \'/span>\'); |
||
| 4497 | else if (bIsComplete) |
||
| 4498 | setOuterHTML(document.getElementById(\'debuginfo\'), \'done<br><span id="debuginfo"><\' + \'/span>\'); |
||
| 4499 | else |
||
| 4500 | setOuterHTML(document.getElementById(\'debuginfo\'), \'...<span id="debuginfo"><\' + \'/span>\'); |
||
| 4501 | |||
| 4502 | if (document.getElementById(\'debug_section\').scrollHeight) |
||
| 4503 | document.getElementById(\'debug_section\').scrollTop = document.getElementById(\'debug_section\').scrollHeight'; |
||
| 4504 | |||
| 4505 | echo ' |
||
| 4506 | // Update the page. |
||
| 4507 | setInnerHTML(document.getElementById(\'item_num\'), iItemNum); |
||
| 4508 | setInnerHTML(document.getElementById(\'cur_item_name\'), sItemName);'; |
||
| 4509 | |||
| 4510 | if ($upcontext['file_count'] > 1) |
||
| 4511 | { |
||
| 4512 | echo ' |
||
| 4513 | setInnerHTML(document.getElementById(\'file_done\'), curFile); |
||
| 4514 | setInnerHTML(document.getElementById(\'item_count\'), totalItems);'; |
||
| 4515 | } |
||
| 4516 | |||
| 4517 | echo ' |
||
| 4518 | // Is there an error? |
||
| 4519 | if (oXMLDoc.getElementsByTagName("error")[0]) |
||
| 4520 | { |
||
| 4521 | var sErrorMsg = ""; |
||
| 4522 | for (var i = 0; i < oXMLDoc.getElementsByTagName("error")[0].childNodes.length; i++) |
||
| 4523 | sErrorMsg += oXMLDoc.getElementsByTagName("error")[0].childNodes[i].nodeValue; |
||
| 4524 | document.getElementById("error_block").classList.remove("hidden"); |
||
| 4525 | setInnerHTML(document.getElementById("error_message"), sErrorMsg); |
||
| 4526 | return false; |
||
| 4527 | } |
||
| 4528 | |||
| 4529 | // Get the progress bar right. |
||
| 4530 | barTotal = debugItems * ', $upcontext['file_count'], '; |
||
| 4531 | barDone = (debugItems * (curFile - 1)) + lastItem; |
||
| 4532 | |||
| 4533 | updateStepProgress(barDone, barTotal, ', $upcontext['step_weight'] * ((100 - $upcontext['step_progress']) / 100), '); |
||
| 4534 | |||
| 4535 | // Finally - update the time here as it shows the server is responding! |
||
| 4536 | curTime = new Date(); |
||
| 4537 | iElapsed = (curTime.getTime() / 1000 - ', $upcontext['started'], '); |
||
| 4538 | mins = parseInt(iElapsed / 60); |
||
| 4539 | secs = parseInt(iElapsed - mins * 60); |
||
| 4540 | setInnerHTML(document.getElementById("mins_elapsed"), mins); |
||
| 4541 | setInnerHTML(document.getElementById("secs_elapsed"), secs); |
||
| 4542 | |||
| 4543 | getNextItem(); |
||
| 4544 | return true; |
||
| 4545 | } |
||
| 4546 | |||
| 4547 | // What if we timeout?! |
||
| 4548 | function retTimeout(attemptAgain) |
||
| 4549 | { |
||
| 4550 | // Oh noes... |
||
| 4551 | if (!attemptAgain) |
||
| 4552 | { |
||
| 4553 | document.getElementById("error_block").classList.remove("hidden"); |
||
| 4554 | setInnerHTML(document.getElementById("error_message"), "', sprintf($txt['upgrade_repondtime'], ($timeLimitThreshold * 10)), '" + "<a href=\"#\" onclick=\"retTimeout(true); return false;\">', $txt['upgrade_respondtime_clickhere'], '</a>"); |
||
| 4555 | } |
||
| 4556 | else |
||
| 4557 | { |
||
| 4558 | document.getElementById("error_block").classList.add("hidden"); |
||
| 4559 | getNextItem(); |
||
| 4560 | } |
||
| 4561 | }'; |
||
| 4562 | |||
| 4563 | // Start things off assuming we've not errored. |
||
| 4564 | if (empty($upcontext['error_message'])) |
||
| 4565 | echo ' |
||
| 4566 | getNextItem();'; |
||
| 4567 | |||
| 4568 | echo ' |
||
| 4569 | //# sourceURL=dynamicScript-dbch.js |
||
| 4570 | </script>'; |
||
| 4571 | } |
||
| 4572 | return; |
||
| 4573 | } |
||
| 4574 | |||
| 4575 | function template_database_xml() |
||
| 4576 | { |
||
| 4577 | global $is_debug, $upcontext; |
||
| 4578 | |||
| 4579 | echo ' |
||
| 4580 | <file num="', $upcontext['cur_file_num'], '" items="', $upcontext['total_items'], '" debug_items="', $upcontext['debug_items'], '">', $upcontext['cur_file_name'], '</file> |
||
| 4581 | <item num="', $upcontext['current_item_num'], '">', $upcontext['current_item_name'], '</item> |
||
| 4582 | <debug num="', $upcontext['current_debug_item_num'], '" percent="', isset($upcontext['substep_progress']) ? $upcontext['substep_progress'] : '-1', '" complete="', empty($upcontext['completed_step']) ? 0 : 1, '" skipped="', empty($upcontext['skip_db_substeps']) ? 0 : 1, '">', $upcontext['current_debug_item_name'], '</debug>'; |
||
| 4583 | |||
| 4584 | if (!empty($upcontext['error_message'])) |
||
| 4585 | echo ' |
||
| 4586 | <error>', $upcontext['error_message'], '</error>'; |
||
| 4587 | |||
| 4588 | if (!empty($upcontext['error_string'])) |
||
| 4589 | echo ' |
||
| 4590 | <sql>', $upcontext['error_string'], '</sql>'; |
||
| 4591 | |||
| 4592 | if ($is_debug) |
||
| 4593 | echo ' |
||
| 4594 | <curtime>', time(), '</curtime>'; |
||
| 4595 | } |
||
| 4596 | |||
| 4597 | // Template for the UTF-8 conversion step. Basically a copy of the backup stuff with slight modifications.... |
||
| 4598 | function template_convert_utf8() |
||
| 4599 | { |
||
| 4600 | global $upcontext, $support_js, $is_debug, $txt; |
||
| 4601 | |||
| 4602 | echo ' |
||
| 4603 | <h3>', $txt['upgrade_wait2'], '</h3> |
||
| 4604 | <form action="', $upcontext['form_url'], '" name="upform" id="upform" method="post"> |
||
| 4605 | <input type="hidden" name="utf8_done" id="utf8_done" value="0"> |
||
| 4606 | <strong>', $txt['upgrade_completed'], ' <span id="tab_done">', $upcontext['cur_table_num'], '</span> ', $txt['upgrade_outof'], ' ', $upcontext['table_count'], ' ', $txt['upgrade_tables'], '</strong> |
||
| 4607 | <div id="debug_section"> |
||
| 4608 | <span id="debuginfo"></span> |
||
| 4609 | </div>'; |
||
| 4610 | |||
| 4611 | // Done any tables so far? |
||
| 4612 | if (!empty($upcontext['previous_tables'])) |
||
| 4613 | foreach ($upcontext['previous_tables'] as $table) |
||
| 4614 | echo ' |
||
| 4615 | <br>', $txt['upgrade_completed_table'], ' "', $table, '".'; |
||
| 4616 | |||
| 4617 | echo ' |
||
| 4618 | <h3 id="current_tab"> |
||
| 4619 | ', $txt['upgrade_current_table'], ' "<span id="current_table">', $upcontext['cur_table_name'], '</span>" |
||
| 4620 | </h3>'; |
||
| 4621 | |||
| 4622 | // If we dropped their index, let's let them know |
||
| 4623 | if ($upcontext['dropping_index']) |
||
| 4624 | echo ' |
||
| 4625 | <p id="indexmsg" class="', $upcontext['cur_table_num'] == $upcontext['table_count'] ? 'inline_block' : 'hidden', '>', $txt['upgrade_fulltext'], '</p>'; |
||
| 4626 | |||
| 4627 | // Completion notification |
||
| 4628 | echo ' |
||
| 4629 | <p id="commess" class="', $upcontext['cur_table_num'] == $upcontext['table_count'] ? 'inline_block' : 'hidden', '">', $txt['upgrade_conversion_proceed'], '</p>'; |
||
| 4630 | |||
| 4631 | // Continue please! |
||
| 4632 | $upcontext['continue'] = $support_js ? 2 : 1; |
||
| 4633 | |||
| 4634 | // If javascript allows we want to do this using XML. |
||
| 4635 | if ($support_js) |
||
| 4636 | { |
||
| 4637 | echo ' |
||
| 4638 | <script> |
||
| 4639 | var lastTable = ', $upcontext['cur_table_num'], '; |
||
| 4640 | function getNextTables() |
||
| 4641 | { |
||
| 4642 | getXMLDocument(\'', $upcontext['form_url'], '&xml&substep=\' + lastTable, onConversionUpdate); |
||
| 4643 | } |
||
| 4644 | |||
| 4645 | // Got an update! |
||
| 4646 | function onConversionUpdate(oXMLDoc) |
||
| 4647 | { |
||
| 4648 | var sCurrentTableName = ""; |
||
| 4649 | var iTableNum = 0; |
||
| 4650 | var sCompletedTableName = getInnerHTML(document.getElementById(\'current_table\')); |
||
| 4651 | for (var i = 0; i < oXMLDoc.getElementsByTagName("table")[0].childNodes.length; i++) |
||
| 4652 | sCurrentTableName += oXMLDoc.getElementsByTagName("table")[0].childNodes[i].nodeValue; |
||
| 4653 | iTableNum = oXMLDoc.getElementsByTagName("table")[0].getAttribute("num"); |
||
| 4654 | |||
| 4655 | // Update the page. |
||
| 4656 | setInnerHTML(document.getElementById(\'tab_done\'), iTableNum); |
||
| 4657 | setInnerHTML(document.getElementById(\'current_table\'), sCurrentTableName); |
||
| 4658 | lastTable = iTableNum; |
||
| 4659 | updateStepProgress(iTableNum, ', $upcontext['table_count'], ', ', $upcontext['step_weight'] * ((100 - $upcontext['step_progress']) / 100), ');'; |
||
| 4660 | |||
| 4661 | // If debug flood the screen. |
||
| 4662 | if ($is_debug) |
||
| 4663 | echo ' |
||
| 4664 | setOuterHTML(document.getElementById(\'debuginfo\'), \'<br>Completed Table: "\' + sCompletedTableName + \'".<span id="debuginfo"><\' + \'/span>\'); |
||
| 4665 | |||
| 4666 | if (document.getElementById(\'debug_section\').scrollHeight) |
||
| 4667 | document.getElementById(\'debug_section\').scrollTop = document.getElementById(\'debug_section\').scrollHeight'; |
||
| 4668 | |||
| 4669 | echo ' |
||
| 4670 | // Get the next update... |
||
| 4671 | if (iTableNum == ', $upcontext['table_count'], ') |
||
| 4672 | { |
||
| 4673 | document.getElementById(\'commess\').classList.remove(\'hidden\'); |
||
| 4674 | if (document.getElementById(\'indexmsg\') != null) { |
||
| 4675 | document.getElementById(\'indexmsg\').classList.remove(\'hidden\'); |
||
| 4676 | } |
||
| 4677 | document.getElementById(\'current_tab\').classList.add(\'hidden\'); |
||
| 4678 | document.getElementById(\'contbutt\').disabled = 0; |
||
| 4679 | document.getElementById(\'utf8_done\').value = 1; |
||
| 4680 | } |
||
| 4681 | else |
||
| 4682 | getNextTables(); |
||
| 4683 | } |
||
| 4684 | getNextTables(); |
||
| 4685 | //# sourceURL=dynamicScript-conv.js |
||
| 4686 | </script>'; |
||
| 4687 | } |
||
| 4688 | } |
||
| 4689 | |||
| 4690 | function template_convert_xml() |
||
| 4691 | { |
||
| 4692 | global $upcontext; |
||
| 4693 | |||
| 4694 | echo ' |
||
| 4695 | <table num="', $upcontext['cur_table_num'], '">', $upcontext['cur_table_name'], '</table>'; |
||
| 4696 | } |
||
| 4697 | |||
| 4698 | // Template for the database backup tool/ |
||
| 4699 | function template_serialize_json() |
||
| 4700 | { |
||
| 4701 | global $upcontext, $support_js, $is_debug, $txt; |
||
| 4702 | |||
| 4703 | echo ' |
||
| 4704 | <h3>', $txt['upgrade_convert_datajson'], '</h3> |
||
| 4705 | <form action="', $upcontext['form_url'], '" name="upform" id="upform" method="post"> |
||
| 4706 | <input type="hidden" name="json_done" id="json_done" value="0"> |
||
| 4707 | <strong>', $txt['upgrade_completed'], ' <span id="tab_done">', $upcontext['cur_table_num'], '</span> ', $txt['upgrade_outof'], ' ', $upcontext['table_count'], ' ', $txt['upgrade_tables'], '</strong> |
||
| 4708 | <div id="debug_section"> |
||
| 4709 | <span id="debuginfo"></span> |
||
| 4710 | </div>'; |
||
| 4711 | |||
| 4712 | // Dont any tables so far? |
||
| 4713 | if (!empty($upcontext['previous_tables'])) |
||
| 4714 | foreach ($upcontext['previous_tables'] as $table) |
||
| 4715 | echo ' |
||
| 4716 | <br>', $txt['upgrade_completed_table'], ' "', $table, '".'; |
||
| 4717 | |||
| 4718 | echo ' |
||
| 4719 | <h3 id="current_tab"> |
||
| 4720 | ', $txt['upgrade_current_table'], ' "<span id="current_table">', $upcontext['cur_table_name'], '</span>" |
||
| 4721 | </h3> |
||
| 4722 | <p id="commess" class="', $upcontext['cur_table_num'] == $upcontext['table_count'] ? 'inline_block' : 'hidden', '">', $txt['upgrade_json_completed'], '</p>'; |
||
| 4723 | |||
| 4724 | // Try to make sure substep was reset. |
||
| 4725 | if ($upcontext['cur_table_num'] == $upcontext['table_count']) |
||
| 4726 | echo ' |
||
| 4727 | <input type="hidden" name="substep" id="substep" value="0">'; |
||
| 4728 | |||
| 4729 | // Continue please! |
||
| 4730 | $upcontext['continue'] = $support_js ? 2 : 1; |
||
| 4731 | |||
| 4732 | // If javascript allows we want to do this using XML. |
||
| 4733 | if ($support_js) |
||
| 4734 | { |
||
| 4735 | echo ' |
||
| 4736 | <script> |
||
| 4737 | var lastTable = ', $upcontext['cur_table_num'], '; |
||
| 4738 | function getNextTables() |
||
| 4739 | { |
||
| 4740 | getXMLDocument(\'', $upcontext['form_url'], '&xml&substep=\' + lastTable, onBackupUpdate); |
||
| 4741 | } |
||
| 4742 | |||
| 4743 | // Got an update! |
||
| 4744 | function onBackupUpdate(oXMLDoc) |
||
| 4745 | { |
||
| 4746 | var sCurrentTableName = ""; |
||
| 4747 | var iTableNum = 0; |
||
| 4748 | var sCompletedTableName = getInnerHTML(document.getElementById(\'current_table\')); |
||
| 4749 | for (var i = 0; i < oXMLDoc.getElementsByTagName("table")[0].childNodes.length; i++) |
||
| 4750 | sCurrentTableName += oXMLDoc.getElementsByTagName("table")[0].childNodes[i].nodeValue; |
||
| 4751 | iTableNum = oXMLDoc.getElementsByTagName("table")[0].getAttribute("num"); |
||
| 4752 | |||
| 4753 | // Update the page. |
||
| 4754 | setInnerHTML(document.getElementById(\'tab_done\'), iTableNum); |
||
| 4755 | setInnerHTML(document.getElementById(\'current_table\'), sCurrentTableName); |
||
| 4756 | lastTable = iTableNum; |
||
| 4757 | updateStepProgress(iTableNum, ', $upcontext['table_count'], ', ', $upcontext['step_weight'] * ((100 - $upcontext['step_progress']) / 100), ');'; |
||
| 4758 | |||
| 4759 | // If debug flood the screen. |
||
| 4760 | if ($is_debug) |
||
| 4761 | echo ' |
||
| 4762 | setOuterHTML(document.getElementById(\'debuginfo\'), \'<br>', $txt['upgrade_completed_table'], ' "\' + sCompletedTableName + \'".<span id="debuginfo"><\' + \'/span>\'); |
||
| 4763 | |||
| 4764 | if (document.getElementById(\'debug_section\').scrollHeight) |
||
| 4765 | document.getElementById(\'debug_section\').scrollTop = document.getElementById(\'debug_section\').scrollHeight'; |
||
| 4766 | |||
| 4767 | echo ' |
||
| 4768 | // Get the next update... |
||
| 4769 | if (iTableNum == ', $upcontext['table_count'], ') |
||
| 4770 | { |
||
| 4771 | document.getElementById(\'commess\').classList.remove("hidden"); |
||
| 4772 | document.getElementById(\'current_tab\').classList.add("hidden"); |
||
| 4773 | document.getElementById(\'contbutt\').disabled = 0; |
||
| 4774 | document.getElementById(\'json_done\').value = 1; |
||
| 4775 | } |
||
| 4776 | else |
||
| 4777 | getNextTables(); |
||
| 4778 | } |
||
| 4779 | getNextTables(); |
||
| 4780 | //# sourceURL=dynamicScript-json.js |
||
| 4781 | </script>'; |
||
| 4782 | } |
||
| 4783 | } |
||
| 4784 | |||
| 4785 | function template_serialize_json_xml() |
||
| 4786 | { |
||
| 4787 | global $upcontext; |
||
| 4788 | |||
| 4789 | echo ' |
||
| 4790 | <table num="', $upcontext['cur_table_num'], '">', $upcontext['cur_table_name'], '</table>'; |
||
| 4791 | } |
||
| 4792 | |||
| 4793 | function template_upgrade_complete() |
||
| 4794 | { |
||
| 4795 | global $upcontext, $upgradeurl, $settings, $boardurl, $is_debug, $txt; |
||
| 4796 | |||
| 4797 | echo ' |
||
| 4798 | <h3>', $txt['upgrade_done'], ' <a href="', $boardurl, '/index.php">', $txt['upgrade_done2'], '</a>. ', $txt['upgrade_done3'], '</h3> |
||
| 4799 | <form action="', $boardurl, '/index.php">'; |
||
| 4800 | |||
| 4801 | if (!empty($upcontext['can_delete_script'])) |
||
| 4802 | echo ' |
||
| 4803 | <label> |
||
| 4804 | <input type="checkbox" id="delete_self" onclick="doTheDelete(this);"> ', $txt['upgrade_delete_now'], ' |
||
| 4805 | </label> |
||
| 4806 | <em>', $txt['upgrade_delete_server'], '</em> |
||
| 4807 | <script> |
||
| 4808 | function doTheDelete(theCheck) |
||
| 4809 | { |
||
| 4810 | var theImage = document.getElementById ? document.getElementById("delete_upgrader") : document.all.delete_upgrader; |
||
| 4811 | theImage.src = "', $upgradeurl, '?delete=1&ts_" + (new Date().getTime()); |
||
| 4812 | theCheck.disabled = true; |
||
| 4813 | } |
||
| 4814 | </script> |
||
| 4815 | <img src="', $settings['default_theme_url'], '/images/blank.png" alt="" id="delete_upgrader"><br>'; |
||
| 4816 | |||
| 4817 | // Show Upgrade time in debug mode when we completed the upgrade process totally |
||
| 4818 | if ($is_debug) |
||
| 4819 | { |
||
| 4820 | $active = time() - $upcontext['started']; |
||
| 4821 | $hours = floor($active / 3600); |
||
| 4822 | $minutes = intval(($active / 60) % 60); |
||
| 4823 | $seconds = intval($active % 60); |
||
| 4824 | |||
| 4825 | if ($hours > 0) |
||
| 4826 | echo '', sprintf($txt['upgrade_completed_time_hms'], $seconds, $minutes, $hours), ''; |
||
| 4827 | elseif ($minutes > 0) |
||
| 4828 | echo '', sprintf($txt['upgrade_completed_time_ms'], $seconds, $minutes), ''; |
||
| 4829 | elseif ($seconds > 0) |
||
| 4830 | echo '', sprintf($txt['upgrade_completed_time_s'], $seconds), ''; |
||
| 4831 | } |
||
| 4832 | |||
| 4833 | echo ' |
||
| 4834 | <p> |
||
| 4835 | ', sprintf($txt['upgrade_problems'], 'http://simplemachines.org'), ' |
||
| 4836 | <br> |
||
| 4837 | ', $txt['upgrade_luck'], '<br> |
||
| 4838 | Simple Machines |
||
| 4839 | </p>'; |
||
| 4840 | } |
||
| 4841 | |||
| 4842 | /** |
||
| 4843 | * Convert MySQL (var)char ip col to binary |
||
| 4844 | * |
||
| 4845 | * @param string $targetTable The table to perform the operation on |
||
| 4846 | * @param string $oldCol The old column to gather data from |
||
| 4847 | * @param string $newCol The new column to put data in |
||
| 4848 | * @param int $limit The amount of entries to handle at once. |
||
| 4849 | * @param int $setSize The amount of entries after which to update the database. |
||
| 4850 | * |
||
| 4851 | * newCol needs to be a varbinary(16) null able field |
||
| 4852 | * @return bool |
||
| 4853 | */ |
||
| 4854 | function MySQLConvertOldIp($targetTable, $oldCol, $newCol, $limit = 50000, $setSize = 100) |
||
| 4855 | { |
||
| 4856 | global $smcFunc, $step_progress; |
||
| 4857 | |||
| 4858 | $current_substep = $_GET['substep']; |
||
| 4859 | |||
| 4860 | if (empty($_GET['a'])) |
||
| 4861 | $_GET['a'] = 0; |
||
| 4862 | $step_progress['name'] = 'Converting ips'; |
||
| 4863 | $step_progress['current'] = $_GET['a']; |
||
| 4864 | |||
| 4865 | // Skip this if we don't have the column |
||
| 4866 | $request = $smcFunc['db_query']('', ' |
||
| 4867 | SHOW FIELDS |
||
| 4868 | FROM {db_prefix}{raw:table} |
||
| 4869 | WHERE Field = {string:name}', |
||
| 4870 | array( |
||
| 4871 | 'table' => $targetTable, |
||
| 4872 | 'name' => $oldCol, |
||
| 4873 | ) |
||
| 4874 | ); |
||
| 4875 | if ($smcFunc['db_num_rows']($request) !== 1) |
||
| 4876 | { |
||
| 4877 | $smcFunc['db_free_result']($request); |
||
| 4878 | return; |
||
| 4879 | } |
||
| 4880 | $smcFunc['db_free_result']($request); |
||
| 4881 | |||
| 4882 | //mysql default max length is 1mb https://dev.mysql.com/doc/refman/5.1/en/packet-too-large.html |
||
| 4883 | $arIp = array(); |
||
| 4884 | |||
| 4885 | $is_done = false; |
||
| 4886 | while (!$is_done) |
||
| 4887 | { |
||
| 4888 | // Keep looping at the current step. |
||
| 4889 | nextSubstep($current_substep); |
||
| 4890 | |||
| 4891 | $arIp = array(); |
||
| 4892 | |||
| 4893 | $request = $smcFunc['db_query']('', ' |
||
| 4894 | SELECT DISTINCT {raw:old_col} |
||
| 4895 | FROM {db_prefix}{raw:table_name} |
||
| 4896 | WHERE {raw:new_col} IS NULL AND |
||
| 4897 | {raw:old_col} != {string:unknown} AND |
||
| 4898 | {raw:old_col} != {string:empty} |
||
| 4899 | LIMIT {int:limit}', |
||
| 4900 | array( |
||
| 4901 | 'old_col' => $oldCol, |
||
| 4902 | 'new_col' => $newCol, |
||
| 4903 | 'table_name' => $targetTable, |
||
| 4904 | 'empty' => '', |
||
| 4905 | 'limit' => $limit, |
||
| 4906 | 'unknown' => 'unknown', |
||
| 4907 | ) |
||
| 4908 | ); |
||
| 4909 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 4910 | $arIp[] = $row[$oldCol]; |
||
| 4911 | |||
| 4912 | $smcFunc['db_free_result']($request); |
||
| 4913 | |||
| 4914 | // Special case, null ip could keep us in a loop. |
||
| 4915 | if (is_null($arIp[0])) |
||
| 4916 | unset($arIp[0]); |
||
| 4917 | |||
| 4918 | if (empty($arIp)) |
||
| 4919 | $is_done = true; |
||
| 4920 | |||
| 4921 | $updates = array(); |
||
| 4922 | $cases = array(); |
||
| 4923 | $count = count($arIp); |
||
| 4924 | for ($i = 0; $i < $count; $i++) |
||
| 4925 | { |
||
| 4926 | $arIp[$i] = trim($arIp[$i]); |
||
| 4927 | |||
| 4928 | if (empty($arIp[$i])) |
||
| 4929 | continue; |
||
| 4930 | |||
| 4931 | $updates['ip' . $i] = $arIp[$i]; |
||
| 4932 | $cases[$arIp[$i]] = 'WHEN ' . $oldCol . ' = {string:ip' . $i . '} THEN {inet:ip' . $i . '}'; |
||
| 4933 | |||
| 4934 | if ($setSize > 0 && $i % $setSize === 0) |
||
| 4935 | { |
||
| 4936 | if (count($updates) == 1) |
||
| 4937 | continue; |
||
| 4938 | |||
| 4939 | $updates['whereSet'] = array_values($updates); |
||
| 4940 | $smcFunc['db_query']('', ' |
||
| 4941 | UPDATE {db_prefix}' . $targetTable . ' |
||
| 4942 | SET ' . $newCol . ' = CASE ' . |
||
| 4943 | implode(' |
||
| 4944 | ', $cases) . ' |
||
| 4945 | ELSE NULL |
||
| 4946 | END |
||
| 4947 | WHERE ' . $oldCol . ' IN ({array_string:whereSet})', |
||
| 4948 | $updates |
||
| 4949 | ); |
||
| 4950 | |||
| 4951 | $updates = array(); |
||
| 4952 | $cases = array(); |
||
| 4953 | } |
||
| 4954 | } |
||
| 4955 | |||
| 4956 | // Incase some extras made it through. |
||
| 4957 | if (!empty($updates)) |
||
| 4958 | { |
||
| 4959 | if (count($updates) == 1) |
||
| 4960 | { |
||
| 4961 | foreach ($updates as $key => $ip) |
||
| 4962 | { |
||
| 4963 | $smcFunc['db_query']('', ' |
||
| 4964 | UPDATE {db_prefix}' . $targetTable . ' |
||
| 4965 | SET ' . $newCol . ' = {inet:ip} |
||
| 4966 | WHERE ' . $oldCol . ' = {string:ip}', |
||
| 4967 | array( |
||
| 4968 | 'ip' => $ip |
||
| 4969 | ) |
||
| 4970 | ); |
||
| 4971 | } |
||
| 4972 | } |
||
| 4973 | else |
||
| 4974 | { |
||
| 4975 | $updates['whereSet'] = array_values($updates); |
||
| 4976 | $smcFunc['db_query']('', ' |
||
| 4977 | UPDATE {db_prefix}' . $targetTable . ' |
||
| 4978 | SET ' . $newCol . ' = CASE ' . |
||
| 4979 | implode(' |
||
| 4980 | ', $cases) . ' |
||
| 4981 | ELSE NULL |
||
| 4982 | END |
||
| 4983 | WHERE ' . $oldCol . ' IN ({array_string:whereSet})', |
||
| 4984 | $updates |
||
| 4985 | ); |
||
| 4986 | } |
||
| 4987 | } |
||
| 4988 | else |
||
| 4989 | $is_done = true; |
||
| 4990 | |||
| 4991 | $_GET['a'] += $limit; |
||
| 4992 | $step_progress['current'] = $_GET['a']; |
||
| 4993 | } |
||
| 4994 | |||
| 4995 | unset($_GET['a']); |
||
| 4996 | } |
||
| 4997 | |||
| 4998 | /** |
||
| 4999 | * Get the column info. This is basically the same as smf_db_list_columns but we get 1 column, force detail and other checks. |
||
| 5000 | * |
||
| 5001 | * @param string $targetTable The table to perform the operation on |
||
| 5002 | * @param string $column The column we are looking for. |
||
| 5003 | * |
||
| 5004 | * @return array Info on the table. |
||
| 5005 | */ |
||
| 5006 | function upgradeGetColumnInfo($targetTable, $column) |
||
| 5007 | { |
||
| 5008 | global $smcFunc; |
||
| 5009 | |||
| 5010 | // This should already be here, but be safe. |
||
| 5011 | db_extend('packages'); |
||
| 5012 | |||
| 5013 | $columns = $smcFunc['db_list_columns']($targetTable, true); |
||
| 5014 | |||
| 5015 | if (isset($columns[$column])) |
||
| 5016 | return $columns[$column]; |
||
| 5017 | else |
||
| 5018 | return null; |
||
| 5019 | } |
||
| 5020 | |||
| 5021 | /** |
||
| 5022 | * Takes the changes to be made during the upgradeOptions step, grabs all known Settings data from Settings.php, then runs |
||
| 5023 | * through a process to rebuild onto a brand new Settings template. This should only be done if detection believes the |
||
| 5024 | * settings file isn't using any advanced configuration setups in the Settings.php file. A copy is made as Settings_org.php |
||
| 5025 | * to preserve all changes prior to migration. |
||
| 5026 | * |
||
| 5027 | * @param array $config_vars An array of one or more variables to update |
||
| 5028 | * |
||
| 5029 | * @return void We either successfully update the Settings file, or throw a error here. |
||
| 5030 | */ |
||
| 5031 | function migrateSettingsFile($changes) |
||
| 5032 | { |
||
| 5033 | global $boarddir, $cachedir; |
||
| 5034 | |||
| 5035 | // Try to find all of these settings. |
||
| 5036 | $settingsVars = array( |
||
| 5037 | 'maintenance' => 'int', |
||
| 5038 | 'mtitle' => 'string', |
||
| 5039 | 'mmessage' => 'string', |
||
| 5040 | 'mbname' => 'string', |
||
| 5041 | 'language' => 'string', |
||
| 5042 | 'boardurl' => 'string', |
||
| 5043 | 'webmaster_email' => 'string', |
||
| 5044 | 'cookiename' => 'string', |
||
| 5045 | 'db_type' => 'string', |
||
| 5046 | 'db_port' => 'int', |
||
| 5047 | 'db_server' => 'string_fatal', |
||
| 5048 | 'db_name' => 'string_fatal', |
||
| 5049 | 'db_user' => 'string_fatal', |
||
| 5050 | 'db_passwd' => 'string_fatal', |
||
| 5051 | 'ssi_db_user' => 'string', |
||
| 5052 | 'ssi_db_passwd' => 'string', |
||
| 5053 | 'db_prefix' => 'string_fatal', |
||
| 5054 | 'db_persist' => 'int', |
||
| 5055 | 'db_error_send' => 'int', |
||
| 5056 | 'db_mb4' => 'null', |
||
| 5057 | 'cache_accelerator' => 'string', |
||
| 5058 | 'cache_enable' => 'int', |
||
| 5059 | 'cache_memcached' => 'string', |
||
| 5060 | 'cachedir' => 'string', |
||
| 5061 | 'image_proxy_enabled' => 'bool', |
||
| 5062 | 'image_proxy_secret' => 'string', |
||
| 5063 | 'image_proxy_maxsize' => 'int', |
||
| 5064 | 'boarddir' => 'string', |
||
| 5065 | 'sourcedir' => 'string', |
||
| 5066 | 'packagesdir' => 'string', |
||
| 5067 | 'tasksdir' => 'string', |
||
| 5068 | 'db_character_set' => 'string', |
||
| 5069 | ); |
||
| 5070 | |||
| 5071 | // The Settings file, in an array as if it was handled by updateSettingsFile |
||
| 5072 | $settingsArray = array( |
||
| 5073 | '<' . '?' . 'php', |
||
| 5074 | '', |
||
| 5075 | '/**', |
||
| 5076 | ' * The settings file contains all of the basic settings that need to be present when a database/cache is not available.', |
||
| 5077 | ' *', |
||
| 5078 | ' * Simple Machines Forum (SMF)', |
||
| 5079 | ' *', |
||
| 5080 | ' * @package SMF', |
||
| 5081 | ' * @author Simple Machines http://www.simplemachines.org', |
||
| 5082 | ' * @copyright ' . SMF_SOFTWARE_YEAR . ' Simple Machines and individual contributors', |
||
| 5083 | ' * @license http://www.simplemachines.org/about/smf/license.php BSD', |
||
| 5084 | ' *', |
||
| 5085 | ' * @version ' . SMF_VERSION, |
||
| 5086 | ' */', |
||
| 5087 | '', |
||
| 5088 | '########## Maintenance ##########', |
||
| 5089 | '/**', |
||
| 5090 | ' * The maintenance "mode"', |
||
| 5091 | ' * Set to 1 to enable Maintenance Mode, 2 to make the forum untouchable. (you\'ll have to make it 0 again manually!)', |
||
| 5092 | ' * 0 is default and disables maintenance mode.', |
||
| 5093 | ' * @var int 0, 1, 2', |
||
| 5094 | ' * @global int $maintenance', |
||
| 5095 | ' */', |
||
| 5096 | '$maintenance = 0;', |
||
| 5097 | '/**', |
||
| 5098 | ' * Title for the Maintenance Mode message.', |
||
| 5099 | ' * @var string', |
||
| 5100 | ' * @global int $mtitle', |
||
| 5101 | ' */', |
||
| 5102 | '$mtitle = \'Maintenance Mode\';', |
||
| 5103 | '/**', |
||
| 5104 | ' * Description of why the forum is in maintenance mode.', |
||
| 5105 | ' * @var string', |
||
| 5106 | ' * @global string $mmessage', |
||
| 5107 | ' */', |
||
| 5108 | '$mmessage = \'Okay faithful users...we\\\'re attempting to restore an older backup of the database...news will be posted once we\\\'re back!\';', |
||
| 5109 | '', |
||
| 5110 | '########## Forum Info ##########', |
||
| 5111 | '/**', |
||
| 5112 | ' * The name of your forum.', |
||
| 5113 | ' * @var string', |
||
| 5114 | ' */', |
||
| 5115 | '$mbname = \'My Community\';', |
||
| 5116 | '/**', |
||
| 5117 | ' * The default language file set for the forum.', |
||
| 5118 | ' * @var string', |
||
| 5119 | ' */', |
||
| 5120 | '$language = \'english\';', |
||
| 5121 | '/**', |
||
| 5122 | ' * URL to your forum\'s folder. (without the trailing /!)', |
||
| 5123 | ' * @var string', |
||
| 5124 | ' */', |
||
| 5125 | '$boardurl = \'http://127.0.0.1/smf\';', |
||
| 5126 | '/**', |
||
| 5127 | ' * Email address to send emails from. (like [email protected].)', |
||
| 5128 | ' * @var string', |
||
| 5129 | ' */', |
||
| 5130 | '$webmaster_email = \'[email protected]\';', |
||
| 5131 | '/**', |
||
| 5132 | ' * Name of the cookie to set for authentication.', |
||
| 5133 | ' * @var string', |
||
| 5134 | ' */', |
||
| 5135 | '$cookiename = \'SMFCookie21\';', |
||
| 5136 | '', |
||
| 5137 | '########## Database Info ##########', |
||
| 5138 | '/**', |
||
| 5139 | ' * The database type', |
||
| 5140 | ' * Default options: mysql, postgresql', |
||
| 5141 | ' * @var string', |
||
| 5142 | ' */', |
||
| 5143 | '$db_type = \'mysql\';', |
||
| 5144 | '/**', |
||
| 5145 | ' * The database port', |
||
| 5146 | ' * Default options: 3306 for mysql, 5432 for postgresql', |
||
| 5147 | ' * @var int', |
||
| 5148 | ' */', |
||
| 5149 | '$db_port = 3306;', |
||
| 5150 | '/**', |
||
| 5151 | ' * The server to connect to (or a Unix socket)', |
||
| 5152 | ' * @var string', |
||
| 5153 | ' */', |
||
| 5154 | '$db_server = \'localhost\';', |
||
| 5155 | '/**', |
||
| 5156 | ' * The database name', |
||
| 5157 | ' * @var string', |
||
| 5158 | ' */', |
||
| 5159 | '$db_name = \'smf\';', |
||
| 5160 | '/**', |
||
| 5161 | ' * Database username', |
||
| 5162 | ' * @var string', |
||
| 5163 | ' */', |
||
| 5164 | '$db_user = \'root\';', |
||
| 5165 | '/**', |
||
| 5166 | ' * Database password', |
||
| 5167 | ' * @var string', |
||
| 5168 | ' */', |
||
| 5169 | '$db_passwd = \'\';', |
||
| 5170 | '/**', |
||
| 5171 | ' * Database user for when connecting with SSI', |
||
| 5172 | ' * @var string', |
||
| 5173 | ' */', |
||
| 5174 | '$ssi_db_user = \'\';', |
||
| 5175 | '/**', |
||
| 5176 | ' * Database password for when connecting with SSI', |
||
| 5177 | ' * @var string', |
||
| 5178 | ' */', |
||
| 5179 | '$ssi_db_passwd = \'\';', |
||
| 5180 | '/**', |
||
| 5181 | ' * A prefix to put in front of your table names.', |
||
| 5182 | ' * This helps to prevent conflicts', |
||
| 5183 | ' * @var string', |
||
| 5184 | ' */', |
||
| 5185 | '$db_prefix = \'smf_\';', |
||
| 5186 | '/**', |
||
| 5187 | ' * Use a persistent database connection', |
||
| 5188 | ' * @var int|bool', |
||
| 5189 | ' */', |
||
| 5190 | '$db_persist = 0;', |
||
| 5191 | '/**', |
||
| 5192 | ' *', |
||
| 5193 | ' * @var int|bool', |
||
| 5194 | ' */', |
||
| 5195 | '$db_error_send = 0;', |
||
| 5196 | '/**', |
||
| 5197 | ' * Override the default behavior of the database layer for mb4 handling', |
||
| 5198 | ' * null keep the default behavior untouched', |
||
| 5199 | ' * @var null|bool', |
||
| 5200 | ' */', |
||
| 5201 | '$db_mb4 = null;', |
||
| 5202 | '', |
||
| 5203 | '########## Cache Info ##########', |
||
| 5204 | '/**', |
||
| 5205 | ' * Select a cache system. You want to leave this up to the cache area of the admin panel for', |
||
| 5206 | ' * proper detection of apc, memcached, output_cache, smf, or xcache', |
||
| 5207 | ' * (you can add more with a mod).', |
||
| 5208 | ' * @var string', |
||
| 5209 | ' */', |
||
| 5210 | '$cache_accelerator = \'\';', |
||
| 5211 | '/**', |
||
| 5212 | ' * The level at which you would like to cache. Between 0 (off) through 3 (cache a lot).', |
||
| 5213 | ' * @var int', |
||
| 5214 | ' */', |
||
| 5215 | '$cache_enable = 0;', |
||
| 5216 | '/**', |
||
| 5217 | ' * This is only used for memcache / memcached. Should be a string of \'server:port,server:port\'', |
||
| 5218 | ' * @var array', |
||
| 5219 | ' */', |
||
| 5220 | '$cache_memcached = \'\';', |
||
| 5221 | '/**', |
||
| 5222 | ' * This is only for the \'smf\' file cache system. It is the path to the cache directory.', |
||
| 5223 | ' * It is also recommended that you place this in /tmp/ if you are going to use this.', |
||
| 5224 | ' * @var string', |
||
| 5225 | ' */', |
||
| 5226 | '$cachedir = dirname(__FILE__) . \'/cache\';', |
||
| 5227 | '', |
||
| 5228 | '########## Image Proxy ##########', |
||
| 5229 | '# This is done entirely in Settings.php to avoid loading the DB while serving the images', |
||
| 5230 | '/**', |
||
| 5231 | ' * Whether the proxy is enabled or not', |
||
| 5232 | ' * @var bool', |
||
| 5233 | ' */', |
||
| 5234 | '$image_proxy_enabled = true;', |
||
| 5235 | '', |
||
| 5236 | '/**', |
||
| 5237 | ' * Secret key to be used by the proxy', |
||
| 5238 | ' * @var string', |
||
| 5239 | ' */', |
||
| 5240 | '$image_proxy_secret = \'smfisawesome\';', |
||
| 5241 | '', |
||
| 5242 | '/**', |
||
| 5243 | ' * Maximum file size (in KB) for individual files', |
||
| 5244 | ' * @var int', |
||
| 5245 | ' */', |
||
| 5246 | '$image_proxy_maxsize = 5192;', |
||
| 5247 | '', |
||
| 5248 | '########## Directories/Files ##########', |
||
| 5249 | '# Note: These directories do not have to be changed unless you move things.', |
||
| 5250 | '/**', |
||
| 5251 | ' * The absolute path to the forum\'s folder. (not just \'.\'!)', |
||
| 5252 | ' * @var string', |
||
| 5253 | ' */', |
||
| 5254 | '$boarddir = dirname(__FILE__);', |
||
| 5255 | '/**', |
||
| 5256 | ' * Path to the Sources directory.', |
||
| 5257 | ' * @var string', |
||
| 5258 | ' */', |
||
| 5259 | '$sourcedir = dirname(__FILE__) . \'/Sources\';', |
||
| 5260 | '/**', |
||
| 5261 | ' * Path to the Packages directory.', |
||
| 5262 | ' * @var string', |
||
| 5263 | ' */', |
||
| 5264 | '$packagesdir = dirname(__FILE__) . \'/Packages\';', |
||
| 5265 | '/**', |
||
| 5266 | ' * Path to the tasks directory.', |
||
| 5267 | ' * @var string', |
||
| 5268 | ' */', |
||
| 5269 | '$tasksdir = $sourcedir . \'/tasks\';', |
||
| 5270 | '', |
||
| 5271 | '# Make sure the paths are correct... at least try to fix them.', |
||
| 5272 | 'if (!file_exists($boarddir) && file_exists(dirname(__FILE__) . \'/agreement.txt\'))', |
||
| 5273 | ' $boarddir = dirname(__FILE__);', |
||
| 5274 | 'if (!file_exists($sourcedir) && file_exists($boarddir . \'/Sources\'))', |
||
| 5275 | ' $sourcedir = $boarddir . \'/Sources\';', |
||
| 5276 | 'if (!file_exists($cachedir) && file_exists($boarddir . \'/cache\'))', |
||
| 5277 | ' $cachedir = $boarddir . \'/cache\';', |
||
| 5278 | '', |
||
| 5279 | '######### Legacy Settings #########', |
||
| 5280 | '# UTF-8 is now the only character set supported in 2.1.', |
||
| 5281 | '$db_character_set = \'utf8\';', |
||
| 5282 | '', |
||
| 5283 | '########## Error-Catching ##########', |
||
| 5284 | '# Note: You shouldn\'t touch these settings.', |
||
| 5285 | 'if (file_exists((isset($cachedir) ? $cachedir : dirname(__FILE__)) . \'/db_last_error.php\'))', |
||
| 5286 | ' include((isset($cachedir) ? $cachedir : dirname(__FILE__)) . \'/db_last_error.php\');', |
||
| 5287 | '', |
||
| 5288 | 'if (!isset($db_last_error))', |
||
| 5289 | '{', |
||
| 5290 | ' // File does not exist so lets try to create it', |
||
| 5291 | ' file_put_contents((isset($cachedir) ? $cachedir : dirname(__FILE__)) . \'/db_last_error.php\', \'<\' . \'?\' . "php\n" . \'$db_last_error = 0;\' . "\n" . \'?\' . \'>\');', |
||
| 5292 | ' $db_last_error = 0;', |
||
| 5293 | '}', |
||
| 5294 | '', |
||
| 5295 | '?' . '>', |
||
| 5296 | ); |
||
| 5297 | |||
| 5298 | // Now, find all of the original settings. Mark those for the "change". |
||
| 5299 | $original = array(); |
||
| 5300 | foreach ($settingsVars as $setVar => $setType) |
||
| 5301 | { |
||
| 5302 | global $$setVar; |
||
| 5303 | |||
| 5304 | // Find the setting. |
||
| 5305 | if ($setType == 'string' || $setType == 'string_fatal') |
||
| 5306 | $original[$setVar] = isset($$setVar) ? '\'' . addslashes($)addcslashes($$setVar, '\'\\') . '\'' : (strpos('fatal', $setType) ? null : '\'\''); |
||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
| 5307 | elseif ($setType == 'int' || $setType == 'int_fatal') |
||
| 5308 | $original[$setVar] = isset($$setVar) ? (int) $$setVar : (strpos('fatal', $setType) ? null : 0); |
||
| 5309 | elseif ($setType == 'bool' || $setType == 'bool_fatal') |
||
| 5310 | $original[$setVar] = isset($$setVar) && in_array($$setVar, array(1, true)) ? 'true' : (strpos('fatal', $setType) ? null : 'false'); |
||
| 5311 | elseif ($setType == 'null' || $setType == 'null_fatal') |
||
| 5312 | $original[$setVar] = isset($$setVar) && in_array($$setVar, array(1, true)) ? 'true' : (strpos('fatal', $setType) ? null : 'null'); |
||
| 5313 | |||
| 5314 | // Well this isn't good. Do we fix it or bail? |
||
| 5315 | if (is_null($original) && $setType != 'null' && strpos('fatal', $setType) > -1) |
||
| 5316 | return throw_error(sprintf($txt['error_settings_migration_no_var'], $setVar)); |
||
| 5317 | } |
||
| 5318 | |||
| 5319 | // Finally, merge the changes with the new ones. |
||
| 5320 | $config_vars = $original; |
||
| 5321 | foreach ($changes as $setVar => $value) |
||
| 5322 | { |
||
| 5323 | // Nothing needed here. |
||
| 5324 | if ($setVar != 'upgradeData' && $config_vars[$setVar] == $changes[$setVar]) |
||
| 5325 | continue; |
||
| 5326 | |||
| 5327 | $config_vars[$setVar] = $value; |
||
| 5328 | } |
||
| 5329 | |||
| 5330 | /* |
||
| 5331 | It would be nice to call updateSettingsFile and be done with this. However the function doesn't support passing in the entire file. We also want to backup with a different name, just incase. |
||
| 5332 | */ |
||
| 5333 | |||
| 5334 | // When was Settings.php last changed? |
||
| 5335 | $last_settings_change = filemtime($boarddir . '/Settings.php'); |
||
| 5336 | |||
| 5337 | // remove any \r's that made their way in here |
||
| 5338 | foreach ($settingsArray as $k => $dummy) |
||
| 5339 | $settingsArray[$k] = strtr($dummy, array("\r" => '')) . "\n"; |
||
| 5340 | |||
| 5341 | // go line by line and see whats changing |
||
| 5342 | for ($i = 0, $n = count($settingsArray); $i < $n; $i++) |
||
| 5343 | { |
||
| 5344 | // Don't trim or bother with it if it's not a variable. |
||
| 5345 | if (substr($settingsArray[$i], 0, 1) != '$') |
||
| 5346 | continue; |
||
| 5347 | |||
| 5348 | $settingsArray[$i] = trim($settingsArray[$i]) . "\n"; |
||
| 5349 | |||
| 5350 | // Look through the variables to set.... |
||
| 5351 | foreach ($config_vars as $var => $val) |
||
| 5352 | { |
||
| 5353 | // be sure someone is not updating db_last_error this with a group |
||
| 5354 | if ($var === 'db_last_error') |
||
| 5355 | unset($config_vars[$var]); |
||
| 5356 | elseif (strncasecmp($settingsArray[$i], '$' . $var, 1 + strlen($var)) == 0) |
||
| 5357 | { |
||
| 5358 | $comment = strstr(substr($settingsArray[$i], strpos($settingsArray[$i], ';')), '#'); |
||
| 5359 | $settingsArray[$i] = '$' . $var . ' = ' . $val . ';' . ($comment == '' ? '' : "\t\t" . rtrim($comment)) . "\n"; |
||
| 5360 | |||
| 5361 | // This one's been 'used', so to speak. |
||
| 5362 | unset($config_vars[$var]); |
||
| 5363 | } |
||
| 5364 | } |
||
| 5365 | |||
| 5366 | // End of the file ... maybe |
||
| 5367 | if (substr(trim($settingsArray[$i]), 0, 2) == '?' . '>') |
||
| 5368 | $end = $i; |
||
| 5369 | } |
||
| 5370 | |||
| 5371 | // This should never happen, but apparently it is happening. |
||
| 5372 | if (empty($end) || $end < 10) |
||
| 5373 | $end = count($settingsArray) - 1; |
||
| 5374 | |||
| 5375 | // Still more variables to go? Then lets add them at the end. |
||
| 5376 | if (!empty($config_vars)) |
||
| 5377 | { |
||
| 5378 | if (trim($settingsArray[$end]) == '?' . '>') |
||
| 5379 | $settingsArray[$end++] = ''; |
||
| 5380 | else |
||
| 5381 | $end++; |
||
| 5382 | |||
| 5383 | // Add in any newly defined vars that were passed |
||
| 5384 | foreach ($config_vars as $var => $val) |
||
| 5385 | $settingsArray[$end++] = '$' . $var . ' = ' . $val . ';' . "\n"; |
||
| 5386 | |||
| 5387 | $settingsArray[$end] = '?' . '>'; |
||
| 5388 | } |
||
| 5389 | else |
||
| 5390 | $settingsArray[$end] = trim($settingsArray[$end]); |
||
| 5391 | |||
| 5392 | // Sanity error checking: the file needs to be at least 12 lines. |
||
| 5393 | if (count($settingsArray) < 12) |
||
| 5394 | return throw_error($txt['error_settings_migration_too_short']); |
||
| 5395 | |||
| 5396 | // Try to avoid a few pitfalls: |
||
| 5397 | // - like a possible race condition, |
||
| 5398 | // - or a failure to write at low diskspace |
||
| 5399 | // |
||
| 5400 | // Check before you act: if cache is enabled, we can do a simple write test |
||
| 5401 | // to validate that we even write things on this filesystem. |
||
| 5402 | if ((empty($cachedir) || !file_exists($cachedir)) && file_exists($boarddir . '/cache')) |
||
| 5403 | $cachedir = $boarddir . '/cache'; |
||
| 5404 | |||
| 5405 | $test_fp = @fopen($cachedir . '/settings_update.tmp', "w+"); |
||
| 5406 | if ($test_fp) |
||
| 5407 | { |
||
| 5408 | fclose($test_fp); |
||
| 5409 | $written_bytes = file_put_contents($cachedir . '/settings_update.tmp', 'test', LOCK_EX); |
||
| 5410 | @unlink($cachedir . '/settings_update.tmp'); |
||
| 5411 | |||
| 5412 | // Oops. Low disk space, perhaps. Don't mess with Settings.php then. |
||
| 5413 | // No means no. :P |
||
| 5414 | if ($written_bytes !== 4) |
||
| 5415 | return throw_error($txt['error_settings_migration_write_failed']); |
||
| 5416 | } |
||
| 5417 | |||
| 5418 | // Protect me from what I want! :P |
||
| 5419 | clearstatcache(); |
||
| 5420 | if (filemtime($boarddir . '/Settings.php') === $last_settings_change) |
||
| 5421 | { |
||
| 5422 | // save the old before we do anything |
||
| 5423 | $settings_backup_fail = !@is_writable($boarddir . '/Settings_org.php') || !@copy($boarddir . '/Settings.php', $boarddir . '/Settings_org.php'); |
||
| 5424 | $settings_backup_fail = !$settings_backup_fail ? (!file_exists($boarddir . '/Settings_org.php') || filesize($boarddir . '/Settings_org.php') === 0) : $settings_backup_fail; |
||
| 5425 | |||
| 5426 | // write out the new |
||
| 5427 | $write_settings = implode('', $settingsArray); |
||
| 5428 | $written_bytes = file_put_contents($boarddir . '/Settings.php', $write_settings, LOCK_EX); |
||
| 5429 | |||
| 5430 | // survey says ... |
||
| 5431 | if ($written_bytes !== strlen($write_settings) && !$settings_backup_fail) |
||
| 5432 | { |
||
| 5433 | if (file_exists($boarddir . '/Settings_bak.php')) |
||
| 5434 | @copy($boarddir . '/Settings_bak.php', $boarddir . '/Settings.php'); |
||
| 5435 | |||
| 5436 | return throw_error($txt['error_settings_migration_general']); |
||
| 5437 | } |
||
| 5438 | } |
||
| 5439 | |||
| 5440 | // Even though on normal installations the filemtime should prevent this being used by the installer incorrectly |
||
| 5441 | // it seems that there are times it might not. So let's MAKE it dump the cache. |
||
| 5442 | if (function_exists('opcache_invalidate')) |
||
| 5443 | opcache_invalidate($boarddir . '/Settings.php', true); |
||
| 5444 | } |
||
| 5445 | |||
| 5446 | /** |
||
| 5447 | * Determine if we should auto select the migrate Settings file. This is determined by a variety of missing settings. |
||
| 5448 | * Prior to checking these settings, we look for advanced setups such as integrations or if variables have been moved |
||
| 5449 | * to another file. If these are detected, we abort. |
||
| 5450 | * |
||
| 5451 | * @param array $config_vars An array of one or more variables to update |
||
| 5452 | * |
||
| 5453 | * @return void We either successfully update the Settings file, or throw a error here. |
||
| 5454 | */ |
||
| 5455 | function detectSettingsFileMigrationNeeded() |
||
| 5456 | { |
||
| 5457 | global $boarddir, $packagesdir, $tasksdir, $db_server, $db_type, $image_proxy_enabled, $db_show_debug; |
||
| 5458 | |||
| 5459 | // We should not migrate if db_show_debug is in there, some dev stuff going on here. |
||
| 5460 | if (isset($db_show_debug)) |
||
| 5461 | return false; |
||
| 5462 | |||
| 5463 | $file_contents = file_get_contents($boarddir . '/Settings.php'); |
||
| 5464 | |||
| 5465 | // Is there a include statement somewhere in there? Some advanced handling of the variables elsewhere? |
||
| 5466 | // Try our best to stay away from the cachedir match. |
||
| 5467 | if (preg_match('~\sinclude\((?:(?!\(isset\(\$cachedir))~im', $file_contents)) |
||
| 5468 | return false; |
||
| 5469 | |||
| 5470 | // If we find a mention of $GLOBALS, there may be a integration going on. |
||
| 5471 | if (preg_match('~\$GLOBALS\[~im', $file_contents)) |
||
| 5472 | return false; |
||
| 5473 | |||
| 5474 | // If these are not set, it makes us a candidate to migrate. |
||
| 5475 | if (!isset($packagesdir, $tasksdir, $db_server, $db_type, $image_proxy_enabled)) |
||
| 5476 | return true; |
||
| 5477 | |||
| 5478 | return false; |
||
| 5479 | } |
||
| 5480 | |||
| 5481 | ?> |