PageRenderTime 59ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/install/upgrade.php

https://github.com/Arantor/Elkarte
PHP | 4467 lines | 3461 code | 597 blank | 409 comment | 721 complexity | 3fe4172b1f5f9edd38337f4143b567e3 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-3.0

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

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

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