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

/other/upgrade.php

https://github.com/smf-portal/SMF2.1
PHP | 4523 lines | 3515 code | 601 blank | 407 comment | 730 complexity | 3fea4611b32c8325cd60afa9439758d6 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * Simple Machines Forum (SMF)
  4. *
  5. * @package SMF
  6. * @author Simple Machines http://www.simplemachines.org
  7. * @copyright 2012 Simple Machines
  8. * @license http://www.simplemachines.org/about/smf/license.php BSD
  9. *
  10. * @version 2.1 Alpha 1
  11. */
  12. // Version information...
  13. define('SMF_VERSION', '2.1 Alpha 1');
  14. define('SMF_LANG_VERSION', '2.1');
  15. $GLOBALS['required_php_version'] = '5.1.0';
  16. $GLOBALS['required_mysql_version'] = '4.0.18';
  17. $databases = array(
  18. 'mysql' => array(
  19. 'name' => 'MySQL',
  20. 'version' => '4.0.18',
  21. 'version_check' => 'return min(mysql_get_server_info(), mysql_get_client_info());',
  22. 'utf8_support' => true,
  23. 'utf8_version' => '4.1.0',
  24. 'utf8_version_check' => 'return mysql_get_server_info();',
  25. 'alter_support' => true,
  26. ),
  27. 'postgresql' => array(
  28. 'name' => 'PostgreSQL',
  29. 'version' => '8.0',
  30. 'version_check' => '$version = pg_version(); return $version[\'client\'];',
  31. 'always_has_db' => true,
  32. ),
  33. 'sqlite' => array(
  34. 'name' => 'SQLite',
  35. 'version' => '1',
  36. 'version_check' => 'return 1;',
  37. 'always_has_db' => true,
  38. ),
  39. );
  40. // General options for the script.
  41. $timeLimitThreshold = 3;
  42. $upgrade_path = dirname(__FILE__);
  43. $upgradeurl = $_SERVER['PHP_SELF'];
  44. // Where the SMF images etc are kept.
  45. $smfsite = 'http://www.simplemachines.org/smf';
  46. // Disable the need for admins to login?
  47. $disable_security = false;
  48. // How long, in seconds, must admin be inactive to allow someone else to run?
  49. $upcontext['inactive_timeout'] = 10;
  50. // All the steps in detail.
  51. // Number,Name,Function,Progress Weight.
  52. $upcontext['steps'] = array(
  53. 0 => array(1, 'Login', 'WelcomeLogin', 2),
  54. 1 => array(2, 'Upgrade Options', 'UpgradeOptions', 2),
  55. 2 => array(3, 'Backup', 'BackupDatabase', 10),
  56. 3 => array(4, 'Database Changes', 'DatabaseChanges', 70),
  57. // This is removed as it doesn't really work right at the moment.
  58. //4 => array(5, 'Cleanup Mods', 'CleanupMods', 10),
  59. 4 => array(5, 'Delete Upgrade', 'DeleteUpgrade', 1),
  60. );
  61. // Just to remember which one has files in it.
  62. $upcontext['database_step'] = 3;
  63. @set_time_limit(600);
  64. if (!ini_get('safe_mode'))
  65. {
  66. ini_set('mysql.connect_timeout', -1);
  67. ini_set('default_socket_timeout', 900);
  68. }
  69. // Clean the upgrade path if this is from the client.
  70. if (!empty($_SERVER['argv']) && php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR']))
  71. for ($i = 1; $i < $_SERVER['argc']; $i++)
  72. {
  73. if (preg_match('~^--path=(.+)$~', $_SERVER['argv'][$i], $match) != 0)
  74. $upgrade_path = substr($match[1], -1) == '/' ? substr($match[1], 0, -1) : $match[1];
  75. }
  76. // Are we from the client?
  77. if (php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR']))
  78. {
  79. $command_line = true;
  80. $disable_security = 1;
  81. }
  82. else
  83. $command_line = false;
  84. // Load this now just because we can.
  85. require_once($upgrade_path . '/Settings.php');
  86. // Are we logged in?
  87. if (isset($upgradeData))
  88. {
  89. $upcontext['user'] = unserialize(base64_decode($upgradeData));
  90. // Check for sensible values.
  91. if (empty($upcontext['user']['started']) || $upcontext['user']['started'] < time() - 86400)
  92. $upcontext['user']['started'] = time();
  93. if (empty($upcontext['user']['updated']) || $upcontext['user']['updated'] < time() - 86400)
  94. $upcontext['user']['updated'] = 0;
  95. $upcontext['started'] = $upcontext['user']['started'];
  96. $upcontext['updated'] = $upcontext['user']['updated'];
  97. }
  98. // Nothing sensible?
  99. if (empty($upcontext['updated']))
  100. {
  101. $upcontext['started'] = time();
  102. $upcontext['updated'] = 0;
  103. $upcontext['user'] = array(
  104. 'id' => 0,
  105. 'name' => 'Guest',
  106. 'pass' => 0,
  107. 'started' => $upcontext['started'],
  108. 'updated' => $upcontext['updated'],
  109. );
  110. }
  111. // Load up some essential data...
  112. loadEssentialData();
  113. // Are we going to be mimic'ing SSI at this point?
  114. if (isset($_GET['ssi']))
  115. {
  116. require_once($sourcedir . '/Subs.php');
  117. require_once($sourcedir . '/Errors.php');
  118. require_once($sourcedir . '/Logging.php');
  119. require_once($sourcedir . '/Load.php');
  120. require_once($sourcedir . '/Security.php');
  121. require_once($sourcedir . '/Subs-Package.php');
  122. loadUserSettings();
  123. loadPermissions();
  124. }
  125. // All the non-SSI stuff.
  126. if (!function_exists('ip2range'))
  127. require_once($sourcedir . '/Subs.php');
  128. if (!function_exists('un_htmlspecialchars'))
  129. {
  130. function un_htmlspecialchars($string)
  131. {
  132. return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES)) + array('&#039;' => '\'', '&nbsp;' => ' '));
  133. }
  134. }
  135. if (!function_exists('text2words'))
  136. {
  137. function text2words($text)
  138. {
  139. global $smcFunc;
  140. // Step 1: Remove entities/things we don't consider words:
  141. $words = preg_replace('~(?:[\x0B\0\xA0\t\r\s\n(){}\\[\\]<>!@$%^*.,:+=`\~\?/\\\\]+|&(?:amp|lt|gt|quot);)+~', ' ', $text);
  142. // Step 2: Entities we left to letters, where applicable, lowercase.
  143. $words = preg_replace('~([^&\d]|^)[#;]~', '$1 ', un_htmlspecialchars(strtolower($words)));
  144. // Step 3: Ready to split apart and index!
  145. $words = explode(' ', $words);
  146. $returned_words = array();
  147. foreach ($words as $word)
  148. {
  149. $word = trim($word, '-_\'');
  150. if ($word != '')
  151. $returned_words[] = substr($word, 0, 20);
  152. }
  153. return array_unique($returned_words);
  154. }
  155. }
  156. if (!function_exists('clean_cache'))
  157. {
  158. // Empty out the cache folder.
  159. function clean_cache($type = '')
  160. {
  161. global $cachedir, $sourcedir;
  162. // No directory = no game.
  163. if (!is_dir($cachedir))
  164. return;
  165. // Remove the files in SMF's own disk cache, if any
  166. $dh = opendir($cachedir);
  167. while ($file = readdir($dh))
  168. {
  169. if ($file != '.' && $file != '..' && $file != 'index.php' && $file != '.htaccess' && (!$type || substr($file, 0, strlen($type)) == $type))
  170. @unlink($cachedir . '/' . $file);
  171. }
  172. closedir($dh);
  173. // Invalidate cache, to be sure!
  174. // ... as long as Load.php can be modified, anyway.
  175. @touch($sourcedir . '/' . 'Load.php');
  176. clearstatcache();
  177. }
  178. }
  179. // MD5 Encryption.
  180. if (!function_exists('md5_hmac'))
  181. {
  182. function md5_hmac($data, $key)
  183. {
  184. if (strlen($key) > 64)
  185. $key = pack('H*', md5($key));
  186. $key = str_pad($key, 64, chr(0x00));
  187. $k_ipad = $key ^ str_repeat(chr(0x36), 64);
  188. $k_opad = $key ^ str_repeat(chr(0x5c), 64);
  189. return md5($k_opad . pack('H*', md5($k_ipad . $data)));
  190. }
  191. }
  192. // http://www.faqs.org/rfcs/rfc959.html
  193. if (!class_exists('ftp_connection'))
  194. {
  195. class ftp_connection
  196. {
  197. var $connection = 'no_connection', $error = false, $last_message, $pasv = array();
  198. // Create a new FTP connection...
  199. function ftp_connection($ftp_server, $ftp_port = 21, $ftp_user = 'anonymous', $ftp_pass = 'ftpclient@simplemachines.org')
  200. {
  201. if ($ftp_server !== null)
  202. $this->connect($ftp_server, $ftp_port, $ftp_user, $ftp_pass);
  203. }
  204. function connect($ftp_server, $ftp_port = 21, $ftp_user = 'anonymous', $ftp_pass = 'ftpclient@simplemachines.org')
  205. {
  206. if (substr($ftp_server, 0, 6) == 'ftp://')
  207. $ftp_server = substr($ftp_server, 6);
  208. elseif (substr($ftp_server, 0, 7) == 'ftps://')
  209. $ftp_server = 'ssl://' . substr($ftp_server, 7);
  210. if (substr($ftp_server, 0, 7) == 'http://')
  211. $ftp_server = substr($ftp_server, 7);
  212. $ftp_server = strtr($ftp_server, array('/' => '', ':' => '', '@' => ''));
  213. // Connect to the FTP server.
  214. $this->connection = @fsockopen($ftp_server, $ftp_port, $err, $err, 5);
  215. if (!$this->connection)
  216. {
  217. $this->error = 'bad_server';
  218. return;
  219. }
  220. // Get the welcome message...
  221. if (!$this->check_response(220))
  222. {
  223. $this->error = 'bad_response';
  224. return;
  225. }
  226. // Send the username, it should ask for a password.
  227. fwrite($this->connection, 'USER ' . $ftp_user . "\r\n");
  228. if (!$this->check_response(331))
  229. {
  230. $this->error = 'bad_username';
  231. return;
  232. }
  233. // Now send the password... and hope it goes okay.
  234. fwrite($this->connection, 'PASS ' . $ftp_pass . "\r\n");
  235. if (!$this->check_response(230))
  236. {
  237. $this->error = 'bad_password';
  238. return;
  239. }
  240. }
  241. function chdir($ftp_path)
  242. {
  243. if (!is_resource($this->connection))
  244. return false;
  245. // No slash on the end, please...
  246. if (substr($ftp_path, -1) == '/' && $ftp_path !== '/')
  247. $ftp_path = substr($ftp_path, 0, -1);
  248. fwrite($this->connection, 'CWD ' . $ftp_path . "\r\n");
  249. if (!$this->check_response(250))
  250. {
  251. $this->error = 'bad_path';
  252. return false;
  253. }
  254. return true;
  255. }
  256. function chmod($ftp_file, $chmod)
  257. {
  258. if (!is_resource($this->connection))
  259. return false;
  260. // Convert the chmod value from octal (0777) to text ("777").
  261. fwrite($this->connection, 'SITE CHMOD ' . decoct($chmod) . ' ' . $ftp_file . "\r\n");
  262. if (!$this->check_response(200))
  263. {
  264. $this->error = 'bad_file';
  265. return false;
  266. }
  267. return true;
  268. }
  269. function unlink($ftp_file)
  270. {
  271. // We are actually connected, right?
  272. if (!is_resource($this->connection))
  273. return false;
  274. // Delete file X.
  275. fwrite($this->connection, 'DELE ' . $ftp_file . "\r\n");
  276. if (!$this->check_response(250))
  277. {
  278. fwrite($this->connection, 'RMD ' . $ftp_file . "\r\n");
  279. // Still no love?
  280. if (!$this->check_response(250))
  281. {
  282. $this->error = 'bad_file';
  283. return false;
  284. }
  285. }
  286. return true;
  287. }
  288. function check_response($desired)
  289. {
  290. // Wait for a response that isn't continued with -, but don't wait too long.
  291. $time = time();
  292. do
  293. $this->last_message = fgets($this->connection, 1024);
  294. while (substr($this->last_message, 3, 1) != ' ' && time() - $time < 5);
  295. // Was the desired response returned?
  296. return is_array($desired) ? in_array(substr($this->last_message, 0, 3), $desired) : substr($this->last_message, 0, 3) == $desired;
  297. }
  298. function passive()
  299. {
  300. // We can't create a passive data connection without a primary one first being there.
  301. if (!is_resource($this->connection))
  302. return false;
  303. // Request a passive connection - this means, we'll talk to you, you don't talk to us.
  304. @fwrite($this->connection, 'PASV' . "\r\n");
  305. $time = time();
  306. do
  307. $response = fgets($this->connection, 1024);
  308. while (substr($response, 3, 1) != ' ' && time() - $time < 5);
  309. // If it's not 227, we weren't given an IP and port, which means it failed.
  310. if (substr($response, 0, 4) != '227 ')
  311. {
  312. $this->error = 'bad_response';
  313. return false;
  314. }
  315. // Snatch the IP and port information, or die horribly trying...
  316. if (preg_match('~\((\d+),\s*(\d+),\s*(\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+))\)~', $response, $match) == 0)
  317. {
  318. $this->error = 'bad_response';
  319. return false;
  320. }
  321. // This is pretty simple - store it for later use ;).
  322. $this->pasv = array('ip' => $match[1] . '.' . $match[2] . '.' . $match[3] . '.' . $match[4], 'port' => $match[5] * 256 + $match[6]);
  323. return true;
  324. }
  325. function create_file($ftp_file)
  326. {
  327. // First, we have to be connected... very important.
  328. if (!is_resource($this->connection))
  329. return false;
  330. // I'd like one passive mode, please!
  331. if (!$this->passive())
  332. return false;
  333. // Seems logical enough, so far...
  334. fwrite($this->connection, 'STOR ' . $ftp_file . "\r\n");
  335. // Okay, now we connect to the data port. If it doesn't work out, it's probably "file already exists", etc.
  336. $fp = @fsockopen($this->pasv['ip'], $this->pasv['port'], $err, $err, 5);
  337. if (!$fp || !$this->check_response(150))
  338. {
  339. $this->error = 'bad_file';
  340. @fclose($fp);
  341. return false;
  342. }
  343. // This may look strange, but we're just closing it to indicate a zero-byte upload.
  344. fclose($fp);
  345. if (!$this->check_response(226))
  346. {
  347. $this->error = 'bad_response';
  348. return false;
  349. }
  350. return true;
  351. }
  352. function list_dir($ftp_path = '', $search = false)
  353. {
  354. // Are we even connected...?
  355. if (!is_resource($this->connection))
  356. return false;
  357. // Passive... non-agressive...
  358. if (!$this->passive())
  359. return false;
  360. // Get the listing!
  361. fwrite($this->connection, 'LIST -1' . ($search ? 'R' : '') . ($ftp_path == '' ? '' : ' ' . $ftp_path) . "\r\n");
  362. // Connect, assuming we've got a connection.
  363. $fp = @fsockopen($this->pasv['ip'], $this->pasv['port'], $err, $err, 5);
  364. if (!$fp || !$this->check_response(array(150, 125)))
  365. {
  366. $this->error = 'bad_response';
  367. @fclose($fp);
  368. return false;
  369. }
  370. // Read in the file listing.
  371. $data = '';
  372. while (!feof($fp))
  373. $data .= fread($fp, 4096);
  374. fclose($fp);
  375. // Everything go okay?
  376. if (!$this->check_response(226))
  377. {
  378. $this->error = 'bad_response';
  379. return false;
  380. }
  381. return $data;
  382. }
  383. function locate($file, $listing = null)
  384. {
  385. if ($listing === null)
  386. $listing = $this->list_dir('', true);
  387. $listing = explode("\n", $listing);
  388. @fwrite($this->connection, 'PWD' . "\r\n");
  389. $time = time();
  390. do
  391. $response = fgets($this->connection, 1024);
  392. while (substr($response, 3, 1) != ' ' && time() - $time < 5);
  393. // Check for 257!
  394. if (preg_match('~^257 "(.+?)" ~', $response, $match) != 0)
  395. $current_dir = strtr($match[1], array('""' => '"'));
  396. else
  397. $current_dir = '';
  398. for ($i = 0, $n = count($listing); $i < $n; $i++)
  399. {
  400. if (trim($listing[$i]) == '' && isset($listing[$i + 1]))
  401. {
  402. $current_dir = substr(trim($listing[++$i]), 0, -1);
  403. $i++;
  404. }
  405. // Okay, this file's name is:
  406. $listing[$i] = $current_dir . '/' . trim(strlen($listing[$i]) > 30 ? strrchr($listing[$i], ' ') : $listing[$i]);
  407. if (substr($file, 0, 1) == '*' && substr($listing[$i], -(strlen($file) - 1)) == substr($file, 1))
  408. return $listing[$i];
  409. if (substr($file, -1) == '*' && substr($listing[$i], 0, strlen($file) - 1) == substr($file, 0, -1))
  410. return $listing[$i];
  411. if (basename($listing[$i]) == $file || $listing[$i] == $file)
  412. return $listing[$i];
  413. }
  414. return false;
  415. }
  416. function create_dir($ftp_dir)
  417. {
  418. // We must be connected to the server to do something.
  419. if (!is_resource($this->connection))
  420. return false;
  421. // Make this new beautiful directory!
  422. fwrite($this->connection, 'MKD ' . $ftp_dir . "\r\n");
  423. if (!$this->check_response(257))
  424. {
  425. $this->error = 'bad_file';
  426. return false;
  427. }
  428. return true;
  429. }
  430. function detect_path($filesystem_path, $lookup_file = null)
  431. {
  432. $username = '';
  433. if (isset($_SERVER['DOCUMENT_ROOT']))
  434. {
  435. if (preg_match('~^/home[2]?/([^/]+?)/public_html~', $_SERVER['DOCUMENT_ROOT'], $match))
  436. {
  437. $username = $match[1];
  438. $path = strtr($_SERVER['DOCUMENT_ROOT'], array('/home/' . $match[1] . '/' => '', '/home2/' . $match[1] . '/' => ''));
  439. if (substr($path, -1) == '/')
  440. $path = substr($path, 0, -1);
  441. if (strlen(dirname($_SERVER['PHP_SELF'])) > 1)
  442. $path .= dirname($_SERVER['PHP_SELF']);
  443. }
  444. elseif (substr($filesystem_path, 0, 9) == '/var/www/')
  445. $path = substr($filesystem_path, 8);
  446. else
  447. $path = strtr(strtr($filesystem_path, array('\\' => '/')), array($_SERVER['DOCUMENT_ROOT'] => ''));
  448. }
  449. else
  450. $path = '';
  451. if (is_resource($this->connection) && $this->list_dir($path) == '')
  452. {
  453. $data = $this->list_dir('', true);
  454. if ($lookup_file === null)
  455. $lookup_file = $_SERVER['PHP_SELF'];
  456. $found_path = dirname($this->locate('*' . basename(dirname($lookup_file)) . '/' . basename($lookup_file), $data));
  457. if ($found_path == false)
  458. $found_path = dirname($this->locate(basename($lookup_file)));
  459. if ($found_path != false)
  460. $path = $found_path;
  461. }
  462. elseif (is_resource($this->connection))
  463. $found_path = true;
  464. return array($username, $path, isset($found_path));
  465. }
  466. function close()
  467. {
  468. // Goodbye!
  469. fwrite($this->connection, 'QUIT' . "\r\n");
  470. fclose($this->connection);
  471. return true;
  472. }
  473. }
  474. }
  475. // Have we got tracking data - if so use it (It will be clean!)
  476. if (isset($_GET['data']))
  477. {
  478. $upcontext['upgrade_status'] = unserialize(base64_decode($_GET['data']));
  479. $upcontext['current_step'] = $upcontext['upgrade_status']['curstep'];
  480. $upcontext['language'] = $upcontext['upgrade_status']['lang'];
  481. $upcontext['rid'] = $upcontext['upgrade_status']['rid'];
  482. $is_debug = $upcontext['upgrade_status']['debug'];
  483. $support_js = $upcontext['upgrade_status']['js'];
  484. // Load the language.
  485. if (file_exists($boarddir . '/Themes/default/languages/Install.' . $upcontext['language'] . '.php'))
  486. require_once($boarddir . '/Themes/default/languages/Install.' . $upcontext['language'] . '.php');
  487. }
  488. // Set the defaults.
  489. else
  490. {
  491. $upcontext['current_step'] = 0;
  492. $upcontext['rid'] = mt_rand(0, 5000);
  493. $upcontext['upgrade_status'] = array(
  494. 'curstep' => 0,
  495. 'lang' => isset($_GET['lang']) ? $_GET['lang'] : basename($language, '.lng'),
  496. 'rid' => $upcontext['rid'],
  497. 'pass' => 0,
  498. 'debug' => 0,
  499. 'js' => 0,
  500. );
  501. $upcontext['language'] = $upcontext['upgrade_status']['lang'];
  502. }
  503. // Don't do security check if on Yabbse
  504. if (!isset($modSettings['smfVersion']))
  505. $disable_security = true;
  506. // If this isn't the first stage see whether they are logging in and resuming.
  507. if ($upcontext['current_step'] != 0 || !empty($upcontext['user']['step']))
  508. checkLogin();
  509. // This only exists if we're on SMF ;)
  510. if (isset($modSettings['smfVersion']))
  511. {
  512. $request = $smcFunc['db_query']('', '
  513. SELECT variable, value
  514. FROM {db_prefix}themes
  515. WHERE id_theme = {int:id_theme}
  516. AND variable IN ({string:theme_url}, {string:theme_dir}, {string:images_url})',
  517. array(
  518. 'id_theme' => 1,
  519. 'theme_url' => 'theme_url',
  520. 'theme_dir' => 'theme_dir',
  521. 'images_url' => 'images_url',
  522. 'db_error_skip' => true,
  523. )
  524. );
  525. while ($row = $smcFunc['db_fetch_assoc']($request))
  526. $modSettings[$row['variable']] = $row['value'];
  527. $smcFunc['db_free_result']($request);
  528. }
  529. if (!isset($modSettings['theme_url']))
  530. {
  531. $modSettings['theme_dir'] = $boarddir . '/Themes/default';
  532. $modSettings['theme_url'] = 'Themes/default';
  533. $modSettings['images_url'] = 'Themes/default/images';
  534. }
  535. if (!isset($settings['default_theme_url']))
  536. $settings['default_theme_url'] = $modSettings['theme_url'];
  537. if (!isset($settings['default_theme_dir']))
  538. $settings['default_theme_dir'] = $modSettings['theme_dir'];
  539. $upcontext['is_large_forum'] = (empty($modSettings['smfVersion']) || $modSettings['smfVersion'] <= '1.1 RC1') && !empty($modSettings['totalMessages']) && $modSettings['totalMessages'] > 75000;
  540. // Default title...
  541. $upcontext['page_title'] = isset($modSettings['smfVersion']) ? 'Updating Your SMF Install!' : 'Upgrading from YaBB SE!';
  542. $upcontext['right_to_left'] = isset($txt['lang_rtl']) ? $txt['lang_rtl'] : false;
  543. if ($command_line)
  544. cmdStep0();
  545. // Don't error if we're using xml.
  546. if (isset($_GET['xml']))
  547. $upcontext['return_error'] = true;
  548. // Loop through all the steps doing each one as required.
  549. $upcontext['overall_percent'] = 0;
  550. foreach ($upcontext['steps'] as $num => $step)
  551. {
  552. if ($num >= $upcontext['current_step'])
  553. {
  554. // The current weight of this step in terms of overall progress.
  555. $upcontext['step_weight'] = $step[3];
  556. // Make sure we reset the skip button.
  557. $upcontext['skip'] = false;
  558. // We cannot proceed if we're not logged in.
  559. if ($num != 0 && !$disable_security && $upcontext['user']['pass'] != $upcontext['upgrade_status']['pass'])
  560. {
  561. $upcontext['steps'][0][2]();
  562. break;
  563. }
  564. // Call the step and if it returns false that means pause!
  565. if (function_exists($step[2]) && $step[2]() === false)
  566. break;
  567. elseif (function_exists($step[2]))
  568. $upcontext['current_step']++;
  569. }
  570. $upcontext['overall_percent'] += $step[3];
  571. }
  572. upgradeExit();
  573. // Exit the upgrade script.
  574. function upgradeExit($fallThrough = false)
  575. {
  576. global $upcontext, $upgradeurl, $boarddir, $command_line;
  577. // Save where we are...
  578. if (!empty($upcontext['current_step']) && !empty($upcontext['user']['id']))
  579. {
  580. $upcontext['user']['step'] = $upcontext['current_step'];
  581. $upcontext['user']['substep'] = $_GET['substep'];
  582. $upcontext['user']['updated'] = time();
  583. $upgradeData = base64_encode(serialize($upcontext['user']));
  584. copy($boarddir . '/Settings.php', $boarddir . '/Settings_bak.php');
  585. changeSettings(array('upgradeData' => '"' . $upgradeData . '"'));
  586. updateLastError();
  587. }
  588. // Handle the progress of the step, if any.
  589. if (!empty($upcontext['step_progress']) && isset($upcontext['steps'][$upcontext['current_step']]))
  590. {
  591. $upcontext['step_progress'] = round($upcontext['step_progress'], 1);
  592. $upcontext['overall_percent'] += $upcontext['step_progress'] * ($upcontext['steps'][$upcontext['current_step']][3] / 100);
  593. }
  594. $upcontext['overall_percent'] = (int) $upcontext['overall_percent'];
  595. // We usually dump our templates out.
  596. if (!$fallThrough)
  597. {
  598. // This should not happen my dear... HELP ME DEVELOPERS!!
  599. if (!empty($command_line))
  600. {
  601. if (function_exists('debug_print_backtrace'))
  602. debug_print_backtrace();
  603. echo "\n" . 'Error: Unexpected call to use the ' . (isset($upcontext['sub_template']) ? $upcontext['sub_template'] : '') . ' template. Please copy and paste all the text above and visit the SMF support forum to tell the Developers that they\'ve made a boo boo; they\'ll get you up and running again.';
  604. flush();
  605. die();
  606. }
  607. if (!isset($_GET['xml']))
  608. template_upgrade_above();
  609. else
  610. {
  611. header('Content-Type: text/xml; charset=ISO-8859-1');
  612. // Sadly we need to retain the $_GET data thanks to the old upgrade scripts.
  613. $upcontext['get_data'] = array();
  614. foreach ($_GET as $k => $v)
  615. {
  616. if (substr($k, 0, 3) != 'amp' && !in_array($k, array('xml', 'substep', 'lang', 'data', 'step', 'filecount')))
  617. {
  618. $upcontext['get_data'][$k] = $v;
  619. }
  620. }
  621. template_xml_above();
  622. }
  623. // Call the template.
  624. if (isset($upcontext['sub_template']))
  625. {
  626. $upcontext['upgrade_status']['curstep'] = $upcontext['current_step'];
  627. $upcontext['form_url'] = $upgradeurl . '?step=' . $upcontext['current_step'] . '&amp;substep=' . $_GET['substep'] . '&amp;data=' . base64_encode(serialize($upcontext['upgrade_status']));
  628. // Custom stuff to pass back?
  629. if (!empty($upcontext['query_string']))
  630. $upcontext['form_url'] .= $upcontext['query_string'];
  631. call_user_func('template_' . $upcontext['sub_template']);
  632. }
  633. // Was there an error?
  634. if (!empty($upcontext['forced_error_message']))
  635. echo $upcontext['forced_error_message'];
  636. // Show the footer.
  637. if (!isset($_GET['xml']))
  638. template_upgrade_below();
  639. else
  640. template_xml_below();
  641. }
  642. // Bang - gone!
  643. die();
  644. }
  645. // Used to direct the user to another location.
  646. function redirectLocation($location, $addForm = true)
  647. {
  648. global $upgradeurl, $upcontext, $command_line;
  649. // Command line users can't be redirected.
  650. if ($command_line)
  651. upgradeExit(true);
  652. // Are we providing the core info?
  653. if ($addForm)
  654. {
  655. $upcontext['upgrade_status']['curstep'] = $upcontext['current_step'];
  656. $location = $upgradeurl . '?step=' . $upcontext['current_step'] . '&substep=' . $_GET['substep'] . '&data=' . base64_encode(serialize($upcontext['upgrade_status'])) . $location;
  657. }
  658. while (@ob_end_clean());
  659. header('Location: ' . strtr($location, array('&amp;' => '&')));
  660. // Exit - saving status as we go.
  661. upgradeExit(true);
  662. }
  663. // Load all essential data and connect to the DB as this is pre SSI.php
  664. function loadEssentialData()
  665. {
  666. global $db_server, $db_user, $db_passwd, $db_name, $db_connection, $db_prefix, $db_character_set, $db_type;
  667. global $modSettings, $sourcedir, $smcFunc, $upcontext;
  668. // Do the non-SSI stuff...
  669. @set_magic_quotes_runtime(0);
  670. error_reporting(E_ALL);
  671. define('SMF', 1);
  672. // Start the session.
  673. if (@ini_get('session.save_handler') == 'user')
  674. @ini_set('session.save_handler', 'files');
  675. @session_start();
  676. if (empty($smcFunc))
  677. $smcFunc = array();
  678. // Check we don't need some compatibility.
  679. if (@version_compare(PHP_VERSION, '5.1', '<='))
  680. require_once($sourcedir . '/Subs-Compat.php');
  681. // Initialize everything...
  682. initialize_inputs();
  683. // Get the database going!
  684. if (empty($db_type))
  685. $db_type = 'mysql';
  686. if (file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php'))
  687. {
  688. require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
  689. // Make the connection...
  690. $db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, array('non_fatal' => true));
  691. // Oh dear god!!
  692. if ($db_connection === null)
  693. die('Unable to connect to database - please check username and password are correct in Settings.php');
  694. if ($db_type == 'mysql' && isset($db_character_set) && preg_match('~^\w+$~', $db_character_set) === 1)
  695. $smcFunc['db_query']('', '
  696. SET NAMES ' . $db_character_set,
  697. array(
  698. 'db_error_skip' => true,
  699. )
  700. );
  701. // Load the modSettings data...
  702. $request = $smcFunc['db_query']('', '
  703. SELECT variable, value
  704. FROM {db_prefix}settings',
  705. array(
  706. 'db_error_skip' => true,
  707. )
  708. );
  709. $modSettings = array();
  710. while ($row = $smcFunc['db_fetch_assoc']($request))
  711. $modSettings[$row['variable']] = $row['value'];
  712. $smcFunc['db_free_result']($request);
  713. }
  714. else
  715. {
  716. return throw_error('Cannot find ' . $sourcedir . '/Subs-Db-' . $db_type . '.php' . '. Please check you have uploaded all source files and have the correct paths set.');
  717. }
  718. // If they don't have the file, they're going to get a warning anyway so we won't need to clean request vars.
  719. if (file_exists($sourcedir . '/QueryString.php'))
  720. {
  721. require_once($sourcedir . '/QueryString.php');
  722. cleanRequest();
  723. }
  724. if (!isset($_GET['substep']))
  725. $_GET['substep'] = 0;
  726. }
  727. function initialize_inputs()
  728. {
  729. global $sourcedir, $start_time, $upcontext, $db_type;
  730. $start_time = time();
  731. umask(0);
  732. // Fun. Low PHP version...
  733. if (!isset($_GET))
  734. {
  735. $GLOBALS['_GET']['step'] = 0;
  736. return;
  737. }
  738. ob_start();
  739. // Better to upgrade cleanly and fall apart than to screw everything up if things take too long.
  740. ignore_user_abort(true);
  741. // This is really quite simple; if ?delete is on the URL, delete the upgrader...
  742. if (isset($_GET['delete']))
  743. {
  744. @unlink(__FILE__);
  745. // And the extra little files ;).
  746. @unlink(dirname(__FILE__) . '/upgrade_1-0.sql');
  747. @unlink(dirname(__FILE__) . '/upgrade_1-1.sql');
  748. @unlink(dirname(__FILE__) . '/upgrade_2-0_' . $db_type . '.sql');
  749. @unlink(dirname(__FILE__) . '/upgrade_2-1_' . $db_type . '.sql');
  750. @unlink(dirname(__FILE__) . '/webinstall.php');
  751. $dh = opendir(dirname(__FILE__));
  752. while ($file = readdir($dh))
  753. {
  754. if (preg_match('~upgrade_\d-\d_([A-Za-z])+\.sql~i', $file, $matches) && isset($matches[1]))
  755. @unlink(dirname(__FILE__) . '/' . $file);
  756. }
  757. closedir($dh);
  758. 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');
  759. exit;
  760. }
  761. // Are we calling the backup css file?
  762. if (isset($_GET['infile_css']))
  763. {
  764. header('Content-Type: text/css');
  765. template_css();
  766. exit;
  767. }
  768. // Anybody home?
  769. if (!isset($_GET['xml']))
  770. {
  771. $upcontext['remote_files_available'] = false;
  772. $test = @fsockopen('www.simplemachines.org', 80, $errno, $errstr, 1);
  773. if ($test)
  774. $upcontext['remote_files_available'] = true;
  775. @fclose($test);
  776. }
  777. // Something is causing this to happen, and it's annoying. Stop it.
  778. $temp = 'upgrade_php?step';
  779. while (strlen($temp) > 4)
  780. {
  781. if (isset($_GET[$temp]))
  782. unset($_GET[$temp]);
  783. $temp = substr($temp, 1);
  784. }
  785. // Force a step, defaulting to 0.
  786. $_GET['step'] = (int) @$_GET['step'];
  787. $_GET['substep'] = (int) @$_GET['substep'];
  788. }
  789. // Step 0 - Let's welcome them in and ask them to login!
  790. function WelcomeLogin()
  791. {
  792. global $boarddir, $sourcedir, $db_prefix, $language, $modSettings, $cachedir, $upgradeurl, $upcontext, $disable_security;
  793. global $smcFunc, $db_type, $databases, $txt;
  794. $upcontext['sub_template'] = 'welcome_message';
  795. // Check for some key files - one template, one language, and a new and an old source file.
  796. $check = @file_exists($boarddir . '/Themes/default/index.template.php')
  797. && @file_exists($sourcedir . '/QueryString.php')
  798. && @file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php')
  799. && @file_exists(dirname(__FILE__) . '/upgrade_2-1_' . $db_type . '.sql');
  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. if (!$check)
  808. // 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.
  809. return throw_error('The upgrader was unable to find some crucial files.<br /><br />Please make sure you uploaded all of the files included in the package, including the Themes, Sources, and other directories.');
  810. // Do they meet the install requirements?
  811. if (!php_version_check())
  812. return throw_error('Warning! You do not appear to have a version of PHP installed on your webserver that meets SMF\'s minimum installations requirements.<br /><br />Please ask your host to upgrade.');
  813. if (!db_version_check())
  814. return throw_error('Your ' . $databases[$db_type]['name'] . ' version does not meet the minimum requirements of SMF.<br /><br />Please ask your host to upgrade.');
  815. // Do they have ALTER privileges?
  816. if (!empty($databases[$db_type]['alter_support']) && $smcFunc['db_query']('alter_boards', 'ALTER TABLE {db_prefix}boards ORDER BY id_board', array()) === false)
  817. return throw_error('The ' . $databases[$db_type]['name'] . ' user you have set in Settings.php does not have proper privileges.<br /><br />Please ask your host to give this user the ALTER, CREATE, and DROP privileges.');
  818. // Do a quick version spot check.
  819. $temp = substr(@implode('', @file($boarddir . '/index.php')), 0, 4096);
  820. preg_match('~\*\s@version\s+(.+)[\s]{2}~i', $temp, $match);
  821. if (empty($match[1]) || $match[1] != SMF_VERSION)
  822. return throw_error('The upgrader found some old or outdated files.<br /><br />Please make certain you uploaded the new versions of all the files included in the package.');
  823. // What absolutely needs to be writable?
  824. $writable_files = array(
  825. $boarddir . '/Settings.php',
  826. $boarddir . '/Settings_bak.php',
  827. );
  828. require_once($sourcedir . '/Security.php');
  829. createToken('login');
  830. // Check the cache directory.
  831. $cachedir_temp = empty($cachedir) ? $boarddir . '/cache' : $cachedir;
  832. if (!file_exists($cachedir_temp))
  833. @mkdir($cachedir_temp);
  834. if (!file_exists($cachedir_temp))
  835. return throw_error('The cache directory could not be found.<br /><br />Please make sure you have a directory called &quot;cache&quot; in your forum directory before continuing.');
  836. if (!file_exists($boarddir . '/Themes/default/languages/index.' . $upcontext['language'] . '.php') && !isset($modSettings['smfVersion']) && !isset($_GET['lang']))
  837. return throw_error('The upgrader was unable to find language files for the language specified in Settings.php.<br />SMF will not work without the primary language files installed.<br /><br />Please either install them, or <a href="' . $upgradeurl . '?step=0;lang=english">use english instead</a>.');
  838. elseif (!isset($_GET['skiplang']))
  839. {
  840. $temp = substr(@implode('', @file($boarddir . '/Themes/default/languages/index.' . $upcontext['language'] . '.php')), 0, 4096);
  841. preg_match('~(?://|/\*)\s*Version:\s+(.+?);\s*index(?:[\s]{2}|\*/)~i', $temp, $match);
  842. if (empty($match[1]) || $match[1] != SMF_LANG_VERSION)
  843. return throw_error('The upgrader found some old or outdated language files, for the forum default language, ' . $upcontext['language'] . '.<br /><br />Please make certain you uploaded the new versions of all the files included in the package, even the theme and language files for the default theme.<br />&nbsp;&nbsp;&nbsp;[<a href="' . $upgradeurl . '?skiplang">SKIP</a>] [<a href="' . $upgradeurl . '?lang=english">Try English</a>]');
  844. }
  845. // This needs to exist!
  846. if (!file_exists($boarddir . '/Themes/default/languages/Install.' . $upcontext['language'] . '.php'))
  847. return throw_error('The upgrader could not find the &quot;Install&quot; language file for the forum default language, ' . $upcontext['language'] . '.<br /><br />Please make certain you uploaded all the files included in the package, even the theme and language files for the default theme.<br />&nbsp;&nbsp;&nbsp;[<a href="' . $upgradeurl . '?lang=english">Try English</a>]');
  848. else
  849. require_once($boarddir . '/Themes/default/languages/Install.' . $upcontext['language'] . '.php');
  850. if (!makeFilesWritable($writable_files))
  851. return false;
  852. // Check agreement.txt. (it may not exist, in which case $boarddir must be writable.)
  853. if (isset($modSettings['agreement']) && (!is_writable($boarddir) || file_exists($boarddir . '/agreement.txt')) && !is_writable($boarddir . '/agreement.txt'))
  854. return throw_error('The upgrader was unable to obtain write access to agreement.txt.<br /><br />If you are using a linux or unix based server, please ensure that the file is chmod\'d to 777, or if it does not exist that the directory this upgrader is in is 777.<br />If your server is running Windows, please ensure that the internet guest account has the proper permissions on it or its folder.');
  855. // Upgrade the agreement.
  856. elseif (isset($modSettings['agreement']))
  857. {
  858. $fp = fopen($boarddir . '/agreement.txt', 'w');
  859. fwrite($fp, $modSettings['agreement']);
  860. fclose($fp);
  861. }
  862. // We're going to check that their board dir setting is right incase they've been moving stuff around.
  863. if (strtr($boarddir, array('/' => '', '\\' => '')) != strtr(dirname(__FILE__), array('/' => '', '\\' => '')))
  864. $upcontext['warning'] = '
  865. It looks as if your board directory settings <em>might</em> be incorrect. Your board directory is currently set to &quot;' . $boarddir . '&quot; but should probably be &quot;' . dirname(__FILE__) . '&quot;. Settings.php currently lists your paths as:<br />
  866. <ul>
  867. <li>Board Directory: ' . $boarddir . '</li>
  868. <li>Source Directory: ' . $boarddir . '</li>
  869. <li>Cache Directory: ' . $cachedir_temp . '</li>
  870. </ul>
  871. If these seem incorrect please open Settings.php in a text editor before proceeding with this upgrade. If they are incorrect due to you moving your forum to a new location please download and execute the <a href="http://download.simplemachines.org/?tools">Repair Settings</a> tool from the Simple Machines website before continuing.';
  872. // Either we're logged in or we're going to present the login.
  873. if (checkLogin())
  874. return true;
  875. return false;
  876. }
  877. // Step 0.5: Does the login work?
  878. function checkLogin()
  879. {
  880. global $boarddir, $sourcedir, $db_prefix, $language, $modSettings, $cachedir, $upgradeurl, $upcontext, $disable_security;
  881. global $smcFunc, $db_type, $databases, $support_js, $txt;
  882. // Are we trying to login?
  883. if (isset($_POST['contbutt']) && (!empty($_POST['user']) || $disable_security))
  884. {
  885. // If we've disabled security pick a suitable name!
  886. if (empty($_POST['user']))
  887. $_POST['user'] = 'Administrator';
  888. // Before 2.0 these column names were different!
  889. $oldDB = false;
  890. if (empty($db_type) || $db_type == 'mysql')
  891. {
  892. $request = $smcFunc['db_query']('', '
  893. SHOW COLUMNS
  894. FROM {db_prefix}members
  895. LIKE {string:member_name}',
  896. array(
  897. 'member_name' => 'memberName',
  898. 'db_error_skip' => true,
  899. )
  900. );
  901. if ($smcFunc['db_num_rows']($request) != 0)
  902. $oldDB = true;
  903. $smcFunc['db_free_result']($request);
  904. }
  905. // Get what we believe to be their details.
  906. if (!$disable_security)
  907. {
  908. if ($oldDB)
  909. $request = $smcFunc['db_query']('', '
  910. SELECT id_member, memberName AS member_name, passwd, id_group,
  911. additionalGroups AS additional_groups, lngfile
  912. FROM {db_prefix}members
  913. WHERE memberName = {string:member_name}',
  914. array(
  915. 'member_name' => $_POST['user'],
  916. 'db_error_skip' => true,
  917. )
  918. );
  919. else
  920. $request = $smcFunc['db_query']('', '
  921. SELECT id_member, member_name, passwd, id_group, additional_groups, lngfile
  922. FROM {db_prefix}members
  923. WHERE member_name = {string:member_name}',
  924. array(
  925. 'member_name' => $_POST['user'],
  926. 'db_error_skip' => true,
  927. )
  928. );
  929. if ($smcFunc['db_num_rows']($request) != 0)
  930. {
  931. list ($id_member, $name, $password, $id_group, $addGroups, $user_language) = $smcFunc['db_fetch_row']($request);
  932. $groups = explode(',', $addGroups);
  933. $groups[] = $id_group;
  934. foreach ($groups as $k => $v)
  935. $groups[$k] = (int) $v;
  936. // Figure out the password using SMF's encryption - if what they typed is right.
  937. if (isset($_REQUEST['hash_passwrd']) && strlen($_REQUEST['hash_passwrd']) == 40)
  938. {
  939. // Challenge passed.
  940. if ($_REQUEST['hash_passwrd'] == sha1($password . $upcontext['rid']))
  941. $sha_passwd = $password;
  942. }
  943. else
  944. $sha_passwd = sha1(strtolower($name) . un_htmlspecialchars($_REQUEST['passwrd']));
  945. }
  946. else
  947. $upcontext['username_incorrect'] = true;
  948. $smcFunc['db_free_result']($request);
  949. }
  950. $upcontext['username'] = $_POST['user'];
  951. // Track whether javascript works!
  952. if (!empty($_POST['js_works']))
  953. {
  954. $upcontext['upgrade_status']['js'] = 1;
  955. $support_js = 1;
  956. }
  957. else
  958. $support_js = 0;
  959. // Note down the version we are coming from.
  960. if (!empty($modSettings['smfVersion']) && empty($upcontext['user']['version']))
  961. $upcontext['user']['version'] = $modSettings['smfVersion'];
  962. // Didn't get anywhere?
  963. if ((empty($sha_passwd) || $password != $sha_passwd) && empty($upcontext['username_incorrect']) && !$disable_security)
  964. {
  965. // MD5?
  966. $md5pass = md5_hmac($_REQUEST['passwrd'], strtolower($_POST['user']));
  967. if ($md5pass != $password)
  968. {
  969. $upcontext['password_failed'] = true;
  970. // Disable the hashing this time.
  971. $upcontext['disable_login_hashing'] = true;
  972. }
  973. }
  974. if ((empty($upcontext['password_failed']) && !empty($name)) || $disable_security)
  975. {
  976. // Set the password.
  977. if (!$disable_security)
  978. {
  979. // Do we actually have permission?
  980. if (!in_array(1, $groups))
  981. {
  982. $request = $smcFunc['db_query']('', '
  983. SELECT permission
  984. FROM {db_prefix}permissions
  985. WHERE id_group IN ({array_int:groups})
  986. AND permission = {string:admin_forum}',
  987. array(
  988. 'groups' => $groups,
  989. 'admin_forum' => 'admin_forum',
  990. 'db_error_skip' => true,
  991. )
  992. );
  993. if ($smcFunc['db_num_rows']($request) == 0)
  994. return throw_error('You need to be an admin to perform an upgrade!');
  995. $smcFunc['db_free_result']($request);
  996. }
  997. $upcontext['user']['id'] = $id_member;
  998. $upcontext['user']['name'] = $name;
  999. }
  1000. else
  1001. {
  1002. $upcontext['user']['id'] = 1;
  1003. $upcontext['user']['name'] = 'Administrator';
  1004. }
  1005. $upcontext['user']['pass'] = mt_rand(0,60000);
  1006. // This basically is used to match the GET variables to Settings.php.
  1007. $upcontext['upgrade_status']['pass'] = $upcontext['user']['pass'];
  1008. // Set the language to that of the user?
  1009. if (isset($user_language) && $user_language != $upcontext['language'] && file_exists($boarddir . '/Themes/default/languages/index.' . basename($user_language, '.lng') . '.php'))
  1010. {
  1011. $user_language = basename($user_language, '.lng');
  1012. $temp = substr(@implode('', @file($boarddir . '/Themes/default/languages/index.' . $user_language . '.php')), 0, 4096);
  1013. preg_match('~(?://|/\*)\s*Version:\s+(.+?);\s*index(?:[\s]{2}|\*/)~i', $temp, $match);
  1014. if (empty($match[1]) || $match[1] != SMF_LANG_VERSION)
  1015. $upcontext['upgrade_options_warning'] = 'The language files for your selected language, ' . $user_language . ', have not been updated to the latest version. Upgrade will continue with the forum default, ' . $upcontext['language'] . '.';
  1016. elseif (!file_exists($boarddir . '/Themes/default/languages/Install.' . basename($user_language, '.lng') . '.php'))
  1017. $upcontext['upgrade_options_warning'] = 'The language files for your selected language, ' . $user_language . ', have not been uploaded/updated as the &quot;Install&quot; language file is missing. Upgrade will continue with the forum default, ' . $upcontext['language'] . '.';
  1018. else
  1019. {
  1020. // Set this as the new language.
  1021. $upcontext['language'] = $user_language;
  1022. $upcontext['upgrade_status']['lang'] = $upcontext['language'];
  1023. // Include the file.
  1024. require_once($boarddir . '/Themes/default/languages/Install.' . $user_language . '.php');
  1025. }
  1026. }
  1027. // If we're resuming set the step and substep to be correct.
  1028. if (isset($_POST['cont']))
  1029. {
  1030. $upcontext['current_step'] = $upcontext['user']['step'];
  1031. $_GET['substep'] = $upcontext['user']['substep'];
  1032. }
  1033. return true;
  1034. }
  1035. }
  1036. return false;
  1037. }
  1038. // Step 1: Do the maintenance and backup.
  1039. function UpgradeOptions()
  1040. {
  1041. global $db_prefix, $command_line, $modSettings, $is_debug, $smcFunc;
  1042. global $boarddir, $boardurl, $sourcedir, $maintenance, $mmessage, $cachedir, $upcontext, $db_type;
  1043. $upcontext['sub_template'] = 'upgrade_options';
  1044. $upcontext['page_title'] = 'Upgrade Options';
  1045. // If we've not submitted then we're done.
  1046. if (empty($_POST['upcont']))
  1047. return false;
  1048. // Firstly, if they're enabling SM stat collection just do it.
  1049. if (!empty($_POST['stats']) && substr($boardurl, 0, 16) != 'http://localhost' && empty($modSettings['allow_sm_stats']))
  1050. {
  1051. // Attempt to register the site etc.
  1052. $fp = @fsockopen('www.simplemachines.org', 80, $errno, $errstr);
  1053. if ($fp)
  1054. {
  1055. $out = 'GET /smf/stats/register_stats.php?site=' . base64_encode($boardurl) . ' HTTP/1.1' . "\r\n";
  1056. $out .= 'Host: www.simplemachines.org' . "\r\n";
  1057. $out .= 'Connection: Close' . "\r\n\r\n";
  1058. fwrite($fp, $out);
  1059. $return_data = '';
  1060. while (!feof($fp))
  1061. $return_data .= fgets($fp, 128);
  1062. fclose($fp);
  1063. // Get the unique site ID.
  1064. preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
  1065. if (!empty($ID[1]))
  1066. $smcFunc['db_insert']('replace',
  1067. $db_prefix . 'settings',
  1068. array('variable' => 'string', 'value' => 'string'),
  1069. array('allow_sm_stats', $ID[1]),
  1070. array('variable')
  1071. );
  1072. }
  1073. }
  1074. else
  1075. $smcFunc['db_query']('', '
  1076. DELETE FROM {db_prefix}settings
  1077. WHERE variable = {string:allow_sm_stats}',
  1078. array(
  1079. 'allow_sm_stats' => 'allow_sm_stats',
  1080. 'db_error_skip' => true,
  1081. )
  1082. );
  1083. // Emptying the error log?
  1084. if (!empty($_POST['empty_error']))
  1085. $smcFunc['db_query']('truncate_table', '
  1086. TRUNCATE {db_prefix}log_errors',
  1087. array(
  1088. )
  1089. );
  1090. $changes = array();
  1091. // If we're overriding the language follow it through.
  1092. if (isset($_GET['lang']) && file_exists($boarddir . '/Themes/default/languages/index.' . $_GET['lang'] . '.php'))
  1093. $changes['language'] = '\'' . $_GET['lang'] . '\'';
  1094. if (!empty($_POST['maint']))
  1095. {
  1096. $changes['maintenance'] = '2';
  1097. // Remember what it was...
  1098. $upcontext['user']['main'] = $maintenance;
  1099. if (!empty($_POST['maintitle']))
  1100. {
  1101. $changes['mtitle'] = '\'' . addslashes($_POST['maintitle']) . '\'';
  1102. $changes['mmessage'] = '\'' . addslashes($_POST['mainmessage']) . '\'';
  1103. }
  1104. else
  1105. {
  1106. $changes['mtitle'] = '\'Upgrading the forum...\'';
  1107. $changes['mmessage'] = '\'Don\\\'t worry, we will be back shortly with an updated forum. It will only be a minute ;).\'';
  1108. }
  1109. }
  1110. if ($command_line)
  1111. echo ' * Updating Settings.php...';
  1112. // Backup the current one first.
  1113. copy($boarddir . '/Settings.php', $boarddir . '/Settings_bak.php');
  1114. // Fix some old paths.
  1115. if (substr($boarddir, 0, 1) == '.')
  1116. $changes['boarddir'] = '\'' . fixRelativePath($boarddir) . '\'';
  1117. if (substr($sourcedir, 0, 1) == '.')
  1118. $changes['sourcedir'] = '\'' . fixRelativePath($sourcedir) . '\'';
  1119. if (empty($cachedir) || substr($cachedir, 0, 1) == '.')
  1120. $changes['cachedir'] = '\'' . fixRelativePath($boarddir) . '/cache\'';
  1121. // Not had the database type added before?
  1122. if (empty($db_type))
  1123. $changes['db_type'] = 'mysql';
  1124. // @todo Maybe change the cookie name if going to 1.1, too?
  1125. // Update Settings.php with the new settings.
  1126. changeSettings($changes);
  1127. if ($command_line)
  1128. echo ' Successful.' . "\n";
  1129. // Are we doing debug?
  1130. if (isset($_POST['debug']))
  1131. {
  1132. $upcontext['upgrade_status']['debug'] = true;
  1133. $is_debug = true;
  1134. }
  1135. // If we're not backing up then jump one.
  1136. if (empty($_POST['backup']))
  1137. $upcontext['current_step']++;
  1138. // If we've got here then let's proceed to the next step!
  1139. return true;
  1140. }
  1141. // Backup the database - why not...
  1142. function BackupDatabase()
  1143. {
  1144. global $upcontext, $db_prefix, $command_line, $is_debug, $support_js, $file_steps, $smcFunc;
  1145. $upcontext['sub_template'] = isset($_GET['xml']) ? 'backup_xml' : 'backup_database';
  1146. $upcontext['page_title'] = 'Backup Database';
  1147. // Done it already - js wise?
  1148. if (!empty($_POST['backup_done']))
  1149. return true;
  1150. // Some useful stuff here.
  1151. db_extend();
  1152. // Get all the table names.
  1153. $filter = str_replace('_', '\_', preg_match('~^`(.+?)`\.(.+?)$~', $db_prefix, $match) != 0 ? $match[2] : $db_prefix) . '%';
  1154. $db = preg_match('~^`(.+?)`\.(.+?)$~', $db_prefix, $match) != 0 ? strtr($match[1], array('`' => '')) : false;
  1155. $tables = $smcFunc['db_list_tables']($db, $filter);
  1156. $table_names = array();
  1157. foreach ($tables as $table)
  1158. if (substr($table, 0, 7) !== 'backup_')
  1159. $table_names[] = $table;
  1160. $upcontext['table_count'] = count($table_names);
  1161. $upcontext['cur_table_num'] = $_GET['substep'];
  1162. $upcontext['cur_table_name'] = str_replace($db_prefix, '', isset($table_names[$_GET['substep']]) ? $table_names[$_GET['substep']] : $table_names[0]);
  1163. $upcontext['step_progress'] = (int) (($upcontext['cur_table_num'] / $upcontext['table_count']) * 100);
  1164. // For non-java auto submit...
  1165. $file_steps = $upcontext['table_count'];
  1166. // What ones have we already done?
  1167. foreach ($table_names as $id => $table)
  1168. if ($id < $_GET['substep'])
  1169. $upcontext['previous_tables'][] = $table;
  1170. if ($command_line)
  1171. echo 'Backing Up Tables.';
  1172. // If we don't support javascript we backup here.
  1173. if (!$support_js || isset($_GET['xml']))
  1174. {
  1175. // Backup each table!
  1176. for ($substep = $_GET['substep'], $n = count($table_names); $substep < $n; $substep++)
  1177. {
  1178. $upcontext['cur_table_name'] = str_replace($db_prefix, '', (isset($table_names[$substep + 1]) ? $table_names[$substep + 1] : $table_names[$substep]));
  1179. $upcontext['cur_table_num'] = $substep + 1;
  1180. $upcontext['step_progress'] = (int) (($upcontext['cur_table_num'] / $upcontext['table_count']) * 100);
  1181. // Do we need to pause?
  1182. nextSubstep($substep);
  1183. backupTable($table_names[$substep]);
  1184. // If this is XML to keep it nice for the user do one table at a time anyway!
  1185. if (isset($_GET['xml']))
  1186. return upgradeExit();
  1187. }
  1188. if ($is_debug && $command_line)
  1189. {
  1190. echo "\n" . ' Successful.\'' . "\n";
  1191. flush();
  1192. }
  1193. $upcontext['step_progress'] = 100;
  1194. $_GET['substep'] = 0;
  1195. // Make sure we move on!
  1196. return true;
  1197. }
  1198. // Either way next place to post will be database changes!
  1199. $_GET['substep'] = 0;
  1200. return false;
  1201. }
  1202. // Backup one table...
  1203. function backupTable($table)
  1204. {
  1205. global $is_debug, $command_line, $db_prefix, $smcFunc;
  1206. if ($is_debug && $command_line)
  1207. {
  1208. echo "\n" . ' +++ Backing up \"' . str_replace($db_prefix, '', $table) . '"...';
  1209. flush();
  1210. }
  1211. $smcFunc['db_backup_table']($table, 'backup_' . $table);
  1212. if ($is_debug && $command_line)
  1213. echo ' done.';
  1214. }
  1215. // Step 2: Everything.
  1216. function DatabaseChanges()
  1217. {
  1218. global $db_prefix, $modSettings, $command_line, $smcFunc;
  1219. global $language, $boardurl, $sourcedir, $boarddir, $upcontext, $support_js, $db_type;
  1220. // Have we just completed this?
  1221. if (!empty($_POST['database_done']))
  1222. return true;
  1223. $upcontext['sub_template'] = isset($_GET['xml']) ? 'database_xml' : 'database_changes';
  1224. $upcontext['page_title'] = 'Database Changes';
  1225. // All possible files.
  1226. // Name, <version, insert_on_complete
  1227. $files = array(
  1228. array('upgrade_1-0.sql', '1.1', '1.1 RC0'),
  1229. array('upgrade_1-1.sql', '2.0', '2.0 a'),
  1230. array('upgrade_2-0_' . $db_type . '.sql', '2.1', '2.1 dev0'),
  1231. array('upgrade_2-1_' . $db_type . '.sql', '3.0', SMF_VERSION),
  1232. );
  1233. // How many files are there in total?
  1234. if (isset($_GET['filecount']))
  1235. $upcontext['file_count'] = (int) $_GET['filecount'];
  1236. else
  1237. {
  1238. $upcontext['file_count'] = 0;
  1239. foreach ($files as $file)
  1240. {
  1241. if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < $file[1])
  1242. $upcontext['file_count']++;
  1243. }
  1244. }
  1245. // Do each file!
  1246. $did_not_do = count($files) - $upcontext['file_count'];
  1247. $upcontext['step_progress'] = 0;
  1248. $upcontext['cur_file_num'] = 0;
  1249. foreach ($files as $file)
  1250. {
  1251. if ($did_not_do)
  1252. $did_not_do--;
  1253. else
  1254. {
  1255. $upcontext['cur_file_num']++;
  1256. $upcontext['cur_file_name'] = $file[0];
  1257. // Do we actually need to do this still?
  1258. if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < $file[1])
  1259. {
  1260. $nextFile = parse_sql(dirname(__FILE__) . '/' . $file[0]);
  1261. if ($nextFile)
  1262. {
  1263. // Only update the version of this if complete.
  1264. $smcFunc['db_insert']('replace',
  1265. $db_prefix . 'settings',
  1266. array('variable' => 'string', 'value' => 'string'),
  1267. array('smfVersion', $file[2]),
  1268. array('variable')
  1269. );
  1270. $modSettings['smfVersion'] = $file[2];
  1271. }
  1272. // If this is XML we only do this stuff once.
  1273. if (isset($_GET['xml']))
  1274. {
  1275. // Flag to move on to the next.
  1276. $upcontext['completed_step'] = true;
  1277. // Did we complete the whole file?
  1278. if ($nextFile)
  1279. $upcontext['current_debug_item_num'] = -1;
  1280. return upgradeExit();
  1281. }
  1282. elseif ($support_js)
  1283. break;
  1284. }
  1285. // Set the progress bar to be right as if we had - even if we hadn't...
  1286. $upcontext['step_progress'] = ($upcontext['cur_file_num'] / $upcontext['file_count']) * 100;
  1287. }
  1288. }
  1289. $_GET['substep'] = 0;
  1290. // So the template knows we're done.
  1291. if (!$support_js)
  1292. {
  1293. $upcontext['changes_complete'] = true;
  1294. // If this is the command line we can't do any more.
  1295. if ($command_line)
  1296. return DeleteUpgrade();
  1297. return true;
  1298. }
  1299. return false;
  1300. }
  1301. // Clean up any mods installed...
  1302. function CleanupMods()
  1303. {
  1304. global $db_prefix, $modSettings, $upcontext, $boarddir, $sourcedir, $settings, $smcFunc, $command_line;
  1305. // Sorry. Not supported for command line users.
  1306. if ($command_line)
  1307. return true;
  1308. // Skipp…

Large files files are truncated, but you can click here to view the full file