diff --git a/build/build_diff.php b/build/build_diff.php new file mode 100755 index 0000000000..c8a40f4f5e --- /dev/null +++ b/build/build_diff.php @@ -0,0 +1,408 @@ +#!/usr/bin/env php + 'tar -czf', + 'tar.bz2' => 'tar -cjf', + 'zip' => 'zip -r' + ); + + chdir($location . '/save/' . $s_name); + foreach ($compress_programs as $extension => $compress_command) + { + echo "Packaging code changes for $extension\n"; + run_command("rm ./../../release_files/{$code_changes_filename}.{$extension}"); + flush(); + + // Build Package + run_command("$compress_command ./../../release_files/{$code_changes_filename}.{$extension} *"); + + // Build MD5 Sum + run_command("md5sum ./../../release_files/{$code_changes_filename}.{$extension} > ./../../release_files/{$code_changes_filename}.{$extension}.md5"); + flush(); + } +} + +/** +* $output_format can be: language, prosilver and subsilver2 +*/ +function build_code_changes($output_format) +{ + global $substitute_new, $substitute_old, $simple_name_old, $simple_name_new, $echo_changes, $package_changed_files, $location, $debug_file, $s_name; + + // Global array holding the data entries + $data = array( + 'header' => array(), + 'diff' => array(), + ); + + // Read diff file and prepare the output filedata... + //$patch_filename = '../new_version/patches/phpBB-' . $substitute_old . '_to_' . $substitute_new . '.patch'; + $release_filename = 'phpbb-' . $substitute_old . '_to_' . $substitute_new . '_' . $output_format . '.txt'; + + if (!$package_changed_files) + { + if (!$echo_changes) + { + $fp = fopen('save/' . $s_name . '/' . $output_format . '/' . $release_filename, 'wb'); + + if (!$fp) + { + die('Unable to create ' . $release_filename); + } + } + } + + include_once($location . '/build_helper.php'); + $package = new build_package(array($substitute_old, $substitute_new), false); + + $titles = array( + 'language' => 'phpBB ' . $substitute_old . ' to phpBB ' . $substitute_new . ' Language Pack Changes', + 'prosilver' => 'phpBB ' . $substitute_old . ' to phpBB ' . $substitute_new . ' prosilver Changes', + 'subsilver2' => 'phpBB ' . $substitute_old . ' to phpBB ' . $substitute_new . ' subsilver2 Changes', + ); + + $data['header'] = array( + 'title' => $titles[$output_format], + 'intro' => ' + +These are the ' . $titles[$output_format] . ' summed up into a little Mod. These changes are only partial and do not include any code changes, therefore not meant for updating phpBB. + + ', + 'included_files' => array(), + ); + + // We collect the files we want to diff first (ironically we grab this from a diff file) + if (!$echo_changes) + { + echo "\n\nCollecting Filenames:"; + } + + // We re-create the patch file + foreach ($package->old_packages as $_package_name => $dest_package_filename) + { + chdir($package->locations['old_versions']); + + if (!$echo_changes) + { + echo "\n\n" . 'Creating patch/diff files for phpBB-' . $dest_package_filename . $package->get('new_version_number'); + } + + $dest_package_filename = $location . '/save/' . $s_name . '/phpBB-' . $dest_package_filename . $package->get('new_version_number') . '.patch'; + $package->run_command('diff ' . $package->diff_options . ' ' . $_package_name . ' ' . $package->get('simple_name') . ' > ' . $dest_package_filename); + + // Parse this diff to determine file changes from the checked versions and save them + $result = $package->collect_diff_files($dest_package_filename, $_package_name); + $package->run_command('rm ' . $dest_package_filename); + } + + chdir($location); + + $filenames = array(); + foreach ($result['files'] as $filename) + { + if ($debug_file !== false && $filename != $debug_file) + { + continue; + } + + // Decide which files to compare... + switch ($output_format) + { + case 'language': + if (strpos($filename, 'language/en/') !== 0) + { + continue 2; + } + break; + + case 'prosilver': + if (strpos($filename, 'styles/prosilver/') !== 0) + { + continue 2; + } + break; + + case 'subsilver2': + if (strpos($filename, 'styles/subsilver2/') !== 0) + { + continue 2; + } + break; + } + + if (!file_exists($location . '/old_versions/' . $simple_name_old . '/' . $filename)) + { + // New file... include it + $data['header']['included_files'][] = array( + 'old' => $location . '/old_versions/' . $simple_name_old . '/' . $filename, + 'new' => $location . '/old_versions/' . $simple_name_new . '/' . $filename, + 'phpbb_filename' => $filename, + ); + continue; + } + + $filenames[] = array( + 'old' => $location . '/old_versions/' . $simple_name_old . '/' . $filename, + 'new' => $location . '/old_versions/' . $simple_name_new . '/' . $filename, + 'phpbb_filename' => $filename, + ); + } + + // Now let us go through the filenames list and create a more comprehensive diff + if (!$echo_changes) + { + fwrite($fp, build_header($output_format, $filenames, $data['header'])); + } + else + { + //echo build_header('text', $filenames, $data['header']); + } + + // Copy files... + $files_to_copy = array(); + + foreach ($data['header']['included_files'] as $filename) + { + $files_to_copy[] = $filename['phpbb_filename']; + } + + // First step is to copy the new version over (clean structure) + if (!$echo_changes && sizeof($files_to_copy)) + { + foreach ($files_to_copy as $file) + { + // Create directory? + $dirname = dirname($file); + + if ($dirname) + { + $dirname = explode('/', $dirname); + $__dir = array(); + + foreach ($dirname as $i => $dir) + { + $__dir[] = $dir; + run_command("mkdir -p $location/save/" . $s_name . '/' . $output_format . '/' . implode('/', $__dir)); + } + } + + $source_file = $location . '/new_version/phpBB3/' . $file; + $dest_file = $location . '/save/' . $s_name . '/' . $output_format . '/'; + $dest_file .= $file; + + $command = "cp -p $source_file $dest_file"; + $result = trim(`$command`); + echo "- Copied File: " . $source_file . " -> " . $dest_file . "\n"; + } + } + + include_once('diff_class.php'); + + if (!$echo_changes) + { + echo "\n\nDiffing Codebases:"; + } + + foreach ($filenames as $file_ary) + { + if (!file_exists($file_ary['old'])) + { + $lines1 = array(); + } + else + { + $lines1 = file($file_ary['old']); + } + $lines2 = file($file_ary['new']); + + if (!sizeof($lines1)) + { + // New File + } + else + { + $diff = new Diff($lines1, $lines2); + $fmt = new BBCodeDiffFormatter(false, 5, $debug_file); + + if (!$echo_changes) + { + fwrite($fp, $fmt->format_open($file_ary['phpbb_filename'])); + fwrite($fp, $fmt->format($diff, $lines1)); + fwrite($fp, $fmt->format_close($file_ary['phpbb_filename'])); + } + else + { + echo $fmt->format_open($file_ary['phpbb_filename']); + echo $fmt->format($diff, $lines1); + echo $fmt->format_close($file_ary['phpbb_filename']); + } + + if ($debug_file !== false) + { + echo $fmt->format_open($file_ary['phpbb_filename']); + echo $fmt->format($diff, $lines1); + echo $fmt->format_close($file_ary['phpbb_filename']); + exit; + } + } + } + + if (!$echo_changes) + { + fwrite($fp, build_footer($output_format)); + + // Close file + fclose($fp); + + chmod('save/' . $s_name . '/' . $output_format . '/' . $release_filename, 0666); + } + else + { + echo build_footer($output_format); + } +} + +/** +* Build Footer +*/ +function build_footer($mode) +{ + $html = ''; + + $html .= "# \n"; + $html .= "#-----[ SAVE/CLOSE ALL FILES ]------------------------------------------ \n"; + $html .= "# \n"; + $html .= "# EoM"; + + return $html; +} + +/** +* Build Header +*/ +function build_header($mode, $filenames, $header) +{ + global $substitute_old; + + $html = ''; + + $html .= "############################################################## \n"; + $html .= "## Title: " . $header['title'] . "\n"; + $html .= "## Author: naderman < naderman@phpbb.com > (Nils Adermann) http://www.phpbb.com \n"; + $html .= "## Description: \n"; + + $intr = explode("\n", $header['intro']); + $introduction = ''; + foreach ($intr as $_line) + { + $introduction .= wordwrap($_line, 80) . "\n"; + } + $intr = explode("\n", $introduction); + + foreach ($intr as $_line) + { + $html .= "## " . $_line . "\n"; + } + $html .= "## \n"; + $html .= "## Files To Edit: \n"; + + foreach ($filenames as $file_ary) + { + $html .= "## " . $file_ary['phpbb_filename'] . "\n"; + } + $html .= "##\n"; + if (sizeof($header['included_files'])) + { + $html .= "## Included Files: \n"; + foreach ($header['included_files'] as $filename) + { + $html .= "## {$filename['phpbb_filename']}\n"; + } + } + $html .= "## License: http://opensource.org/licenses/gpl-license.php GNU General Public License v2 \n"; + $html .= "############################################################## \n"; + $html .= "\n"; + + // COPY Statement? + if (sizeof($header['included_files'])) + { + $html .= "#\n#-----[ COPY ]------------------------------------------\n#\n"; + foreach ($header['included_files'] as $filename) + { + $html .= "copy {$filename['phpbb_filename']} to {$filename['phpbb_filename']}\n"; + } + $html .= "\n"; + } + + return $html; +} + +function run_command($command) +{ + $result = trim(`$command`); + echo "\n- Command Run: " . $command . "\n"; +} + +?> diff --git a/build/build_helper.php b/build/build_helper.php new file mode 100644 index 0000000000..2bae32218b --- /dev/null +++ b/build/build_helper.php @@ -0,0 +1,485 @@ +versions = $versions; + $this->verbose = $verbose; + + // Get last two entries + $_latest = $this->versions[sizeof($this->versions) - 1]; + $_before = $this->versions[sizeof($this->versions) - 2]; + + $this->locations = array( + 'new_version' => dirname(dirname(__FILE__)) . '/phpBB/', + 'old_versions' => dirname(__FILE__) . '/old_versions/', + 'root' => dirname(__FILE__) . '/', + 'package_dir' => dirname(__FILE__) . '/new_version/' + ); + + $this->package_infos = array( + 'package_name' => 'phpBB3', + 'name_prefix' => 'phpbb', + 'simple_name' => 'phpbb' . str_replace('.', '', $_latest), + 'new_version_number' => $_latest, + 'short_version_number' => str_replace('.', '', $_latest), + 'release_filename' => 'phpBB-' . $_latest, + 'last_version' => 'phpbb' . str_replace('.', '', $_before), + 'last_version_number' => $_before, + ); + + $this->package_infos['dest_dir'] = $this->locations['package_dir'] . $this->package_infos['package_name']; + $this->package_infos['diff_dir'] = $this->locations['old_versions'] . $this->package_infos['simple_name']; + $this->package_infos['patch_directory'] = $this->locations['package_dir'] . 'patches'; + $this->package_infos['files_directory'] = $this->locations['package_dir'] . 'files'; + $this->package_infos['update_directory'] = $this->locations['package_dir'] . 'update'; + $this->package_infos['release_directory'] = $this->locations['package_dir'] . 'release_files'; + + // Old packages always exclude the latest version. ;) + $this->old_packages = array(); + + foreach ($this->versions as $package_version) + { + if ($package_version == $_latest) + { + continue; + } + + $this->old_packages['phpbb' . str_replace('.', '', $package_version)] = $package_version . '_to_'; + } + + // We need to make sure this is up to date with the latest version + $this->clean_directory_structure = array( + 'adm' => array( + 'images' => '', + 'style' => '', + ), + 'cache' => '', + 'docs' => '', + 'download' => '', + 'files' => '', + 'images' => array( + 'avatars' => array( + 'gallery' => '', + 'upload' => '', + ), + 'icons' => array( + 'misc' => '', + 'smile' => '', + ), + 'ranks' => '', + 'smilies' => '', + 'upload_icons' => '', + ), + 'includes' => array( + 'acm' => '', + 'acp' => array( + 'info' => '', + ), + 'auth' => '', + 'captcha' => array( + 'plugins' => '', + ), + 'diff' => '', + 'db' => '', + 'hooks' => '', + 'mcp' => array( + 'info' => '', + ), + 'questionnaire' => '', + 'search' => '', + 'ucp' => array( + 'info' => '', + ), + 'utf' => array( + 'data' => '', + ), + ), + 'install' => array( + 'convertors'=> '', + 'schemas' => '', +// 'data' => '', + ), + 'language' => array( + 'en' => array( + 'acp' => '', + 'email' => '', + 'mods' => '', + ), + ), + 'store' => '', + 'styles' => array( + 'subsilver2' => array( + 'imageset' => array( + 'en' => '', + ), + 'template' => '', + 'theme' => array( + 'images' => '', + ), + ), + 'prosilver' => array( + 'imageset' => array( + 'en' => '', + ), + 'template' => '', + 'theme' => array( + 'images' => '', + ), + ), + ), + ); + + // Files to remove (not include within package) + $this->files_to_remove = array(); //array('includes/utf/data/recode_cjk.php'); + + // Files within the main directory to copy - do not include config.php + $this->files_to_copy = array( + '.htaccess', 'common.php', 'cron.php', 'faq.php', 'feed.php', 'index.php', 'mcp.php', 'memberlist.php', 'posting.php', 'report.php', + 'search.php', 'style.php', 'ucp.php', 'viewforum.php', 'viewonline.php', 'viewtopic.php' + ); + + // These files/directories will be removed and not used for creating the patch files + $this->remove_from_diff_structure = array( + 'config.php', 'cache', 'docs', 'files', 'install', 'store', 'develop' + ); + + // Writeable directories + $this->writeable = array('cache', 'store', 'images/avatars/upload', 'files'); + + // Fill the rest of the files_to_copy array + foreach ($this->clean_directory_structure as $cur_dir => $dir_struct) + { + $this->_fill_files_to_copy($this->locations['new_version'] . $cur_dir, $cur_dir, $dir_struct); + } + } + + function get($var) + { + return $this->package_infos[$var]; + } + + function _fill_files_to_copy($directory, $cur_dir, $dir_struct) + { + $dh = opendir($directory); + + while ($file = readdir($dh)) + { + if (is_file($directory . '/' . $file) && $file != '.' && $file != '..') + { + $_loc = str_replace($this->locations['new_version'], '', $directory . '/' . $file); + + if (in_array($_loc, $this->files_to_remove)) + { + continue; + } + + $this->files_to_copy[] = $cur_dir . '/' . $file; + } + } + closedir($dh); + + if (is_array($dir_struct)) + { + foreach ($dir_struct as $_cur_dir => $_dir_struct) + { + $this->_fill_files_to_copy($directory . '/' . $_cur_dir, $cur_dir . '/' . $_cur_dir, $_dir_struct); + } + } + } + + function adjust_permissions($directory) + { + $dh = opendir($directory); + + while ($file = readdir($dh)) + { + if ($file == '.' || $file == '..' || $file == '.svn') + { + continue; + } + + // If file, then 644 + if (is_file($directory . '/' . $file)) + { + chmod($directory . '/' . $file, 0644); + } + else if (is_dir($directory . '/' . $file)) + { + $_loc = str_replace($this->package_infos['dest_dir'] . '/', '', $directory . '/' . $file); + + // If directory is within the writeable chmod to 777, else 755 + $mode = (in_array($_loc, $this->writeable)) ? 0777 : 0755; + chmod($directory . '/' . $file, $mode); + + // Now traverse to the directory + $this->adjust_permissions($directory . '/' . $file); + } + } + closedir($dh); + } + + function begin_status($headline) + { + if ($this->status_begun) + { + echo "\nDone.\n\n"; + } + + $this->num_dots = 0; + + echo $headline . "\n "; + + $this->status_begun = true; + } + + function run_command($command) + { + $result = trim(`$command`); + + if ($this->verbose) + { + echo " command : " . getcwd() . '$ ' . $command . "\n"; + echo " result : " . $result . "\n"; + } + else + { + if ($this->num_dots > 70) + { + echo "\n"; + $this->num_dots = 0; + } + echo '.'; + $this->num_dots++; + } + + flush(); + } + + function create_directory($directory, $dir_struct) + { + if (!file_exists($directory)) + { + $this->run_command("mkdir $directory"); + } + + if (is_array($dir_struct)) + { + foreach ($dir_struct as $_dir => $_dir_struct) + { + $this->create_directory($directory . '/' . $_dir, $_dir_struct); + } + } + } + + function collect_diff_files($diff_filename, $package_name) + { + $diff_result = $binary = array(); + $diff_contents = file($diff_filename); + + $special_diff_contents = array(); + + foreach ($diff_contents as $num => $line) + { + $line = trim($line); + + if (!$line) + { + continue; + } + + // Special diff content? + if (strpos($line, 'diff ' . $this->diff_options . ' ') === 0 || strpos($line, '*** ') === 0 || strpos($line, '--- ') === 0 || (strpos($line, ' Exp $') !== false && strpos($line, '$Id:') !== false)) + { + $special_diff_contents[] = $line; + } + else if (strpos($line, 'diff ' . $this->diff_options . ' ') === 0 || strpos($line, '*** ') === 0 || strpos($line, '--- ') === 0 || (strpos($line, ' Exp $') !== false && strpos($line, '$Id:') !== false) || (strpos($line, ' $') !== false && strpos($line, '$Id:') !== false)) + { + $special_diff_contents[] = $line; + } + + // Is diffing line? + if (strstr($line, 'diff ' . $this->diff_options . ' ')) + { + $next_line = $diff_contents[$num+1]; + if (strpos($next_line, '***') === 0) + { + // *** phpbb208/admin/admin_board.php Sat Jul 10 20:16:26 2004 + $next_line = explode("\t", $next_line); + $next_line = trim($next_line[0]); + $next_line = str_replace('*** ' . $package_name . '/', '', $next_line); + $diff_result[] = $next_line; + } + } + + // Is binary? + if (preg_match('/^Binary files ' . $package_name . '\/(.*) and [a-z0-9_-]+\/\1 differ/i', $line, $match)) + { + $binary[] = trim($match[1]); + } + } + + // Now go through the list again and find out which files have how many changes... + $num_changes = array(); + + /* [1070] => diff -crN phpbb200/includes/usercp_avatar.php phpbb2023/includes/usercp_avatar.php + [1071] => *** phpbb200/includes/usercp_avatar.php Sat Jul 10 20:16:13 2004 + [1072] => --- phpbb2023/includes/usercp_avatar.php Wed Feb 6 22:28:04 2008 + [1073] => *** 6,12 **** + [1074] => ! * $Id$ + [1075] => --- 6,12 ---- + [1076] => *** 51,59 **** + [1077] => --- 51,60 ---- + [1078] => *** 62,80 **** + [1079] => --- 63,108 ---- + [1080] => *** 87,97 **** + */ + while (($line = array_shift($special_diff_contents)) !== NULL) + { + $line = trim($line); + + if (!$line) + { + continue; + } + + // Is diffing line? + if (strstr($line, 'diff ' . $this->diff_options . ' ')) + { + $next_line = array_shift($special_diff_contents); + if (strpos($next_line, '*** ') === 0) + { + // *** phpbb208/admin/admin_board.php Sat Jul 10 20:16:26 2004 + $next_line = explode("\t", $next_line); + $next_line = trim($next_line[0]); + $next_line = str_replace('*** ' . $package_name . '/', '', $next_line); + + $is_reached = false; + $prev_line = ''; + + while (!$is_reached) + { + $line = array_shift($special_diff_contents); + + if (strpos($line, 'diff ' . $this->diff_options) === 0 || empty($special_diff_contents)) + { + $is_reached = true; + array_unshift($special_diff_contents, $line); + continue; + } + + if (strpos($line, '*** ') === 0 && strpos($line, ' ****') !== false) + { + $is_comment = false; + while (!(strpos($line, '--- ') === 0 && strpos($line, ' ----') !== false)) + { + $line = array_shift($special_diff_contents); + if (strpos($line, ' Exp $') !== false || strpos($line, '$Id:') !== false) + { + $is_comment = true; + } + } + + if (!$is_comment) + { + if (!isset($num_changes[$next_line])) + { + $num_changes[$next_line] = 1; + } + else + { + $num_changes[$next_line]++; + } + } + } + } + } + } + } + + // Now remove those results not having changes + $return = array(); + + foreach ($diff_result as $key => $value) + { + if (isset($num_changes[$value])) + { + $return[] = $value; + } + } + + foreach ($binary as $value) + { + $return[] = $value; + } + + $diff_result = $return; + unset($return); + unset($special_diff_contents); + + $result = array( + 'files' => array(), + 'binary' => array(), + 'all' => $diff_result, + ); + + $binary_extensions = array('gif', 'jpg', 'jpeg', 'png', 'ttf'); + + // Split into file and binary + foreach ($diff_result as $filename) + { + if (strpos($filename, '.') === false) + { + $result['files'][] = $filename; + continue; + } + + $extension = explode('.', $filename); + $extension = array_pop($extension); + + if (in_array($extension, $binary_extensions)) + { + $result['binary'][] = $filename; + } + else + { + $result['files'][] = $filename; + } + } + + return $result; + } +} diff --git a/build/compare.sh b/build/compare.sh new file mode 100755 index 0000000000..df442fd4c7 --- /dev/null +++ b/build/compare.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +orig_dir="../../phpBB" + + +rm -rf test_release_files +mkdir test_release_files +cd test_release_files + +for ext in "tar.bz2" "zip" +do + cp "../new_version/release_files/$1.$ext" ./ + + if [ "$ext" = "tar.bz2" ] + then + command="tar -xjf" + else + command="unzip -q" + fi + + $command "$1.$ext" + + for file in `find phpBB3 -name '.svn' -prune -o -type f -print` + do + orig_file="${file/#phpBB3/$orig_dir}" + diff_result=`diff $orig_file $file` + + if [ -n "$diff_result" ] + then + echo "Difference in package $1.$ext" + echo $diff_result + fi + done + + rm -rf phpBB3 +done + +cd .. +rm -rf test_release_files + diff --git a/build/diff_class.php b/build/diff_class.php new file mode 100644 index 0000000000..4625ffde24 --- /dev/null +++ b/build/diff_class.php @@ -0,0 +1,1711 @@ + +* @copyright (c) 2010 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* Class used internally by WikiDiff to actually compute the diffs. +* +* The algorithm used here is mostly lifted from the perl module +* Algorithm::Diff (version 1.06) by Ned Konz, which is available at: +* http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip +* +* More ideas are taken from: +* http://www.ics.uci.edu/~eppstein/161/960229.html +* +* Some ideas are (and a bit of code) are from from analyze.c, from GNU +* diffutils-2.7, which can be found at: +* ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz +* +* Finally, some ideas (subdivision by NCHUNKS > 2, and some optimizations) +* are my own. +*/ +class _WikiDiffEngine +{ + var $edits; // List of editing operation to convert XV to YV. + var $xv = array(), $yv = array(); + + function _WikiDiffEngine($from_lines, $to_lines) + { + $n_from = sizeof($from_lines); + $n_to = sizeof($to_lines); + + $endskip = 0; + // Ignore trailing and leading matching lines. + while ($n_from > 0 && $n_to > 0) + { + if ($from_lines[$n_from - 1] != $to_lines[$n_to - 1]) + { + break; + } + + $n_from--; + $n_to--; + $endskip++; + } + + for ($skip = 0; $skip < min($n_from, $n_to); $skip++) + { + if ($from_lines[$skip] != $to_lines[$skip]) + { + break; + } + } + $n_from -= $skip; + $n_to -= $skip; + + $xlines = array(); + $ylines = array(); + + // Ignore lines which do not exist in both files. + for ($x = 0; $x < $n_from; $x++) + { + $xhash[$from_lines[$x + $skip]] = 1; + } + + for ($y = 0; $y < $n_to; $y++) + { + $line = $to_lines[$y + $skip]; + $ylines[] = $line; + + if (($this->ychanged[$y] = empty($xhash[$line]))) + { + continue; + } + $yhash[$line] = 1; + $this->yv[] = $line; + $this->yind[] = $y; + } + + for ($x = 0; $x < $n_from; $x++) + { + $line = $from_lines[$x + $skip]; + $xlines[] = $line; + + if (($this->xchanged[$x] = empty($yhash[$line]))) + { + continue; // fixme? what happens to yhash/xhash when + // there are two identical lines?? + } + $this->xv[] = $line; + $this->xind[] = $x; + } + + // Find the LCS. + $this->_compareseq(0, sizeof($this->xv), 0, sizeof($this->yv)); + + // Merge edits when possible + $this->_shift_boundaries($xlines, $this->xchanged, $this->ychanged); + $this->_shift_boundaries($ylines, $this->ychanged, $this->xchanged); + + // Compute the edit operations. + $this->edits = array(); + + if ($skip) + { + $this->edits[] = $skip; + } + + $x = 0; + $y = 0; + + while ($x < $n_from || $y < $n_to) + { + // Skip matching "snake". + $x0 = $x; + $ncopy = 0; + while ($x < $n_from && $y < $n_to && !$this->xchanged[$x] && !$this->ychanged[$y]) + { + ++$x; + ++$y; + ++$ncopy; + } + + if ($x > $x0) + { + $this->edits[] = $x - $x0; + } + + // Find deletes. + $x0 = $x; + $ndelete = 0; + + while ($x < $n_from && $this->xchanged[$x]) + { + ++$x; + ++$ndelete; + } + + if ($x > $x0) + { + $this->edits[] = -($x - $x0); + } + + // Find adds. + if (isset($this->ychanged[$y]) && $this->ychanged[$y]) + { + $adds = array(); + while ($y < $n_to && $this->ychanged[$y]) + { + $adds[] = $ylines[$y++]; + } + $this->edits[] = $adds; + } + } + + if (!empty($endskip)) + { + $this->edits[] = $endskip; + } + } + + /* Divide the Largest Common Subsequence (LCS) of the sequences + * [XOFF, XLIM) and [YOFF, YLIM) into NCHUNKS approximately equally + * sized segments. + * + * Returns (LCS, PTS). LCS is the length of the LCS. PTS is an + * array of NCHUNKS+1 (X, Y) indexes giving the diving points between + * sub sequences. The first sub-sequence is contained in [X0, X1), + * [Y0, Y1), the second in [X1, X2), [Y1, Y2) and so on. Note + * that (X0, Y0) == (XOFF, YOFF) and + * (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM). + * + * This function assumes that the first lines of the specified portions + * of the two files do not match, and likewise that the last lines do not + * match. The caller must trim matching lines from the beginning and end + * of the portions it is going to specify. + */ + function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks) + { + $flip = false; + + if ($xlim - $xoff > $ylim - $yoff) + { + // Things seems faster (I'm not sure I understand why) + // when the shortest sequence in X. + $flip = true; + list ($xoff, $xlim, $yoff, $ylim) = array( $yoff, $ylim, $xoff, $xlim); + } + + if ($flip) + { + for ($i = $ylim - 1; $i >= $yoff; $i--) + { + $ymatches[$this->xv[$i]][] = $i; + } + } + else + { + for ($i = $ylim - 1; $i >= $yoff; $i--) + { + $ymatches[$this->yv[$i]][] = $i; + } + } + + $this->lcs = 0; + $this->seq[0]= $yoff - 1; + $this->in_seq = array(); + $ymids[0] = array(); + + $numer = $xlim - $xoff + $nchunks - 1; + $x = $xoff; + + for ($chunk = 0; $chunk < $nchunks; $chunk++) + { + if ($chunk > 0) + { + for ($i = 0; $i <= $this->lcs; $i++) + { + $ymids[$i][$chunk-1] = $this->seq[$i]; + } + } + + $x1 = $xoff + (int)(($numer + ($xlim-$xoff)*$chunk) / $nchunks); + + for ( ; $x < $x1; $x++) + { + $_index = $flip ? $this->yv[$x] : $this->xv[$x]; + $matches = (isset($ymatches[$_index])) ? $ymatches[$_index] : array(); + + if (!$matches) + { + continue; + } + reset($matches); + + while (list ($junk, $y) = each($matches)) + { + if (!isset($this->in_seq[$y]) || !$this->in_seq[$y]) + { + $k = $this->_lcs_pos($y); + //if (!$k) die('assertion "!$k" failed'); + $ymids[$k] = $ymids[$k-1]; + break; + } + } + + while (list ($junk, $y) = each($matches)) + { + if ($y > $this->seq[$k-1]) + { + //if ($y >= $this->seq[$k]) die('assertion failed'); + // Optimization: this is a common case: + // next match is just replacing previous match. + $this->in_seq[$this->seq[$k]] = false; + $this->seq[$k] = $y; + $this->in_seq[$y] = 1; + } + else if (!isset($this->in_seq[$y]) || !$this->in_seq[$y]) + { + $k = $this->_lcs_pos($y); + //if (!$k) die('assertion "!$k" failed'); + $ymids[$k] = $ymids[$k-1]; + } + } + } + } + + $seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff); + $ymid = $ymids[$this->lcs]; + + for ($n = 0; $n < $nchunks - 1; $n++) + { + $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks); + $y1 = $ymid[$n] + 1; + $seps[] = $flip ? array($y1, $x1) : array($x1, $y1); + } + $seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim); + + return array($this->lcs, $seps); + } + + function _lcs_pos ($ypos) + { + $end = $this->lcs; + if ($end == 0 || $ypos > $this->seq[$end]) + { + $this->seq[++$this->lcs] = $ypos; + $this->in_seq[$ypos] = 1; + return $this->lcs; + } + + $beg = 1; + while ($beg < $end) + { + $mid = (int)(($beg + $end) / 2); + + if ($ypos > $this->seq[$mid]) + { + $beg = $mid + 1; + } + else + { + $end = $mid; + } + } + + //if ($ypos == $this->seq[$end]) die("assertion failure"); + + $this->in_seq[$this->seq[$end]] = false; + $this->seq[$end] = $ypos; + $this->in_seq[$ypos] = 1; + return $end; + } + + /* Find LCS of two sequences. + * + * The results are recorded in the vectors $this->{x,y}changed[], by + * storing a 1 in the element for each line that is an insertion + * or deletion (ie. is not in the LCS). + * + * The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1. + * + * Note that XLIM, YLIM are exclusive bounds. + * All line numbers are origin-0 and discarded lines are not counted. + */ + function _compareseq ($xoff, $xlim, $yoff, $ylim) + { + // Slide down the bottom initial diagonal. + while ($xoff < $xlim && $yoff < $ylim && $this->xv[$xoff] == $this->yv[$yoff]) + { + ++$xoff; + ++$yoff; + } + + // Slide up the top initial diagonal. + while ($xlim > $xoff && $ylim > $yoff && $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) + { + --$xlim; + --$ylim; + } + + if ($xoff == $xlim || $yoff == $ylim) + { + $lcs = 0; + } + else + { + // This is ad hoc but seems to work well. + //$nchunks = sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5); + //$nchunks = max(2,min(8,(int)$nchunks)); + $nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1; + list ($lcs, $seps) = $this->_diag($xoff, $xlim, $yoff, $ylim, $nchunks); + } + + if ($lcs == 0) + { + // X and Y sequences have no common subsequence: + // mark all changed. + while ($yoff < $ylim) + { + $this->ychanged[$this->yind[$yoff++]] = 1; + } + + while ($xoff < $xlim) + { + $this->xchanged[$this->xind[$xoff++]] = 1; + } + } + else + { + // Use the partitions to split this problem into subproblems. + reset($seps); + + $pt1 = $seps[0]; + + while ($pt2 = next($seps)) + { + $this->_compareseq ($pt1[0], $pt2[0], $pt1[1], $pt2[1]); + $pt1 = $pt2; + } + } + } + + /* Adjust inserts/deletes of identical lines to join changes + * as much as possible. + * + * We do something when a run of changed lines include a + * line at one end and have an excluded, identical line at the other. + * We are free to choose which identical line is included. + * `compareseq' usually chooses the one at the beginning, + * but usually it is cleaner to consider the following identical line + * to be the "change". + * + * This is extracted verbatim from analyze.c (GNU diffutils-2.7). + */ + function _shift_boundaries ($lines, &$changed, $other_changed) + { + $i = 0; + $j = 0; + $len = sizeof($lines); + + while (1) + { + /* + * Scan forwards to find beginning of another run of changes. + * Also keep track of the corresponding point in the other file. + */ + + while ($i < $len && $changed[$i] == 0) + { + while ($other_changed[$j++]) + { + continue; + } + $i++; + } + + if ($i == $len) + { + break; + } + + $start = $i; + + // Find the end of this run of changes. + while (isset($changed[++$i])) + { + continue; + } + + while (isset($other_changed[$j]) && $other_changed[$j]) + { + $j++; + } + + do + { + /* + * Record the length of this run of changes, so that + * we can later determine whether the run has grown. + */ + $runlength = $i - $start; + + /* + * Move the changed region back, so long as the + * previous unchanged line matches the last changed one. + * This merges with previous changed regions. + */ + while ($start && $lines[$start - 1] == $lines[$i - 1]) + { + $changed[--$start] = 1; + $changed[--$i] = false; + + while ($changed[$start - 1]) + { + $start--; + } + + while ($other_changed[--$j]) + { + continue; + } + } + + /* + * Set CORRESPONDING to the end of the changed run, at the last + * point where it corresponds to a changed run in the other file. + * CORRESPONDING == LEN means no such point has been found. + */ + $corresponding = empty($other_changed[$j - 1]) ? $len : $i; + + /* + * Move the changed region forward, so long as the + * first changed line matches the following unchanged one. + * This merges with following changed regions. + * Do this second, so that if there are no merges, + * the changed region is moved forward as far as possible. + */ + while ($i != $len && $lines[$start] == $lines[$i]) + { + $changed[$start++] = false; + $changed[$i++] = 1; + + while ($changed[$i]) + { + $i++; + } + + while ($other_changed[++$j]) + { + $corresponding = $i; + } + } + } while ($runlength != $i - $start); + + /* + * If possible, move the fully-merged run of changes + * back to a corresponding run in the other file. + */ + while ($corresponding < $i) + { + $changed[--$start] = 1; + $changed[--$i] = 0; + + while ($other_changed[--$j]) + { + continue; + } + } + } + } +} + +/** +* Class representing a diff between two files. +*/ +class Diff +{ + var $edits; + + /** + * Compute diff between files (or deserialize serialized WikiDiff.) + */ + function Diff($from_lines = false, $to_lines = false) + { + if ($from_lines && $to_lines) + { + $compute = new _WikiDiffEngine($from_lines, $to_lines); + $this->edits = $compute->edits; + } + else if ($from_lines) + { + // $from_lines is not really from_lines, but rather + // a serialized Diff. + $this->edits = unserialize($from_lines); + } + else + { + $this->edits = array(); + } + } + + /** + * Compute reversed Diff. + * + * SYNOPSIS: + * + * $diff = new Diff($lines1, $lines2); + * $rev = $diff->reverse($lines1); + * + * // reconstruct $lines1 from $lines2: + * $out = $rev->apply($lines2); + */ + function reverse ($from_lines) + { + $x = 0; + $rev = new Diff; + + for (reset($this->edits); $edit = current($this->edits); next($this->edits)) + { + if (is_array($edit)) + { // Was an add, turn it into a delete. + $nadd = sizeof($edit); + if ($nadd == 0) + { + die("assertion error"); + } + $edit = -$nadd; + } + else if ($edit > 0) + { + // Was a copy --- just pass it through. } + $x += $edit; + } + else if ($edit < 0) + { // Was a delete, turn it into an add. + $ndelete = -$edit; + $edit = array(); + + while ($ndelete-- > 0) + { + $edit[] = $from_lines[$x++]; + } + } + else + { + die("assertion error"); + } + + $rev->edits[] = $edit; + } + + return $rev; + } + + /** + * Compose (concatenate) Diffs. + * + * SYNOPSIS: + * + * $diff1 = new Diff($lines1, $lines2); + * $diff2 = new Diff($lines2, $lines3); + * $comp = $diff1->compose($diff2); + * + * // reconstruct $lines3 from $lines1: + * $out = $comp->apply($lines1); + */ + function compose ($that) + { + reset($this->edits); + reset($that->edits); + + $comp = new Diff; + $left = current($this->edits); + $right = current($that->edits); + + while ($left || $right) + { + if (!is_array($left) && $left < 0) + { // Left op is a delete. + $newop = $left; + $left = next($this->edits); + } + else if (is_array($right)) + { // Right op is an add. + $newop = $right; + $right = next($that->edits); + } + else if (!$left || !$right) + { + die ("assertion error"); + } + else if (!is_array($left) && $left > 0) + { // Left op is a copy. + if ($left <= abs($right)) + { + $newop = $right > 0 ? $left : -$left; + $right -= $newop; + + if ($right == 0) + { + $right = next($that->edits); + } + $left = next($this->edits); + } + else + { + $newop = $right; + $left -= abs($right); + $right = next($that->edits); + } + } + else + { // Left op is an add. + if (!is_array($left)) + { + die('assertion error'); + } + $nleft = sizeof($left); + + if ($nleft <= abs($right)) + { + if ($right > 0) + { // Right op is copy + $newop = $left; + $right -= $nleft; + } + else // Right op is delete + { + $newop = false; + $right += $nleft; + } + + if ($right == 0) + { + $right = next($that->edits); + } + $left = next($this->edits); + } + else + { + unset($newop); + + if ($right > 0) + { + for ($i = 0; $i < $right; $i++) + { + $newop[] = $left[$i]; + } + } + + $tmp = array(); + for ($i = abs($right); $i < $nleft; $i++) + { + $tmp[] = $left[$i]; + } + $left = $tmp; + $right = next($that->edits); + } + } + + if (!$op) + { + $op = $newop; + continue; + } + + if (!$newop) + { + continue; + } + + if (is_array($op) && is_array($newop)) + { + // Both $op and $newop are adds. + for ($i = 0; $i < sizeof($newop); $i++) + { + $op[] = $newop[$i]; + } + } + else if (($op > 0 && $newop > 0) || ($op < 0 && $newop < 0)) + { // $op and $newop are both either deletes or copies. + $op += $newop; + } + else + { + $comp->edits[] = $op; + $op = $newop; + } + } + + if ($op) + { + $comp->edits[] = $op; + } + + return $comp; + } + + /* Debugging only: + function _dump () + { + echo "
{L_PHP_VERSION_OLD}
{MESSAGE_TEXT}
This package is meant for those wanting to only replace changed files from a previous version to the latest version. This package normally contains the changed files from up to five previous versions.
This package contains a number of archives, each contains the files changed from a given release to the latest version. You should select the appropriate archive for your current version, e.g. if you currently have 3.0.5 you should select the phpBB-3.0.5_to_3.0.6.zip/tar.gz file.
This package contains a number of archives, each contains the files changed from a given release to the latest version. You should select the appropriate archive for your current version, e.g. if you currently have 3.0.6 you should select the phpBB-3.0.6_to_3.0.7.zip/tar.gz file.
The directory structure has been preserved enabling you (if you wish) to simply upload the contents of the archive to the appropriate location on your server, i.e. simply overwrite the existing files with the new versions. Do not forget that if you have installed any MODs these files will overwrite the originals possibly destroying them in the process. You will need to re-add MODs to any affected file before uploading.
The patch file is one solution for those with many Modifications (MODs) or other changes who do not want to re-add them back to all the changed files if they use the method explained above. To use this you will need command line access to a standard UNIX type patch application. If you do not have access to such an application but still want to use this update approach, we strongly recommend the Automatic update package explained below. It is also the recommended update method.
A number of patch files are provided to allow you to update from previous stable releases. Select the correct patch, e.g. if your current version is 3.0.5 you need the phpBB-3.0.5_to_3.0.6.patch file. Place the correct patch in the parent directory containing the phpBB3 core files (i.e. index.php, viewforum.php, etc.). With this done you should run the following command: patch -cl -d [PHPBB DIRECTORY] -p1 < [PATCH NAME] (where PHPBB DIRECTORY is the directory name your phpBB Installation resides in, for example phpBB3, and where PATCH NAME is the relevant filename of the selected patch file). This should complete quickly, hopefully without any HUNK FAILED comments.
A number of patch files are provided to allow you to update from previous stable releases. Select the correct patch, e.g. if your current version is 3.0.6 you need the phpBB-3.0.6_to_3.0.7.patch file. Place the correct patch in the parent directory containing the phpBB3 core files (i.e. index.php, viewforum.php, etc.). With this done you should run the following command: patch -cl -d [PHPBB DIRECTORY] -p1 < [PATCH NAME] (where PHPBB DIRECTORY is the directory name your phpBB Installation resides in, for example phpBB3, and where PATCH NAME is the relevant filename of the selected patch file). This should complete quickly, hopefully without any HUNK FAILED comments.
If you do get failures you should look at using the Changed files only package to replace the files which failed to patch, please note that you will need to manually re-add any Modifications (MODs) to these particular files. Alternatively if you know how you can examine the .rej files to determine what failed where and make manual adjustments to the relevant source.
If entered with tabs (replace the {TAB}) both equal signs need to be on the same column.
Ensure that your editor is saving files in the UNIX (LF) line ending format. This means that lines are terminated with a newline, not with Windows Line endings (CR/LF combo) as they are on Win32 or Classic Mac (CR) Line endings. Any decent editor should be able to do this, but it might not always be the default setting. Know your editor. If you want advice for an editor for your Operating System, just ask one of the developers. Some of them do their editing on Win32. +
Ensure that your editor is saving files in the UNIX (LF) line ending format. This means that lines are terminated with a newline, not with Windows Line endings (CR/LF combo) as they are on Win32 or Classic Mac (CR) Line endings. Any decent editor should be able to do this, but it might not always be the default setting. Know your editor. If you want advice for an editor for your Operating System, just ask one of the developers. Some of them do their editing on Win32.
/includes/db/firebird.php
/includes/db/msssql.php
/includes/db/mssql_odbc.php
/includes/db/mysql.php
/includes/db/mysqli.php
/includes/db/oracle.php
/includes/db/postgres.php
/styles
style.php
There are some special constants application developers are able to utilize to bend some of phpBB's internal functionality to suit their needs.
Template defined variables can also be utilised. +
Template defined variables can also be utilised.
<!-- DEFINE $SOME_VAR = 'my_file.html' --> <!-- INCLUDE {$SOME_VAR} -->
A contentious decision has seen the ability to include PHP within the template introduced. This is achieved by enclosing the PHP within relevant tags:
The version control system for phpBB3 is subversion. The repository is available at http://code.phpbb.com/svn/phpbb. +
The version control system for phpBB3 is subversion. The repository is available at http://code.phpbb.com/svn/phpbb.
[FLASH]
{L_MODERATOR}{L_MODERATORS}: {MODERATORS}