PageRenderTime 66ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

/phpBB/install/install_update.php

https://github.com/SamTest/phpbb3
PHP | 1799 lines | 1228 code | 330 blank | 241 comment | 215 complexity | 9447f9a4be4ef1b69d908757ed95a0db MD5 | raw file
Possible License(s): AGPL-1.0

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

  1. <?php
  2. /**
  3. *
  4. * @package install
  5. * @version $Id$
  6. * @copyright (c) 2006 phpBB Group
  7. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  8. *
  9. * @todo check for writable cache/store/files directory
  10. */
  11. /**
  12. */
  13. if (!defined('IN_INSTALL'))
  14. {
  15. // Someone has tried to access the file directly. This is not a good idea, so exit
  16. exit;
  17. }
  18. if (!empty($setmodules))
  19. {
  20. // If phpBB is not installed we do not include this module
  21. if (@file_exists($phpbb_root_path . 'config.' . $phpEx) && !@file_exists($phpbb_root_path . 'cache/install_lock'))
  22. {
  23. include_once($phpbb_root_path . 'config.' . $phpEx);
  24. if (!defined('PHPBB_INSTALLED'))
  25. {
  26. return;
  27. }
  28. }
  29. else
  30. {
  31. return;
  32. }
  33. $module[] = array(
  34. 'module_type' => 'update',
  35. 'module_title' => 'UPDATE',
  36. 'module_filename' => substr(basename(__FILE__), 0, -strlen($phpEx)-1),
  37. 'module_order' => 30,
  38. 'module_subs' => '',
  39. 'module_stages' => array('INTRO', 'VERSION_CHECK', 'UPDATE_DB', 'FILE_CHECK', 'UPDATE_FILES'),
  40. 'module_reqs' => ''
  41. );
  42. }
  43. /**
  44. * Update Installation
  45. * @package install
  46. */
  47. class install_update extends module
  48. {
  49. var $p_master;
  50. var $update_info;
  51. var $old_location;
  52. var $new_location;
  53. var $latest_version;
  54. var $current_version;
  55. var $unequal_version;
  56. var $update_to_version;
  57. // Set to false
  58. var $test_update = false;
  59. function install_update(&$p_master)
  60. {
  61. $this->p_master = &$p_master;
  62. }
  63. function main($mode, $sub)
  64. {
  65. global $template, $phpEx, $phpbb_root_path, $user, $db, $config, $cache, $auth, $language;
  66. $this->tpl_name = 'install_update';
  67. $this->page_title = 'UPDATE_INSTALLATION';
  68. $this->unequal_version = false;
  69. $this->old_location = $phpbb_root_path . 'install/update/old/';
  70. $this->new_location = $phpbb_root_path . 'install/update/new/';
  71. // Init DB
  72. require($phpbb_root_path . 'config.' . $phpEx);
  73. require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx);
  74. require($phpbb_root_path . 'includes/constants.' . $phpEx);
  75. // Special options for conflicts/modified files
  76. define('MERGE_NO_MERGE_NEW', 1);
  77. define('MERGE_NO_MERGE_MOD', 2);
  78. define('MERGE_NEW_FILE', 3);
  79. define('MERGE_MOD_FILE', 4);
  80. $db = new $sql_db();
  81. // Connect to DB
  82. $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false);
  83. // We do not need this any longer, unset for safety purposes
  84. unset($dbpasswd);
  85. $config = array();
  86. $sql = 'SELECT config_name, config_value
  87. FROM ' . CONFIG_TABLE;
  88. $result = $db->sql_query($sql);
  89. while ($row = $db->sql_fetchrow($result))
  90. {
  91. $config[$row['config_name']] = $row['config_value'];
  92. }
  93. $db->sql_freeresult($result);
  94. // Force template recompile
  95. $config['load_tplcompile'] = 1;
  96. // First of all, init the user session
  97. $user->session_begin();
  98. $auth->acl($user->data);
  99. // Overwrite user's language with the selected one.
  100. // Config needs to be changed to ensure that guests also get the selected language.
  101. $config_default_lang = $config['default_lang'];
  102. $config['default_lang'] = $language;
  103. $user->data['user_lang'] = $language;
  104. $user->setup(array('common', 'acp/common', 'acp/board', 'install', 'posting'));
  105. // Reset the default_lang
  106. $config['default_lang'] = $config_default_lang;
  107. unset($config_default_lang);
  108. // If we are within the intro page we need to make sure we get up-to-date version info
  109. if ($sub == 'intro')
  110. {
  111. $cache->destroy('_version_info');
  112. }
  113. // Set custom template again. ;)
  114. $template->set_custom_template('../adm/style', 'admin');
  115. // still, the acp template is never stored in the database
  116. $user->theme['template_storedb'] = false;
  117. $template->assign_vars(array(
  118. 'S_USER_LANG' => $user->lang['USER_LANG'],
  119. 'S_CONTENT_DIRECTION' => $user->lang['DIRECTION'],
  120. 'S_CONTENT_ENCODING' => 'UTF-8',
  121. 'S_CONTENT_FLOW_BEGIN' => ($user->lang['DIRECTION'] == 'ltr') ? 'left' : 'right',
  122. 'S_CONTENT_FLOW_END' => ($user->lang['DIRECTION'] == 'ltr') ? 'right' : 'left',
  123. ));
  124. // Get current and latest version
  125. if (($latest_version = $cache->get('_version_info')) === false)
  126. {
  127. $this->latest_version = $this->get_file('version_info');
  128. $cache->put('_version_info', $this->latest_version);
  129. }
  130. else
  131. {
  132. $this->latest_version = $latest_version;
  133. }
  134. // For the current version we trick a bit. ;)
  135. $this->current_version = (!empty($config['version_update_from'])) ? $config['version_update_from'] : $config['version'];
  136. $up_to_date = (version_compare(str_replace('rc', 'RC', strtolower($this->current_version)), str_replace('rc', 'RC', strtolower($this->latest_version)), '<')) ? false : true;
  137. // Check for a valid update directory, else point the user to the phpbb.com website
  138. if (!file_exists($phpbb_root_path . 'install/update') || !file_exists($phpbb_root_path . 'install/update/index.' . $phpEx) || !file_exists($this->old_location) || !file_exists($this->new_location))
  139. {
  140. $template->assign_vars(array(
  141. 'S_ERROR' => true,
  142. 'ERROR_MSG' => ($up_to_date) ? $user->lang['NO_UPDATE_FILES_UP_TO_DATE'] : sprintf($user->lang['NO_UPDATE_FILES_OUTDATED'], $config['version'], $this->current_version, $this->latest_version))
  143. );
  144. return;
  145. }
  146. $this->update_info = $this->get_file('update_info');
  147. // Make sure the update directory holds the correct information
  148. // Since admins are able to run the update/checks more than once we only check if the current version is lower or equal than the version to which we update to.
  149. if (version_compare(str_replace('rc', 'RC', strtolower($this->current_version)), str_replace('rc', 'RC', strtolower($this->update_info['version']['to'])), '>'))
  150. {
  151. $template->assign_vars(array(
  152. 'S_ERROR' => true,
  153. 'ERROR_MSG' => sprintf($user->lang['INCOMPATIBLE_UPDATE_FILES'], $config['version'], $this->update_info['version']['from'], $this->update_info['version']['to']))
  154. );
  155. return;
  156. }
  157. // Check if the update files are actually meant to update from the current version
  158. if ($this->current_version != $this->update_info['version']['from'])
  159. {
  160. $this->unequal_version = true;
  161. $template->assign_vars(array(
  162. 'S_ERROR' => true,
  163. 'ERROR_MSG' => sprintf($user->lang['INCOMPATIBLE_UPDATE_FILES'], $this->current_version, $this->update_info['version']['from'], $this->update_info['version']['to']),
  164. ));
  165. }
  166. // Check if the update files stored are for the latest version...
  167. if ($this->latest_version != $this->update_info['version']['to'])
  168. {
  169. $this->unequal_version = true;
  170. $template->assign_vars(array(
  171. 'S_WARNING' => true,
  172. 'WARNING_MSG' => sprintf($user->lang['OLD_UPDATE_FILES'], $this->update_info['version']['from'], $this->update_info['version']['to'], $this->latest_version))
  173. );
  174. }
  175. // We store the "update to" version, because it is not always the latest. ;)
  176. $this->update_to_version = $this->update_info['version']['to'];
  177. // Fill DB version
  178. if (empty($config['dbms_version']))
  179. {
  180. set_config('dbms_version', $db->sql_server_info(true));
  181. }
  182. if ($this->test_update === false)
  183. {
  184. // Got the updater template itself updated? If so, we are able to directly use it - but only if all three files are present
  185. if (in_array('adm/style/install_update.html', $this->update_info['files']))
  186. {
  187. $this->tpl_name = '../../install/update/new/adm/style/install_update';
  188. }
  189. // What about the language file? Got it updated?
  190. if (in_array('language/en/install.' . $phpEx, $this->update_info['files']))
  191. {
  192. $lang = array();
  193. include($this->new_location . 'language/en/install.' . $phpEx);
  194. // only add new keys to user's language in english
  195. $new_keys = array_diff(array_keys($lang), array_keys($user->lang));
  196. foreach ($new_keys as $i => $new_key)
  197. {
  198. $user->lang[$new_key] = $lang[$new_key];
  199. }
  200. }
  201. }
  202. // Include renderer and engine
  203. $this->include_file('includes/diff/diff.' . $phpEx);
  204. $this->include_file('includes/diff/engine.' . $phpEx);
  205. $this->include_file('includes/diff/renderer.' . $phpEx);
  206. // Make sure we stay at the file check if checking the files again
  207. if (!empty($_POST['check_again']))
  208. {
  209. $sub = $this->p_master->sub = 'file_check';
  210. }
  211. switch ($sub)
  212. {
  213. case 'intro':
  214. $this->page_title = 'UPDATE_INSTALLATION';
  215. $template->assign_vars(array(
  216. 'S_INTRO' => true,
  217. 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=version_check"),
  218. ));
  219. // Make sure the update list is destroyed.
  220. $cache->destroy('_update_list');
  221. $cache->destroy('_diff_files');
  222. $cache->destroy('_expected_files');
  223. break;
  224. case 'version_check':
  225. $this->page_title = 'STAGE_VERSION_CHECK';
  226. $template->assign_vars(array(
  227. 'S_UP_TO_DATE' => $up_to_date,
  228. 'S_VERSION_CHECK' => true,
  229. 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"),
  230. 'U_DB_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_db"),
  231. 'LATEST_VERSION' => $this->latest_version,
  232. 'CURRENT_VERSION' => $this->current_version)
  233. );
  234. // Print out version the update package updates to
  235. if ($this->unequal_version)
  236. {
  237. $template->assign_var('PACKAGE_VERSION', $this->update_info['version']['to']);
  238. }
  239. // Since some people try to update to RC releases, but phpBB.com tells them the last version is the version they currently run
  240. // we are faced with the updater thinking the database schema is up-to-date; which it is, but should be updated none-the-less
  241. // We now try to cope with this by triggering the update process
  242. if (version_compare(str_replace('rc', 'RC', strtolower($this->current_version)), str_replace('rc', 'RC', strtolower($this->update_info['version']['to'])), '<'))
  243. {
  244. $template->assign_vars(array(
  245. 'S_UP_TO_DATE' => false,
  246. ));
  247. }
  248. break;
  249. case 'update_db':
  250. // Make sure the database update is valid for the latest version
  251. $valid = false;
  252. $updates_to_version = '';
  253. if (file_exists($phpbb_root_path . 'install/database_update.' . $phpEx))
  254. {
  255. include_once($phpbb_root_path . 'install/database_update.' . $phpEx);
  256. if ($updates_to_version === $this->update_info['version']['to'])
  257. {
  258. $valid = true;
  259. }
  260. }
  261. // Should not happen at all
  262. if (!$valid)
  263. {
  264. trigger_error($user->lang['DATABASE_UPDATE_INFO_OLD'], E_USER_ERROR);
  265. }
  266. // Just a precaution
  267. $cache->purge();
  268. // Redirect the user to the database update script with some explanations...
  269. $template->assign_vars(array(
  270. 'S_DB_UPDATE' => true,
  271. 'S_DB_UPDATE_FINISHED' => ($config['version'] == $this->update_info['version']['to']) ? true : false,
  272. 'U_DB_UPDATE' => append_sid($phpbb_root_path . 'install/database_update.' . $phpEx, 'type=1&amp;language=' . $user->data['user_lang']),
  273. 'U_DB_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_db"),
  274. 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"),
  275. ));
  276. break;
  277. case 'file_check':
  278. // retrieve info on what changes should have already been made to the files.
  279. $expected_files = $cache->get('_expected_files');
  280. if (!$expected_files)
  281. {
  282. $expected_files = array();
  283. }
  284. // Now make sure the previous file collection is no longer valid...
  285. $cache->destroy('_diff_files');
  286. $this->page_title = 'STAGE_FILE_CHECK';
  287. // Now make sure our update list is correct if the admin refreshes
  288. $action = request_var('action', '');
  289. // We are directly within an update. To make sure our update list is correct we check its status.
  290. $update_list = (!empty($_POST['check_again'])) ? false : $cache->get('_update_list');
  291. $modified = ($update_list !== false) ? @filemtime($cache->cache_dir . 'data_update_list.' . $phpEx) : 0;
  292. // Make sure the list is up-to-date
  293. if ($update_list !== false)
  294. {
  295. $get_new_list = false;
  296. foreach ($this->update_info['files'] as $file)
  297. {
  298. if (file_exists($phpbb_root_path . $file) && filemtime($phpbb_root_path . $file) > $modified)
  299. {
  300. $get_new_list = true;
  301. break;
  302. }
  303. }
  304. }
  305. else
  306. {
  307. $get_new_list = true;
  308. }
  309. if (!$get_new_list && $update_list['status'] != -1)
  310. {
  311. $get_new_list = true;
  312. }
  313. if ($get_new_list)
  314. {
  315. $this->get_update_structure($update_list, $expected_files);
  316. $cache->put('_update_list', $update_list);
  317. // Refresh the page if we are still not finished...
  318. if ($update_list['status'] != -1)
  319. {
  320. $refresh_url = append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check");
  321. meta_refresh(2, $refresh_url);
  322. $template->assign_vars(array(
  323. 'S_IN_PROGRESS' => true,
  324. 'S_COLLECTED' => (int) $update_list['status'],
  325. 'S_TO_COLLECT' => sizeof($this->update_info['files']),
  326. 'L_IN_PROGRESS' => $user->lang['COLLECTING_FILE_DIFFS'],
  327. 'L_IN_PROGRESS_EXPLAIN' => sprintf($user->lang['NUMBER_OF_FILES_COLLECTED'], (int) $update_list['status'], sizeof($this->update_info['files'])),
  328. ));
  329. return;
  330. }
  331. }
  332. if ($action == 'diff')
  333. {
  334. $this->show_diff($update_list);
  335. return;
  336. }
  337. if (sizeof($update_list['no_update']))
  338. {
  339. $template->assign_vars(array(
  340. 'S_NO_UPDATE_FILES' => true,
  341. 'NO_UPDATE_FILES' => implode(', ', array_map('htmlspecialchars', $update_list['no_update'])))
  342. );
  343. }
  344. $new_expected_files = array();
  345. // Now assign the list to the template
  346. foreach ($update_list as $status => $filelist)
  347. {
  348. if ($status == 'no_update' || !sizeof($filelist) || $status == 'status')
  349. {
  350. continue;
  351. }
  352. /* $template->assign_block_vars('files', array(
  353. 'S_STATUS' => true,
  354. 'STATUS' => $status,
  355. 'L_STATUS' => $user->lang['STATUS_' . strtoupper($status)],
  356. 'TITLE' => $user->lang['FILES_' . strtoupper($status)],
  357. 'EXPLAIN' => $user->lang['FILES_' . strtoupper($status) . '_EXPLAIN'],
  358. )
  359. );*/
  360. foreach ($filelist as $file_struct)
  361. {
  362. $s_binary = (!empty($this->update_info['binary']) && in_array($file_struct['filename'], $this->update_info['binary'])) ? true : false;
  363. $filename = htmlspecialchars($file_struct['filename']);
  364. if (strrpos($filename, '/') !== false)
  365. {
  366. $dir_part = substr($filename, 0, strrpos($filename, '/') + 1);
  367. $file_part = substr($filename, strrpos($filename, '/') + 1);
  368. }
  369. else
  370. {
  371. $dir_part = '';
  372. $file_part = $filename;
  373. }
  374. $diff_url = append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check&amp;action=diff&amp;status=$status&amp;file=" . urlencode($file_struct['filename']));
  375. if (isset($file_struct['as_expected']) && $file_struct['as_expected'])
  376. {
  377. $new_expected_files[$file_struct['filename']] = $expected_files[$file_struct['filename']];
  378. }
  379. else
  380. {
  381. $template->assign_block_vars($status, array(
  382. 'STATUS' => $status,
  383. 'FILENAME' => $filename,
  384. 'DIR_PART' => $dir_part,
  385. 'FILE_PART' => $file_part,
  386. 'NUM_CONFLICTS' => (isset($file_struct['conflicts'])) ? $file_struct['conflicts'] : 0,
  387. 'S_CUSTOM' => ($file_struct['custom']) ? true : false,
  388. 'S_BINARY' => $s_binary,
  389. 'CUSTOM_ORIGINAL' => ($file_struct['custom']) ? $file_struct['original'] : '',
  390. 'U_SHOW_DIFF' => $diff_url,
  391. 'L_SHOW_DIFF' => ($status != 'up_to_date') ? $user->lang['SHOW_DIFF_' . strtoupper($status)] : '',
  392. 'U_VIEW_MOD_FILE' => $diff_url . '&amp;op=' . MERGE_MOD_FILE,
  393. 'U_VIEW_NEW_FILE' => $diff_url . '&amp;op=' . MERGE_NEW_FILE,
  394. 'U_VIEW_NO_MERGE_MOD' => $diff_url . '&amp;op=' . MERGE_NO_MERGE_MOD,
  395. 'U_VIEW_NO_MERGE_NEW' => $diff_url . '&amp;op=' . MERGE_NO_MERGE_NEW,
  396. ));
  397. }
  398. }
  399. }
  400. $cache->put('_expected_files', $new_expected_files);
  401. $all_up_to_date = true;
  402. foreach ($update_list as $status => $filelist)
  403. {
  404. if ($status != 'up_to_date' && $status != 'custom' && $status != 'status' && sizeof($filelist))
  405. {
  406. $all_up_to_date = false;
  407. break;
  408. }
  409. }
  410. $template->assign_vars(array(
  411. 'S_FILE_CHECK' => true,
  412. 'S_ALL_UP_TO_DATE' => $all_up_to_date,
  413. 'S_VERSION_UP_TO_DATE' => $up_to_date,
  414. 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"),
  415. 'U_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files"),
  416. 'U_DB_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_db"),
  417. ));
  418. if ($all_up_to_date)
  419. {
  420. // Add database update to log
  421. add_log('admin', 'LOG_UPDATE_PHPBB', $this->current_version, $this->update_to_version);
  422. // Refresh prosilver css data - this may cause some unhappy users, but
  423. $sql = 'SELECT *
  424. FROM ' . STYLES_THEME_TABLE . "
  425. WHERE LOWER(theme_name) = 'prosilver'";
  426. $result = $db->sql_query($sql);
  427. $theme = $db->sql_fetchrow($result);
  428. $db->sql_freeresult($result);
  429. if ($theme)
  430. {
  431. $recache = (empty($theme['theme_data'])) ? true : false;
  432. $update_time = time();
  433. // We test for stylesheet.css because it is faster and most likely the only file changed on common themes
  434. if (!$recache && $theme['theme_mtime'] < @filemtime("{$phpbb_root_path}styles/" . $theme['theme_path'] . '/theme/stylesheet.css'))
  435. {
  436. $recache = true;
  437. $update_time = @filemtime("{$phpbb_root_path}styles/" . $theme['theme_path'] . '/theme/stylesheet.css');
  438. }
  439. else if (!$recache)
  440. {
  441. $last_change = $theme['theme_mtime'];
  442. $dir = @opendir("{$phpbb_root_path}styles/{$theme['theme_path']}/theme");
  443. if ($dir)
  444. {
  445. while (($entry = readdir($dir)) !== false)
  446. {
  447. if (substr(strrchr($entry, '.'), 1) == 'css' && $last_change < @filemtime("{$phpbb_root_path}styles/{$theme['theme_path']}/theme/{$entry}"))
  448. {
  449. $recache = true;
  450. break;
  451. }
  452. }
  453. closedir($dir);
  454. }
  455. }
  456. if ($recache)
  457. {
  458. // Instead of re-caching here, we simply remove theme_data... HAR HAR HAR (think about a carribean pirate)
  459. $sql = 'UPDATE ' . STYLES_THEME_TABLE . " SET theme_data = ''
  460. WHERE theme_id = " . $theme['theme_id'];
  461. $db->sql_query($sql);
  462. $cache->destroy('sql', STYLES_THEME_TABLE);
  463. $cache->destroy('sql', STYLES_TABLE);
  464. }
  465. }
  466. $db->sql_return_on_error(true);
  467. $db->sql_query('DELETE FROM ' . CONFIG_TABLE . " WHERE config_name = 'version_update_from'");
  468. $db->sql_return_on_error(false);
  469. $cache->purge();
  470. }
  471. break;
  472. case 'update_files':
  473. $this->page_title = 'STAGE_UPDATE_FILES';
  474. $s_hidden_fields = '';
  475. $params = array();
  476. $conflicts = request_var('conflict', array('' => 0));
  477. $modified = request_var('modified', array('' => 0));
  478. foreach ($conflicts as $filename => $merge_option)
  479. {
  480. $s_hidden_fields .= '<input type="hidden" name="conflict[' . htmlspecialchars($filename) . ']" value="' . $merge_option . '" />';
  481. $params[] = 'conflict[' . urlencode($filename) . ']=' . urlencode($merge_option);
  482. }
  483. foreach ($modified as $filename => $merge_option)
  484. {
  485. if (!$merge_option)
  486. {
  487. continue;
  488. }
  489. $s_hidden_fields .= '<input type="hidden" name="modified[' . htmlspecialchars($filename) . ']" value="' . $merge_option . '" />';
  490. $params[] = 'modified[' . urlencode($filename) . ']=' . urlencode($merge_option);
  491. }
  492. $no_update = request_var('no_update', array(0 => ''));
  493. foreach ($no_update as $index => $filename)
  494. {
  495. $s_hidden_fields .= '<input type="hidden" name="no_update[]" value="' . htmlspecialchars($filename) . '" />';
  496. $params[] = 'no_update[]=' . urlencode($filename);
  497. }
  498. // Before the user is choosing his preferred method, let's create the content list...
  499. $update_list = $cache->get('_update_list');
  500. if ($update_list === false)
  501. {
  502. trigger_error($user->lang['NO_UPDATE_INFO'], E_USER_ERROR);
  503. }
  504. // Check if the conflicts data is valid
  505. if (sizeof($conflicts))
  506. {
  507. $conflict_filenames = array();
  508. foreach ($update_list['conflict'] as $files)
  509. {
  510. $conflict_filenames[] = $files['filename'];
  511. }
  512. $new_conflicts = array();
  513. foreach ($conflicts as $filename => $diff_method)
  514. {
  515. if (in_array($filename, $conflict_filenames))
  516. {
  517. $new_conflicts[$filename] = $diff_method;
  518. }
  519. }
  520. $conflicts = $new_conflicts;
  521. }
  522. // Build list for modifications
  523. if (sizeof($modified))
  524. {
  525. $modified_filenames = array();
  526. foreach ($update_list['modified'] as $files)
  527. {
  528. $modified_filenames[] = $files['filename'];
  529. }
  530. $new_modified = array();
  531. foreach ($modified as $filename => $diff_method)
  532. {
  533. if (in_array($filename, $modified_filenames))
  534. {
  535. $new_modified[$filename] = $diff_method;
  536. }
  537. }
  538. $modified = $new_modified;
  539. }
  540. // Check number of conflicting files, they need to be equal. For modified files the number can differ
  541. if (sizeof($update_list['conflict']) != sizeof($conflicts))
  542. {
  543. trigger_error($user->lang['MERGE_SELECT_ERROR'], E_USER_ERROR);
  544. }
  545. // Before we do anything, let us diff the files and store the raw file information "somewhere"
  546. $get_files = false;
  547. $file_list = $cache->get('_diff_files');
  548. $expected_files = $cache->get('_expected_files');
  549. if ($file_list === false || $file_list['status'] != -1)
  550. {
  551. $get_files = true;
  552. }
  553. if ($get_files)
  554. {
  555. if ($file_list === false)
  556. {
  557. $file_list = array(
  558. 'status' => 0,
  559. );
  560. }
  561. if (!isset($expected_files) || $expected_files === false)
  562. {
  563. $expected_files = array();
  564. }
  565. $processed = 0;
  566. foreach ($update_list as $status => $files)
  567. {
  568. if (!is_array($files))
  569. {
  570. continue;
  571. }
  572. foreach ($files as $file_struct)
  573. {
  574. // Skip this file if the user selected to not update it
  575. if (in_array($file_struct['filename'], $no_update))
  576. {
  577. $expected_files[$file_struct['filename']] = false;
  578. continue;
  579. }
  580. // Already handled... then skip of course...
  581. if (isset($file_list[$file_struct['filename']]))
  582. {
  583. continue;
  584. }
  585. // Refresh if we reach 5 diffs...
  586. if ($processed >= 5)
  587. {
  588. $cache->put('_diff_files', $file_list);
  589. if (!empty($_REQUEST['download']))
  590. {
  591. $params[] = 'download=1';
  592. }
  593. $redirect_url = append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files&amp;" . implode('&amp;', $params));
  594. meta_refresh(3, $redirect_url);
  595. $template->assign_vars(array(
  596. 'S_IN_PROGRESS' => true,
  597. 'L_IN_PROGRESS' => $user->lang['MERGING_FILES'],
  598. 'L_IN_PROGRESS_EXPLAIN' => $user->lang['MERGING_FILES_EXPLAIN'],
  599. ));
  600. return;
  601. }
  602. if (file_exists($phpbb_root_path . $file_struct['filename']))
  603. {
  604. $contents = file_get_contents($phpbb_root_path . $file_struct['filename']);
  605. if (isset($expected_files[$file_struct['filename']]) && md5($contents) == $expected_files[$file_struct['filename']])
  606. {
  607. continue;
  608. }
  609. }
  610. $original_filename = ($file_struct['custom']) ? $file_struct['original'] : $file_struct['filename'];
  611. switch ($status)
  612. {
  613. case 'modified':
  614. $option = (isset($modified[$file_struct['filename']])) ? $modified[$file_struct['filename']] : 0;
  615. switch ($option)
  616. {
  617. case MERGE_NO_MERGE_NEW:
  618. $contents = file_get_contents($this->new_location . $original_filename);
  619. break;
  620. case MERGE_NO_MERGE_MOD:
  621. $contents = file_get_contents($phpbb_root_path . $file_struct['filename']);
  622. break;
  623. default:
  624. $diff = $this->return_diff($this->old_location . $original_filename, $phpbb_root_path . $file_struct['filename'], $this->new_location . $original_filename);
  625. $contents = implode("\n", $diff->merged_output());
  626. unset($diff);
  627. break;
  628. }
  629. $expected_files[$file_struct['filename']] = md5($contents);
  630. $file_list[$file_struct['filename']] = '_file_' . md5($file_struct['filename']);
  631. $cache->put($file_list[$file_struct['filename']], base64_encode($contents));
  632. $file_list['status']++;
  633. $processed++;
  634. break;
  635. case 'conflict':
  636. $option = $conflicts[$file_struct['filename']];
  637. $contents = '';
  638. switch ($option)
  639. {
  640. case MERGE_NO_MERGE_NEW:
  641. $contents = file_get_contents($this->new_location . $original_filename);
  642. break;
  643. case MERGE_NO_MERGE_MOD:
  644. $contents = file_get_contents($phpbb_root_path . $file_struct['filename']);
  645. break;
  646. default:
  647. $diff = $this->return_diff($this->old_location . $original_filename, $phpbb_root_path . $file_struct['filename'], $this->new_location . $original_filename);
  648. if ($option == MERGE_NEW_FILE)
  649. {
  650. $contents = implode("\n", $diff->merged_new_output());
  651. }
  652. else if ($option == MERGE_MOD_FILE)
  653. {
  654. $contents = implode("\n", $diff->merged_orig_output());
  655. }
  656. else
  657. {
  658. unset($diff);
  659. break 2;
  660. }
  661. unset($diff);
  662. break;
  663. }
  664. $expected_files[$file_struct['filename']] = md5($contents);
  665. $file_list[$file_struct['filename']] = '_file_' . md5($file_struct['filename']);
  666. $cache->put($file_list[$file_struct['filename']], base64_encode($contents));
  667. $file_list['status']++;
  668. $processed++;
  669. break;
  670. }
  671. }
  672. }
  673. $cache->put('_expected_files', $expected_files);
  674. }
  675. $file_list['status'] = -1;
  676. $cache->put('_diff_files', $file_list);
  677. if (!empty($_REQUEST['download']))
  678. {
  679. $this->include_file('includes/functions_compress.' . $phpEx);
  680. $use_method = request_var('use_method', '');
  681. $methods = array('.tar');
  682. $available_methods = array('.tar.gz' => 'zlib', '.tar.bz2' => 'bz2', '.zip' => 'zlib');
  683. foreach ($available_methods as $type => $module)
  684. {
  685. if (!@extension_loaded($module))
  686. {
  687. continue;
  688. }
  689. $methods[] = $type;
  690. }
  691. // Let the user decide in which format he wants to have the pack
  692. if (!$use_method)
  693. {
  694. $this->page_title = 'SELECT_DOWNLOAD_FORMAT';
  695. $radio_buttons = '';
  696. foreach ($methods as $method)
  697. {
  698. $radio_buttons .= '<label><input type="radio"' . ((!$radio_buttons) ? ' id="use_method"' : '') . ' class="radio" value="' . $method . '" name="use_method" /> ' . $method . '</label>';
  699. }
  700. $template->assign_vars(array(
  701. 'S_DOWNLOAD_FILES' => true,
  702. 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files"),
  703. 'RADIO_BUTTONS' => $radio_buttons,
  704. 'S_HIDDEN_FIELDS' => $s_hidden_fields)
  705. );
  706. // To ease the update process create a file location map
  707. $update_list = $cache->get('_update_list');
  708. $script_path = ($config['force_server_vars']) ? (($config['script_path'] == '/') ? '/' : $config['script_path'] . '/') : $user->page['root_script_path'];
  709. foreach ($update_list as $status => $files)
  710. {
  711. if ($status == 'up_to_date' || $status == 'no_update' || $status == 'status')
  712. {
  713. continue;
  714. }
  715. foreach ($files as $file_struct)
  716. {
  717. if (in_array($file_struct['filename'], $no_update))
  718. {
  719. continue;
  720. }
  721. $template->assign_block_vars('location', array(
  722. 'SOURCE' => htmlspecialchars($file_struct['filename']),
  723. 'DESTINATION' => $script_path . htmlspecialchars($file_struct['filename']),
  724. ));
  725. }
  726. }
  727. return;
  728. }
  729. if (!in_array($use_method, $methods))
  730. {
  731. $use_method = '.tar';
  732. }
  733. $update_mode = 'download';
  734. }
  735. else
  736. {
  737. $this->include_file('includes/functions_transfer.' . $phpEx);
  738. // Choose FTP, if not available use fsock...
  739. $method = basename(request_var('method', ''));
  740. $submit = (isset($_POST['submit'])) ? true : false;
  741. $test_ftp_connection = request_var('test_connection', '');
  742. if (!$method || !class_exists($method))
  743. {
  744. $method = 'ftp';
  745. $methods = transfer::methods();
  746. if (!in_array('ftp', $methods))
  747. {
  748. $method = $methods[0];
  749. }
  750. }
  751. $test_connection = false;
  752. if ($test_ftp_connection || $submit)
  753. {
  754. $transfer = new $method(request_var('host', ''), request_var('username', ''), request_var('password', ''), request_var('root_path', ''), request_var('port', ''), request_var('timeout', ''));
  755. $test_connection = $transfer->open_session();
  756. // Make sure that the directory is correct by checking for the existence of common.php
  757. if ($test_connection === true)
  758. {
  759. // Check for common.php file
  760. if (!$transfer->file_exists($phpbb_root_path, 'common.' . $phpEx))
  761. {
  762. $test_connection = 'ERR_WRONG_PATH_TO_PHPBB';
  763. }
  764. }
  765. $transfer->close_session();
  766. // Make sure the login details are correct before continuing
  767. if ($submit && $test_connection !== true)
  768. {
  769. $submit = false;
  770. $test_ftp_connection = true;
  771. }
  772. }
  773. $s_hidden_fields .= build_hidden_fields(array('method' => $method));
  774. if (!$submit)
  775. {
  776. $this->page_title = 'SELECT_FTP_SETTINGS';
  777. if (!class_exists($method))
  778. {
  779. trigger_error('Method does not exist.', E_USER_ERROR);
  780. }
  781. $requested_data = call_user_func(array($method, 'data'));
  782. foreach ($requested_data as $data => $default)
  783. {
  784. $template->assign_block_vars('data', array(
  785. 'DATA' => $data,
  786. 'NAME' => $user->lang[strtoupper($method . '_' . $data)],
  787. 'EXPLAIN' => $user->lang[strtoupper($method . '_' . $data) . '_EXPLAIN'],
  788. 'DEFAULT' => (!empty($_REQUEST[$data])) ? request_var($data, '') : $default
  789. ));
  790. }
  791. $template->assign_vars(array(
  792. 'S_CONNECTION_SUCCESS' => ($test_ftp_connection && $test_connection === true) ? true : false,
  793. 'S_CONNECTION_FAILED' => ($test_ftp_connection && $test_connection !== true) ? true : false,
  794. 'ERROR_MSG' => ($test_ftp_connection && $test_connection !== true) ? $user->lang[$test_connection] : '',
  795. 'S_FTP_UPLOAD' => true,
  796. 'UPLOAD_METHOD' => $method,
  797. 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files"),
  798. 'U_DOWNLOAD_METHOD' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files&amp;download=1"),
  799. 'S_HIDDEN_FIELDS' => $s_hidden_fields,
  800. ));
  801. return;
  802. }
  803. $update_mode = 'upload';
  804. }
  805. // Now update the installation or download the archive...
  806. $download_filename = 'update_' . $this->update_info['version']['from'] . '_to_' . $this->update_info['version']['to'];
  807. $archive_filename = $download_filename . '_' . time() . '_' . unique_id();
  808. // Now init the connection
  809. if ($update_mode == 'download')
  810. {
  811. if (function_exists('phpbb_is_writable') && !phpbb_is_writable($phpbb_root_path . 'store/'))
  812. {
  813. trigger_error(sprintf('The directory “%s” is not writable.', $phpbb_root_path . 'store/'), E_USER_ERROR);
  814. }
  815. if ($use_method == '.zip')
  816. {
  817. $compress = new compress_zip('w', $phpbb_root_path . 'store/' . $archive_filename . $use_method);
  818. }
  819. else
  820. {
  821. $compress = new compress_tar('w', $phpbb_root_path . 'store/' . $archive_filename . $use_method, $use_method);
  822. }
  823. }
  824. else
  825. {
  826. $transfer = new $method(request_var('host', ''), request_var('username', ''), request_var('password', ''), request_var('root_path', ''), request_var('port', ''), request_var('timeout', ''));
  827. $transfer->open_session();
  828. }
  829. // Ok, go through the update list and do the operations based on their status
  830. foreach ($update_list as $status => $files)
  831. {
  832. if (!is_array($files))
  833. {
  834. continue;
  835. }
  836. foreach ($files as $file_struct)
  837. {
  838. // Skip this file if the user selected to not update it
  839. if (in_array($file_struct['filename'], $no_update))
  840. {
  841. continue;
  842. }
  843. $original_filename = ($file_struct['custom']) ? $file_struct['original'] : $file_struct['filename'];
  844. switch ($status)
  845. {
  846. case 'new':
  847. case 'new_conflict':
  848. case 'not_modified':
  849. if ($update_mode == 'download')
  850. {
  851. $compress->add_custom_file($this->new_location . $original_filename, $file_struct['filename']);
  852. }
  853. else
  854. {
  855. if ($status != 'new')
  856. {
  857. $transfer->rename($file_struct['filename'], $file_struct['filename'] . '.bak');
  858. }
  859. // New directory too?
  860. $dirname = dirname($file_struct['filename']);
  861. if ($dirname && !file_exists($phpbb_root_path . $dirname))
  862. {
  863. $transfer->make_dir($dirname);
  864. }
  865. $transfer->copy_file($this->new_location . $original_filename, $file_struct['filename']);
  866. }
  867. break;
  868. case 'modified':
  869. $contents = base64_decode($cache->get($file_list[$file_struct['filename']]));
  870. if ($update_mode == 'download')
  871. {
  872. $compress->add_data($contents, $file_struct['filename']);
  873. }
  874. else
  875. {
  876. // @todo add option to specify if a backup file should be created?
  877. $transfer->rename($file_struct['filename'], $file_struct['filename'] . '.bak');
  878. $transfer->write_file($file_struct['filename'], $contents);
  879. }
  880. break;
  881. case 'conflict':
  882. $contents = base64_decode($cache->get($file_list[$file_struct['filename']]));
  883. if ($update_mode == 'download')
  884. {
  885. $compress->add_data($contents, $file_struct['filename']);
  886. }
  887. else
  888. {
  889. $transfer->rename($file_struct['filename'], $file_struct['filename'] . '.bak');
  890. $transfer->write_file($file_struct['filename'], $contents);
  891. }
  892. break;
  893. }
  894. }
  895. }
  896. if ($update_mode == 'download')
  897. {
  898. $compress->close();
  899. $compress->download($archive_filename, $download_filename);
  900. @unlink($phpbb_root_path . 'store/' . $archive_filename . $use_method);
  901. exit;
  902. }
  903. else
  904. {
  905. $transfer->close_session();
  906. $template->assign_vars(array(
  907. 'S_UPLOAD_SUCCESS' => true,
  908. 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"))
  909. );
  910. return;
  911. }
  912. break;
  913. }
  914. }
  915. /**
  916. * Show file diff
  917. */
  918. function show_diff(&$update_list)
  919. {
  920. global $phpbb_root_path, $template, $user;
  921. $this->tpl_name = 'install_update_diff';
  922. // Got the diff template itself updated? If so, we are able to directly use it
  923. if (in_array('adm/style/install_update_diff.html', $this->update_info['files']))
  924. {
  925. $this->tpl_name = '../../install/update/new/adm/style/install_update_diff';
  926. }
  927. $this->page_title = 'VIEWING_FILE_DIFF';
  928. $status = request_var('status', '');
  929. $file = request_var('file', '');
  930. $diff_mode = request_var('diff_mode', 'inline');
  931. // First of all make sure the file is within our file update list with the correct status
  932. $found_entry = array();
  933. foreach ($update_list[$status] as $index => $file_struct)
  934. {
  935. if ($file_struct['filename'] === $file)
  936. {
  937. $found_entry = $update_list[$status][$index];
  938. }
  939. }
  940. if (empty($found_entry))
  941. {
  942. trigger_error($user->lang['FILE_DIFF_NOT_ALLOWED'], E_USER_ERROR);
  943. }
  944. // If the status is 'up_to_date' then we do not need to show a diff
  945. if ($status == 'up_to_date')
  946. {
  947. trigger_error($user->lang['FILE_ALREADY_UP_TO_DATE'], E_USER_ERROR);
  948. }
  949. $original_file = ($found_entry['custom']) ? $found_entry['original'] : $file;
  950. // Get the correct diff
  951. switch ($status)
  952. {
  953. case 'conflict':
  954. $option = request_var('op', 0);
  955. switch ($option)
  956. {
  957. case MERGE_NO_MERGE_NEW:
  958. case MERGE_NO_MERGE_MOD:
  959. $diff = $this->return_diff(array(), ($option == MERGE_NO_MERGE_NEW) ? $this->new_location . $original_file : $phpbb_root_path . $file);
  960. $template->assign_var('S_DIFF_NEW_FILE', true);
  961. $diff_mode = 'inline';
  962. $this->page_title = 'VIEWING_FILE_CONTENTS';
  963. break;
  964. // Merge differences and use new phpBB code for conflicted blocks
  965. case MERGE_NEW_FILE:
  966. case MERGE_MOD_FILE:
  967. $diff = $this->return_diff($this->old_location . $original_file, $phpbb_root_path . $file, $this->new_location . $original_file);
  968. $template->assign_vars(array(
  969. 'S_DIFF_CONFLICT_FILE' => true,
  970. 'NUM_CONFLICTS' => $diff->get_num_conflicts())
  971. );
  972. $diff = $this->return_diff($phpbb_root_path . $file, ($option == MERGE_NEW_FILE) ? $diff->merged_new_output() : $diff->merged_orig_output());
  973. break;
  974. // Download conflict file
  975. default:
  976. $diff = $this->return_diff($this->old_location . $original_file, $phpbb_root_path . $file, $this->new_location . $original_file);
  977. header('Pragma: no-cache');
  978. header("Content-Type: application/octetstream; name=\"$file\"");
  979. header("Content-disposition: attachment; filename=$file");
  980. @set_time_limit(0);
  981. echo implode("\n", $diff->get_conflicts_content());
  982. flush();
  983. exit;
  984. break;
  985. }
  986. break;
  987. case 'modified':
  988. $option = request_var('op', 0);
  989. switch ($option)
  990. {
  991. case MERGE_NO_MERGE_NEW:
  992. case MERGE_NO_MERGE_MOD:
  993. $diff = $this->return_diff(array(), ($option == MERGE_NO_MERGE_NEW) ? $this->new_location . $original_file : $phpbb_root_path . $file);
  994. $template->assign_var('S_DIFF_NEW_FILE', true);
  995. $diff_mode = 'inline';
  996. $this->page_title = 'VIEWING_FILE_CONTENTS';
  997. break;
  998. default:
  999. $diff = $this->return_diff($this->old_location . $original_file, $phpbb_root_path . $original_file, $this->new_location . $file);
  1000. $diff = $this->return_diff($phpbb_root_path . $file, $diff->merged_output());
  1001. break;
  1002. }
  1003. break;
  1004. case 'not_modified':
  1005. case 'new_conflict':
  1006. $diff = $this->return_diff($phpbb_root_path . $file, $this->new_location . $original_file);
  1007. break;
  1008. case 'new':
  1009. $diff = $this->return_diff(array(), $this->new_location . $original_file);
  1010. $template->assign_var('S_DIFF_NEW_FILE', true);
  1011. $diff_mode = 'inline';
  1012. $this->page_title = 'VIEWING_FILE_CONTENTS';
  1013. break;
  1014. }
  1015. $diff_mode_options = '';
  1016. foreach (array('side_by_side', 'inline', 'unified', 'raw') as $option)
  1017. {
  1018. $diff_mode_options .= '<option value="' . $option . '"' . (($diff_mode == $option) ? ' selected="selected"' : '') . '>' . $user->lang['DIFF_' . strtoupper($option)] . '</option>';
  1019. }
  1020. // Now the correct renderer
  1021. $render_class = 'diff_renderer_' . $diff_mode;
  1022. if (!class_exists($render_class))
  1023. {
  1024. trigger_error('Chosen diff mode is not supported', E_USER_ERROR);
  1025. }
  1026. $renderer = new $render_class();
  1027. $template->assign_vars(array(
  1028. 'DIFF_CONTENT' => $renderer->get_diff_content($diff),
  1029. 'DIFF_MODE' => $diff_mode,
  1030. 'S_DIFF_MODE_OPTIONS' => $diff_mode_options,
  1031. 'S_SHOW_DIFF' => true,
  1032. ));
  1033. unset($diff, $renderer);
  1034. }
  1035. /**
  1036. * Collect all file status infos we need for the update by diffing all files
  1037. */
  1038. function get_update_structure(&$update_list, $expected_files)
  1039. {
  1040. global $phpbb_root_path, $phpEx, $user;
  1041. if ($update_list === false)
  1042. {
  1043. $update_list = array(
  1044. 'up_to_date' => array(),
  1045. 'new' => array(),
  1046. 'not_modified' => array(),
  1047. 'modified' => array(),
  1048. 'new_conflict' => array(),
  1049. 'conflict' => array(),
  1050. 'no_update' => array(),
  1051. 'status' => 0,
  1052. );
  1053. }
  1054. /* if (!empty($this->update_info['custom']))
  1055. {
  1056. foreach ($this->update_info['custom'] as $original_file => $file_ary)
  1057. {
  1058. foreach ($file_ary as $index => $file)
  1059. {
  1060. $this->make_update_diff($update_list, $original_file, $file, true);
  1061. }
  1062. }
  1063. } */
  1064. // Get a list of those files which are completely new by checking with file_exists...
  1065. $num_bytes_processed = 0;
  1066. foreach ($this->update_info['files'] as $index => $file)
  1067. {
  1068. if (is_int($update_list['status']) && $index < $update_list['status'])
  1069. {
  1070. continue;
  1071. }
  1072. if ($num_bytes_processed >= 500 * 1024)
  1073. {
  1074. return;
  1075. }
  1076. if (!file_exists($phpbb_root_path . $file))
  1077. {
  1078. // Make sure the update files are consistent by checking if the file is in new_files...
  1079. if (!file_exists($this->new_location . $file))
  1080. {
  1081. trigger_error($user->lang['INCOMPLETE_UPDATE_FILES'], E_USER_ERROR);
  1082. }
  1083. // If the file exists within the old directory the file got removed and we will write it back
  1084. // not a biggie, but we might want to state this circumstance separately later.
  1085. // if (file_exists($this->old_location . $file))
  1086. // {
  1087. // $update_list['removed'][] = $file;
  1088. // }
  1089. /* Only include a new file as new if the underlying path exist
  1090. // The path normally do not exist if the original style or language has been removed
  1091. if (file_exists($phpbb_root_path . dirname($file)))
  1092. {
  1093. $this->get_custom_info($update_list['new'], $file);
  1094. $update_list['new'][] = array('filename' => $file, 'custom' => false);
  1095. }
  1096. else
  1097. {
  1098. // Do not include style-related or language-related content
  1099. if (strpos($file, 'styles/') !== 0 && strpos($file, 'language/') !== 0)
  1100. {
  1101. $update_list['no_update'][] = $file;
  1102. }
  1103. }*/
  1104. if (file_exists($phpbb_root_path . dirname($file)) || (strpos($file, 'styles/') !== 0 && strpos($file, 'language/') !== 0))
  1105. {
  1106. $this->get_custom_info($update_list['new'], $file);
  1107. $update_list['new'][] = array('filename' => $file, 'custom' => false);
  1108. }
  1109. // unset($this->update_info['files'][$index]);
  1110. }
  1111. else
  1112. {
  1113. // not modified?
  1114. $this->make_update_diff($update_list, $file, $file, $expected_files);
  1115. }
  1116. $num_bytes_processed += (file_exists($this->new_location . $file)) ? filesize($this->new_location . $file) : 100 * 1024;
  1117. $update_list['status']++;
  1118. }
  1119. $update_list['status'] = -1;
  1120. /* if (!sizeof($this->update_info['files']))
  1121. {
  1122. return $update_list;
  1123. }
  1124. // Now diff the remaining files to get information about their status (not modified/modified/up-to-date)
  1125. // not modified?
  1126. foreach ($this->update_info['files'] as $index => $file)
  1127. {
  1128. $this->make_update_diff($update_list, $file, $file);
  1129. }
  1130. // Now to the styles...
  1131. if (empty($this->update_info['custom']))
  1132. {
  1133. return $update_list;
  1134. }
  1135. foreach ($this->update_info['custom'] as $original_file => $file_ary)
  1136. {
  1137. foreach ($file_ary as $index => $file)
  1138. {
  1139. $this->make_update_diff($update_list, $original_file, $file, true);
  1140. }
  1141. }
  1142. return $update_list;*/
  1143. }
  1144. /**
  1145. * Compare files for storage in update_list
  1146. */
  1147. function make_update_diff(&$update_list, $original_file, $file, $expected_files, $custom = false)
  1148. {
  1149. global $phpbb_root_path, $user;
  1150. $update_ary = array('filename' => $file, 'custom' => $custom, 'as_expected' => false);
  1151. if ($custom)
  1152. {
  1153. $update_ary['original'] = $original_file;
  1154. }
  1155. if (file_exists($phpbb_root_path . $file))
  1156. {
  1157. $content = file_get_contents($phpbb_root_path . $file);
  1158. if (isset($expected_files[$file]) && // the user already selected what to do with this file
  1159. ($expected_files[$file] === false || // the user wanted this file to stay the same, so just assume it's alright
  1160. $expected_files[$file] === md5($content)))
  1161. {
  1162. // the file contains what it was supposed to contain after the merge
  1163. $update_ary['as_expected'] = true;
  1164. $update_ary['was_ignored'] = ($expected_files[$file] === false);
  1165. $update_list['up_to_date'][] = $update_ary;
  1166. return;
  1167. }
  1168. }
  1169. // we only want to know if the files are successfully merged and newlines could result in errors (duplicate addition of lines and such things)
  1170. // Therefore we check for empty diffs with two methods, preserving newlines and not preserving them (which mostly works best, therefore the first option)
  1171. // On a successfull update the new location file exists but the old one does not exist.
  1172. // Check for this circumstance, the new file need to be up-to-date with the current file then...
  1173. if (!file_exists($this->old_location . $original_file) && file_exists($this->new_location . $original_file) && file_exists($phpbb_root_path . $file))
  1174. {
  1175. $tmp = array(
  1176. 'file1' => file_get_contents($this->new_location . $original_file),
  1177. 'file2' => $content,
  1178. );
  1179. // We need to diff the contents here to make sure the file is really the one we expect
  1180. $diff = new diff($tmp['file1'], $tmp['file2'], false);
  1181. $empty = $diff->is_empty();
  1182. unset($tmp, $diff);
  1183. // if there are no differences we have an up-to-date file...
  1184. if ($empty)
  1185. {
  1186. $update_list['up_to_date'][] = $update_ary;
  1187. return;
  1188. }
  1189. // If no other status matches we have another file in the way...
  1190. $update_list['new_conflict'][] = $update_ary;
  1191. return;
  1192. }
  1193. // Old file removed?
  1194. if (file_exists($this->old_location . $original_file) && !file_exists($this->new_location . $original_file))
  1195. {
  1196. return;
  1197. }
  1198. // Check for existance, else abort immediately
  1199. if (!file_exists($this->old_location . $original_file) || !file_exists($this->new_location . $original_file))
  1200. {
  1201. trigger_error($user->lang['INCOMPLETE_UPDATE_FILES'], E_USER_ERROR);
  1202. }
  1203. $preserve_cr_ary = array(false, true);
  1204. foreach ($preserve_cr_ary as $preserve_cr)
  1205. {
  1206. $tmp = array(
  1207. 'file1' => file_get_contents($this->old_location . $original_file),
  1208. 'file2' => $content,
  1209. );
  1210. // We need to diff the contents here to make sure the file is really the one we expect
  1211. $diff = new diff($tmp['file1'], $tmp['file2'], $preserve_cr);
  1212. $empty_1 = $diff->is_empty();
  1213. unset($tmp, $diff);
  1214. $tmp = array(
  1215. 'file1' => file_get_contents($this->new_location . $original_file),
  1216. 'file2' => $content,
  1217. );
  1218. $diff = new diff($tmp['file1'], $tmp['file2'], $preserve_cr);
  1219. $empty_2 = $diff->is_empty();
  1220. unset($tmp, $diff);
  1221. // If the file is not modified we are finished here...
  1222. if ($empty_1)
  1223. {
  1224. // Further check if it is already up to date - it could happen that non-modified files
  1225. // slip through
  1226. if ($empty_2)
  1227. {
  1228. $update_list['up_to_date'][] = $update_ary;
  1229. return;
  1230. }
  1231. $update_list['not_modified'][] = $update_ary;
  1232. return;
  1233. }
  1234. // If the file had been modified then we need to check if it is already up to date
  1235. // if there are no differences we have an up-to-date file...
  1236. if ($empty_2)
  1237. {
  1238. $update_list['up_to_date'][] = $update_ary;
  1239. return;
  1240. }
  1241. }
  1242. $conflicts = false;
  1243. foreach ($preserve_cr_ary as $preserve_cr)
  1244. {
  1245. // if the file is modified we try to make sure a merge succeed
  1246. $tmp = array(
  1247. 'orig' => file_get_contents($this->old_location . $original_file),
  1248. 'final1' => file_get_contents($phpbb_root_path . $file),
  1249. 'final2' => file_get_contents($this->new_location . $original_file),
  1250. );
  1251. $diff = new diff3($tmp['orig'], $tmp['final1'], $tmp['final2'], $preserve_cr);
  1252. unset($tmp);
  1253. if (!$diff->get_num_conflicts())
  1254. {
  1255. $tmp = array(
  1256. 'file1' => file_get_contents($phpbb_root_path . $file),
  1257. 'file2' => implode("\n", $diff->merged_output()),
  1258. );
  1259. // now compare the merged output with the original file to see if the modified file is up to date
  1260. $diff2 = new diff($tmp['file1'], $tmp['file2'], $preserve_cr);
  1261. $empty = $diff2->is_empty();
  1262. unset($diff, $diff2);
  1263. if ($empty)
  1264. {
  1265. $update_list['up_to_date'][] = $update_ary;
  1266. return;
  1267. }
  1268. // If we preserve cr tag it as modified because the conflict would not show in this mode anyway
  1269. if ($preserve_cr)
  1270. {
  1271. $update_list['modified'][] = $update_ary;
  1272. return;
  1273. }
  1274. }
  1275. else
  1276. {
  1277. // There is one special case... users having merged with a conflicting file... we need to check this
  1278. $tmp = array(
  1279. 'file1' => file_get_contents($phpbb_root_path . $file),
  1280. 'file2' => implode("\n", $diff->merged_new_output()),
  1281. );
  1282. $diff2 = new diff($tmp['file1'], $tmp['file2'], $preserve_cr);
  1283. $empty = $diff2->is_empty();
  1284. if (!$empty)
  1285. {
  1286. unset($tmp, $diff2);
  1287. // We check if the user merged with his output
  1288. $tmp = array(
  1289. 'file1' => file_get_contents($phpbb_root_path . $file),
  1290. 'file2' => implode("\n", $diff->merged_orig_output()),
  1291. );
  1292. $diff2 = new diff($tmp['file1'], $tmp['file2'], $preserve_cr);
  1293. $empty = $diff2->is_empty();
  1294. }
  1295. if (!$empty)
  1296. {
  1297. $conflicts = $diff->get_num_conflicts();
  1298. }
  1299. unset($diff, $diff2);
  1300. if ($empty)
  1301. {
  1302. // A conflict got resolved...
  1303. $update_list['up_to_date'][] = $update_ary;
  1304. return;
  1305. }
  1306. }
  1307. }
  1308. if ($conflicts !== false)
  1309. {
  1310. $update_ary['conflicts'] = $conflicts;
  1311. $update_list['conflict'][] = $update_ary;
  1312. return;
  1313. }
  1314. // If no other status matches we have a modified file...
  1315. $update_list['modified'][] = $update_ary;
  1316. }
  1317. /**
  1318. * Update update_list with custom new files
  1319. */
  1320. f

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