/** * {@inheritdoc} */ public function run() { // Include diff engine $this->update_helper->include_file('includes/diff/diff.' . $this->php_ext); $this->update_helper->include_file('includes/diff/engine.' . $this->php_ext); // Set up basic vars $old_path = $this->update_helper->get_path_to_old_update_files(); $new_path = $this->update_helper->get_path_to_new_update_files(); $files_to_diff = $this->installer_config->get('update_files', array()); $files_to_diff = $files_to_diff['update_with_diff']; // Set progress bar $this->iohandler->set_task_count(count($files_to_diff), true); $this->iohandler->set_progress('UPDATE_FILE_DIFF', 0); $progress_count = $this->installer_config->get('file_diff_update_count', 0); // Recover progress $progress_key = $this->installer_config->get('differ_progress_key', -1); $progress_recovered = $progress_key === -1; $merge_conflicts = $this->installer_config->get('merge_conflict_list', array()); foreach ($files_to_diff as $key => $filename) { if ($progress_recovered === false) { if ($progress_key === $key) { $progress_recovered = true; } continue; } // Read in files' content $file_contents = array(); // Handle the special case when user created a file with the filename that is now new in the core $file_contents[0] = file_exists($old_path . $filename) ? file_get_contents($old_path . $filename) : ''; $filenames = array($this->phpbb_root_path . $filename, $new_path . $filename); foreach ($filenames as $file_to_diff) { $file_contents[] = file_get_contents($file_to_diff); if ($file_contents[sizeof($file_contents) - 1] === false) { $this->iohandler->add_error_message(array('FILE_DIFFER_ERROR_FILE_CANNOT_BE_READ', $files_to_diff)); unset($file_contents); throw new user_interaction_required_exception(); } } $diff = new \diff3($file_contents[0], $file_contents[1], $file_contents[2]); unset($file_contents); // Handle conflicts if ($diff->get_num_conflicts() !== 0) { $merge_conflicts[] = $filename; } // Save merged output $this->cache->put('_file_' . md5($filename), base64_encode(implode("\n", $diff->merged_output()))); unset($diff); $progress_count++; $this->iohandler->set_progress('UPDATE_FILE_DIFF', $progress_count); if ($this->installer_config->get_time_remaining() <= 0 || $this->installer_config->get_memory_remaining() <= 0) { // Save differ progress $this->installer_config->set('differ_progress_key', $key); $this->installer_config->set('merge_conflict_list', $merge_conflicts); $this->installer_config->set('file_diff_update_count', $progress_count); // Request refresh throw new resource_limit_reached_exception(); } } $this->iohandler->finish_progress('ALL_FILES_DIFFED'); $this->installer_config->set('merge_conflict_list', $merge_conflicts); }
function editPage() { global $WikiTheme; $saveFailed = false; $tokens =& $this->tokens; $tokens['PAGE_LOCKED_MESSAGE'] = ''; $tokens['CONCURRENT_UPDATE_MESSAGE'] = ''; $r =& $this->request; if (isset($r->args['pref']['editWidth']) and $r->getPref('editWidth') != $r->args['pref']['editWidth']) { $r->_prefs->set('editWidth', $r->args['pref']['editWidth']); } if (isset($r->args['pref']['editHeight']) and $r->getPref('editHeight') != $r->args['pref']['editHeight']) { $r->_prefs->set('editHeight', $r->args['pref']['editHeight']); } if (!$this->canEdit()) { if ($this->isInitialEdit()) { return $this->viewSource(); } $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage(); } elseif ($r->getArg('save_and_redirect_to') != "") { if (ENABLE_CAPTCHA && $this->Captcha->Failed()) { $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML::p(HTML::h1($this->Captcha->failed_msg)); } elseif ($this->savePage()) { // noreturn $r->redirect(WikiURL($r->getArg('save_and_redirect_to'))); return true; // Page saved. } $saveFailed = true; } elseif ($this->editaction == 'save') { if (ENABLE_CAPTCHA && $this->Captcha->Failed()) { $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML::p(HTML::h1($this->Captcha->failed_msg)); } elseif ($this->savePage()) { return true; // Page saved. } else { $saveFailed = true; } } if ($saveFailed and $this->isConcurrentUpdate()) { // Get the text of the original page, and the two conflicting edits // The diff3 class takes arrays as input. So retrieve content as // an array, or convert it as necesary. $orig = $this->page->getRevision($this->_currentVersion); // FIXME: what if _currentVersion has be deleted? $orig_content = $orig->getContent(); $this_content = explode("\n", $this->_content); $other_content = $this->current->getContent(); include_once "lib/diff3.php"; $diff = new diff3($orig_content, $this_content, $other_content); $output = $diff->merged_output(_("Your version"), _("Other version")); // Set the content of the textarea to the merged diff // output, and update the version $this->_content = implode("\n", $output); $this->_currentVersion = $this->current->getVersion(); $this->version = $this->_currentVersion; $unresolved = $diff->ConflictingBlocks; $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage($unresolved); } elseif ($saveFailed && !$this->_isSpam) { $tokens['CONCURRENT_UPDATE_MESSAGE'] = HTML(HTML::h2(_("Some internal editing error")), HTML::p(_("Your are probably trying to edit/create an invalid version of this page.")), HTML::p(HTML::em(_("&version=-1 might help.")))); } if ($this->editaction == 'edit_convert') { $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview(); } if ($this->editaction == 'preview') { $tokens['PREVIEW_CONTENT'] = $this->getPreview(); } // FIXME: convert to _MESSAGE? // FIXME: NOT_CURRENT_MESSAGE? $tokens = array_merge($tokens, $this->getFormElements()); if (ENABLE_EDIT_TOOLBAR) { include_once "lib/EditToolbar.php"; $toolbar = new EditToolbar(); $tokens = array_merge($tokens, $toolbar->getTokens()); } return $this->output('editpage', _("Edit: %s")); }
/** * Compare files for storage in update_list */ function make_update_diff(&$update_list, $original_file, $file, $custom = false) { global $phpbb_root_path, $user; $update_ary = array('filename' => $file, 'custom' => $custom); if ($custom) { $update_ary['original'] = $original_file; } // On a successfull update the new location file exists but the old one does not exist. // Check for this circumstance, the new file need to be up-to-date with the current file then... if (!file_exists($this->old_location . $original_file) && file_exists($this->new_location . $original_file) && file_exists($phpbb_root_path . $file)) { $tmp = array( 'file1' => file_get_contents($this->new_location . $original_file), 'file2' => file_get_contents($phpbb_root_path . $file), ); // We need to diff the contents here to make sure the file is really the one we expect $diff = new diff($tmp['file1'], $tmp['file2'], false); $empty = $diff->is_empty(); unset($tmp, $diff); // if there are no differences we have an up-to-date file... if ($empty) { $update_list['up_to_date'][] = $update_ary; return; } // If no other status matches we have another file in the way... $update_list['new_conflict'][] = $update_ary; return; } // Old file removed? if (file_exists($this->old_location . $original_file) && !file_exists($this->new_location . $original_file)) { return; } // Check for existance, else abort immediately if (!file_exists($this->old_location . $original_file) || !file_exists($this->new_location . $original_file)) { trigger_error($user->lang['INCOMPLETE_UPDATE_FILES'], E_USER_ERROR); } $tmp = array( 'file1' => file_get_contents($this->old_location . $original_file), 'file2' => file_get_contents($phpbb_root_path . $file), ); // We need to diff the contents here to make sure the file is really the one we expect $diff = new diff($tmp['file1'], $tmp['file2'], false); $empty_1 = $diff->is_empty(); unset($tmp, $diff); $tmp = array( 'file1' => file_get_contents($this->new_location . $original_file), 'file2' => file_get_contents($phpbb_root_path . $file), ); // We need to diff the contents here to make sure the file is really the one we expect $diff = new diff($tmp['file1'], $tmp['file2'], false); $empty_2 = $diff->is_empty(); unset($tmp, $diff); // If the file is not modified we are finished here... if ($empty_1) { // Further check if it is already up to date - it could happen that non-modified files // slip through if ($empty_2) { $update_list['up_to_date'][] = $update_ary; return; } $update_list['not_modified'][] = $update_ary; return; } // If the file had been modified then we need to check if it is already up to date // if there are no differences we have an up-to-date file... if ($empty_2) { $update_list['up_to_date'][] = $update_ary; return; } // if the file is modified we try to make sure a merge succeed $tmp = array( 'file1' => file_get_contents($this->old_location . $original_file), 'file2' => file_get_contents($phpbb_root_path . $file), 'file3' => file_get_contents($this->new_location . $original_file), ); $diff = new diff3($tmp['file1'], $tmp['file2'], $tmp['file3'], false); unset($tmp); if ($diff->merged_output(false, false, false, true)) { $update_ary['conflicts'] = $diff->_conflicting_blocks; // There is one special case... users having merged with a conflicting file... we need to check this $tmp = array( 'file1' => file_get_contents($phpbb_root_path . $file), 'file2' => implode("\n", $diff->merged_orig_output()), ); $diff = new diff($tmp['file1'], $tmp['file2'], false); $empty = $diff->is_empty(); if ($empty) { unset($update_ary['conflicts']); unset($diff); $update_list['up_to_date'][] = $update_ary; return; } $update_list['conflict'][] = $update_ary; unset($diff); return; } $tmp = array( 'file1' => file_get_contents($phpbb_root_path . $file), 'file2' => implode("\n", $diff->merged_output()), ); // now compare the merged output with the original file to see if the modified file is up to date $diff = new diff($tmp['file1'], $tmp['file2'], false); $empty = $diff->is_empty(); if ($empty) { unset($diff); $update_list['up_to_date'][] = $update_ary; return; } // If no other status matches we have a modified file... $update_list['modified'][] = $update_ary; }
/** * Compare files for storage in update_list */ function make_update_diff(&$update_list, $original_file, $file, $custom = false) { global $phpbb_root_path, $user; $update_ary = array('filename' => $file, 'custom' => $custom); if ($custom) { $update_ary['original'] = $original_file; } // we only want to know if the files are successfully merged and newlines could result in errors (duplicate addition of lines and such things) // Therefore we check for empty diffs with two methods, preserving newlines and not preserving them (which mostly works best, therefore the first option) // On a successfull update the new location file exists but the old one does not exist. // Check for this circumstance, the new file need to be up-to-date with the current file then... if (!file_exists($this->old_location . $original_file) && file_exists($this->new_location . $original_file) && file_exists($phpbb_root_path . $file)) { $tmp = array( 'file1' => file_get_contents($this->new_location . $original_file), 'file2' => file_get_contents($phpbb_root_path . $file), ); // We need to diff the contents here to make sure the file is really the one we expect $diff = new diff($tmp['file1'], $tmp['file2'], false); $empty = $diff->is_empty(); unset($tmp, $diff); // if there are no differences we have an up-to-date file... if ($empty) { $update_list['up_to_date'][] = $update_ary; return; } // If no other status matches we have another file in the way... $update_list['new_conflict'][] = $update_ary; return; } // Old file removed? if (file_exists($this->old_location . $original_file) && !file_exists($this->new_location . $original_file)) { return; } // Check for existance, else abort immediately if (!file_exists($this->old_location . $original_file) || !file_exists($this->new_location . $original_file)) { trigger_error($user->lang['INCOMPLETE_UPDATE_FILES'], E_USER_ERROR); } $preserve_cr_ary = array(false, true); foreach ($preserve_cr_ary as $preserve_cr) { $tmp = array( 'file1' => file_get_contents($this->old_location . $original_file), 'file2' => file_get_contents($phpbb_root_path . $file), ); // We need to diff the contents here to make sure the file is really the one we expect $diff = new diff($tmp['file1'], $tmp['file2'], $preserve_cr); $empty_1 = $diff->is_empty(); unset($tmp, $diff); $tmp = array( 'file1' => file_get_contents($this->new_location . $original_file), 'file2' => file_get_contents($phpbb_root_path . $file), ); $diff = new diff($tmp['file1'], $tmp['file2'], $preserve_cr); $empty_2 = $diff->is_empty(); unset($tmp, $diff); // If the file is not modified we are finished here... if ($empty_1) { // Further check if it is already up to date - it could happen that non-modified files // slip through if ($empty_2) { $update_list['up_to_date'][] = $update_ary; return; } $update_list['not_modified'][] = $update_ary; return; } // If the file had been modified then we need to check if it is already up to date // if there are no differences we have an up-to-date file... if ($empty_2) { $update_list['up_to_date'][] = $update_ary; return; } } $conflicts = false; foreach ($preserve_cr_ary as $preserve_cr) { // if the file is modified we try to make sure a merge succeed $tmp = array( 'orig' => file_get_contents($this->old_location . $original_file), 'final1' => file_get_contents($phpbb_root_path . $file), 'final2' => file_get_contents($this->new_location . $original_file), ); $diff = new diff3($tmp['orig'], $tmp['final1'], $tmp['final2'], $preserve_cr); unset($tmp); if (!$diff->get_num_conflicts()) { $tmp = array( 'file1' => file_get_contents($phpbb_root_path . $file), 'file2' => implode("\n", $diff->merged_output()), ); // now compare the merged output with the original file to see if the modified file is up to date $diff2 = new diff($tmp['file1'], $tmp['file2'], $preserve_cr); $empty = $diff2->is_empty(); unset($diff, $diff2); if ($empty) { $update_list['up_to_date'][] = $update_ary; return; } // If we preserve cr tag it as modified because the conflict would not show in this mode anyway if ($preserve_cr) { $update_list['modified'][] = $update_ary; return; } } else { // There is one special case... users having merged with a conflicting file... we need to check this $tmp = array( 'file1' => file_get_contents($phpbb_root_path . $file), 'file2' => implode("\n", $diff->merged_new_output()), ); $diff2 = new diff($tmp['file1'], $tmp['file2'], $preserve_cr); $empty = $diff2->is_empty(); if (!$empty) { unset($tmp, $diff2); // We check if the user merged with his output $tmp = array( 'file1' => file_get_contents($phpbb_root_path . $file), 'file2' => implode("\n", $diff->merged_orig_output()), ); $diff2 = new diff($tmp['file1'], $tmp['file2'], $preserve_cr); $empty = $diff2->is_empty(); } if (!$empty) { $conflicts = $diff->get_num_conflicts(); } unset($diff, $diff2); if ($empty) { // A conflict got resolved... $update_list['up_to_date'][] = $update_ary; return; } } } if ($conflicts !== false) { $update_ary['conflicts'] = $conflicts; $update_list['conflict'][] = $update_ary; return; } // If no other status matches we have a modified file... $update_list['modified'][] = $update_ary; }