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 + -
显示快捷键?