differenceengine.php
来自「php 开发的内容管理系统」· PHP 代码 · 共 1,752 行 · 第 1/4 页
PHP
1,752 行
<tr> <td colspan='2' width='50%' align='center' class='diff-otitle'>{$otitle}</td> <td colspan='2' width='50%' align='center' class='diff-ntitle'>{$ntitle}</td> </tr> $diff </table> "; return $out; } /** * Use specified text instead of loading from the database */ function setText( $oldText, $newText ) { $this->mOldtext = $oldText; $this->mNewtext = $newText; $this->mTextLoaded = 2; } /** * Load revision metadata for the specified articles. If newid is 0, then compare * the old article in oldid to the current article; if oldid is 0, then * compare the current article to the immediately previous one (ignoring the * value of newid). * * If oldid is false, leave the corresponding revision object set * to false. This is impossible via ordinary user input, and is provided for * API convenience. */ function loadRevisionData() { global $wgLang; if ( $this->mRevisionsLoaded ) { return true; } else { // Whether it succeeds or fails, we don't want to try again $this->mRevisionsLoaded = true; } // Load the new revision object if( $this->mNewid ) { $this->mNewRev = Revision::newFromId( $this->mNewid ); } else { $this->mNewRev = Revision::newFromTitle( $this->mTitle ); } if( is_null( $this->mNewRev ) ) { return false; } // Set assorted variables $timestamp = $wgLang->timeanddate( $this->mNewRev->getTimestamp(), true ); $this->mNewPage = $this->mNewRev->getTitle(); if( $this->mNewRev->isCurrent() ) { $newLink = $this->mNewPage->escapeLocalUrl(); $this->mPagetitle = htmlspecialchars( wfMsg( 'currentrev' ) ); $newEdit = $this->mNewPage->escapeLocalUrl( 'action=edit' ); $this->mNewtitle = "<strong><a href='$newLink'>{$this->mPagetitle}</a> ($timestamp)</strong>" . " (<a href='$newEdit'>" . htmlspecialchars( wfMsg( 'editold' ) ) . "</a>)"; } else { $newLink = $this->mNewPage->escapeLocalUrl( 'oldid=' . $this->mNewid ); $newEdit = $this->mNewPage->escapeLocalUrl( 'action=edit&oldid=' . $this->mNewid ); $this->mPagetitle = htmlspecialchars( wfMsg( 'revisionasof', $timestamp ) ); $this->mNewtitle = "<strong><a href='$newLink'>{$this->mPagetitle}</a></strong>" . " (<a href='$newEdit'>" . htmlspecialchars( wfMsg( 'editold' ) ) . "</a>)"; } // Load the old revision object $this->mOldRev = false; if( $this->mOldid ) { $this->mOldRev = Revision::newFromId( $this->mOldid ); } elseif ( $this->mOldid === 0 ) { $rev = $this->mNewRev->getPrevious(); if( $rev ) { $this->mOldid = $rev->getId(); $this->mOldRev = $rev; } else { // No previous revision; mark to show as first-version only. $this->mOldid = false; $this->mOldRev = false; } }/* elseif ( $this->mOldid === false ) leave mOldRev false; */ if( is_null( $this->mOldRev ) ) { return false; } if ( $this->mOldRev ) { $this->mOldPage = $this->mOldRev->getTitle(); $t = $wgLang->timeanddate( $this->mOldRev->getTimestamp(), true ); $oldLink = $this->mOldPage->escapeLocalUrl( 'oldid=' . $this->mOldid ); $oldEdit = $this->mOldPage->escapeLocalUrl( 'action=edit&oldid=' . $this->mOldid ); $this->mOldtitle = "<strong><a href='$oldLink'>" . htmlspecialchars( wfMsg( 'revisionasof', $t ) ) . "</a></strong> (<a href='$oldEdit'>" . htmlspecialchars( wfMsg( 'editold' ) ) . "</a>)"; } return true; } /** * Load the text of the revisions, as well as revision data. */ function loadText() { if ( $this->mTextLoaded == 2 ) { return true; } else { // Whether it succeeds or fails, we don't want to try again $this->mTextLoaded = 2; } if ( !$this->loadRevisionData() ) { return false; } if ( $this->mOldRev ) { // FIXME: permission tests $this->mOldtext = $this->mOldRev->getText(); if ( $this->mOldtext === false ) { return false; } } if ( $this->mNewRev ) { $this->mNewtext = $this->mNewRev->getText(); if ( $this->mNewtext === false ) { return false; } } return true; } /** * Load the text of the new revision, not the old one */ function loadNewText() { if ( $this->mTextLoaded >= 1 ) { return true; } else { $this->mTextLoaded = 1; } if ( !$this->loadRevisionData() ) { return false; } $this->mNewtext = $this->mNewRev->getText(); return true; }}// A PHP diff engine for phpwiki. (Taken from phpwiki-1.3.3)//// Copyright (C) 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>// You may copy this code freely under the conditions of the GPL.//define('USE_ASSERTS', function_exists('assert'));/** * @todo document * @private * @package MediaWiki * @subpackage DifferenceEngine */class _DiffOp { var $type; var $orig; var $closing; function reverse() { trigger_error('pure virtual', E_USER_ERROR); } function norig() { return $this->orig ? sizeof($this->orig) : 0; } function nclosing() { return $this->closing ? sizeof($this->closing) : 0; }}/** * @todo document * @private * @package MediaWiki * @subpackage DifferenceEngine */class _DiffOp_Copy extends _DiffOp { var $type = 'copy'; function _DiffOp_Copy ($orig, $closing = false) { if (!is_array($closing)) $closing = $orig; $this->orig = $orig; $this->closing = $closing; } function reverse() { return new _DiffOp_Copy($this->closing, $this->orig); }}/** * @todo document * @private * @package MediaWiki * @subpackage DifferenceEngine */class _DiffOp_Delete extends _DiffOp { var $type = 'delete'; function _DiffOp_Delete ($lines) { $this->orig = $lines; $this->closing = false; } function reverse() { return new _DiffOp_Add($this->orig); }}/** * @todo document * @private * @package MediaWiki * @subpackage DifferenceEngine */class _DiffOp_Add extends _DiffOp { var $type = 'add'; function _DiffOp_Add ($lines) { $this->closing = $lines; $this->orig = false; } function reverse() { return new _DiffOp_Delete($this->closing); }}/** * @todo document * @private * @package MediaWiki * @subpackage DifferenceEngine */class _DiffOp_Change extends _DiffOp { var $type = 'change'; function _DiffOp_Change ($orig, $closing) { $this->orig = $orig; $this->closing = $closing; } function reverse() { return new _DiffOp_Change($this->closing, $this->orig); }}/** * Class used internally by Diff 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 * * closingly, some ideas (subdivision by NCHUNKS > 2, and some optimizations) * are my own. * * Line length limits for robustness added by Tim Starling, 2005-08-31 * * @author Geoffrey T. Dairiki, Tim Starling * @private * @package MediaWiki * @subpackage DifferenceEngine */class _DiffEngine{ function diff ($from_lines, $to_lines) { $fname = '_DiffEngine::diff'; wfProfileIn( $fname ); $n_from = sizeof($from_lines); $n_to = sizeof($to_lines); $this->xchanged = $this->ychanged = array(); $this->xv = $this->yv = array(); $this->xind = $this->yind = array(); unset($this->seq); unset($this->in_seq); unset($this->lcs); // Skip leading common lines. for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) { if ($from_lines[$skip] !== $to_lines[$skip]) break; $this->xchanged[$skip] = $this->ychanged[$skip] = false; } // Skip trailing common lines. $xi = $n_from; $yi = $n_to; for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) { if ($from_lines[$xi] !== $to_lines[$yi]) break; $this->xchanged[$xi] = $this->ychanged[$yi] = false; } // Ignore lines which do not exist in both files. for ($xi = $skip; $xi < $n_from - $endskip; $xi++) { $xhash[$this->_line_hash($from_lines[$xi])] = 1; } for ($yi = $skip; $yi < $n_to - $endskip; $yi++) { $line = $to_lines[$yi]; if ( ($this->ychanged[$yi] = empty($xhash[$this->_line_hash($line)])) ) continue; $yhash[$this->_line_hash($line)] = 1; $this->yv[] = $line; $this->yind[] = $yi; } for ($xi = $skip; $xi < $n_from - $endskip; $xi++) { $line = $from_lines[$xi]; if ( ($this->xchanged[$xi] = empty($yhash[$this->_line_hash($line)])) ) continue; $this->xv[] = $line; $this->xind[] = $xi; } // Find the LCS. $this->_compareseq(0, sizeof($this->xv), 0, sizeof($this->yv)); // Merge edits when possible $this->_shift_boundaries($from_lines, $this->xchanged, $this->ychanged); $this->_shift_boundaries($to_lines, $this->ychanged, $this->xchanged); // Compute the edit operations. $edits = array(); $xi = $yi = 0; while ($xi < $n_from || $yi < $n_to) { USE_ASSERTS && assert($yi < $n_to || $this->xchanged[$xi]); USE_ASSERTS && assert($xi < $n_from || $this->ychanged[$yi]); // Skip matching "snake". $copy = array(); while ( $xi < $n_from && $yi < $n_to && !$this->xchanged[$xi] && !$this->ychanged[$yi]) { $copy[] = $from_lines[$xi++]; ++$yi; } if ($copy) $edits[] = new _DiffOp_Copy($copy); // Find deletes & adds. $delete = array(); while ($xi < $n_from && $this->xchanged[$xi]) $delete[] = $from_lines[$xi++]; $add = array(); while ($yi < $n_to && $this->ychanged[$yi]) $add[] = $to_lines[$yi++]; if ($delete && $add) $edits[] = new _DiffOp_Change($delete, $add); elseif ($delete) $edits[] = new _DiffOp_Delete($delete); elseif ($add) $edits[] = new _DiffOp_Add($add); } wfProfileOut( $fname ); return $edits; } /** * Returns the whole line if it's small enough, or the MD5 hash otherwise */ function _line_hash( $line ) { if ( strlen( $line ) > MAX_DIFF_XREF_LENGTH ) { return md5( $line ); } else { return $line; } } /* 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) { $fname = '_DiffEngine::_diag'; wfProfileIn( $fname ); $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++) { wfProfileIn( "$fname-chunk" );
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?