differenceengine.php

来自「php 开发的内容管理系统」· PHP 代码 · 共 1,752 行 · 第 1/4 页

PHP
1,752
字号
<?php/** * See diff.doc * @package MediaWiki * @subpackage DifferenceEngine *//** */define( 'MAX_DIFF_LINE', 10000 );define( 'MAX_DIFF_XREF_LENGTH', 10000 );/** * @todo document * @public * @package MediaWiki * @subpackage DifferenceEngine */class DifferenceEngine {	/**#@+	 * @private	 */	var $mOldid, $mNewid, $mTitle;	var $mOldtitle, $mNewtitle, $mPagetitle;	var $mOldtext, $mNewtext;	var $mOldPage, $mNewPage;	var $mRcidMarkPatrolled;	var $mOldRev, $mNewRev;	var $mRevisionsLoaded = false; // Have the revisions been loaded	var $mTextLoaded = 0; // How many text blobs have been loaded, 0, 1 or 2?	/**#@-*/	/**	 * Constructor	 * @param $titleObj Title object that the diff is associated with	 * @param $old Integer: old ID we want to show and diff with.	 * @param $new String: either 'prev' or 'next'.	 * @param $rcid Integer: ??? FIXME (default 0)	 */	function DifferenceEngine( $titleObj = null, $old = 0, $new = 0, $rcid = 0 ) {		$this->mTitle = $titleObj;		wfDebug("DifferenceEngine old '$old' new '$new' rcid '$rcid'\n");		if ( 'prev' === $new ) {			# Show diff between revision $old and the previous one.			# Get previous one from DB.			#			$this->mNewid = intval($old);			$this->mOldid = $this->mTitle->getPreviousRevisionID( $this->mNewid );		} elseif ( 'next' === $new ) {			# Show diff between revision $old and the previous one.			# Get previous one from DB.			#			$this->mOldid = intval($old);			$this->mNewid = $this->mTitle->getNextRevisionID( $this->mOldid );			if ( false === $this->mNewid ) {				# if no result, NewId points to the newest old revision. The only newer				# revision is cur, which is "0".				$this->mNewid = 0;			}		} else {			$this->mOldid = intval($old);			$this->mNewid = intval($new);		}		$this->mRcidMarkPatrolled = intval($rcid);  # force it to be an integer	}	function showDiffPage() {		global $wgUser, $wgOut, $wgContLang, $wgUseExternalEditor, $wgUseRCPatrol;		$fname = 'DifferenceEngine::showDiffPage';		wfProfileIn( $fname );	 	# If external diffs are enabled both globally and for the user,		# we'll use the application/x-external-editor interface to call		# an external diff tool like kompare, kdiff3, etc.		if($wgUseExternalEditor && $wgUser->getOption('externaldiff')) {			global $wgInputEncoding,$wgServer,$wgScript,$wgLang;			$wgOut->disable();			header ( "Content-type: application/x-external-editor; charset=".$wgInputEncoding );			$url1=$this->mTitle->getFullURL("action=raw&oldid=".$this->mOldid);			$url2=$this->mTitle->getFullURL("action=raw&oldid=".$this->mNewid);			$special=$wgLang->getNsText(NS_SPECIAL);			$control=<<<CONTROL[Process]Type=Diff textEngine=MediaWikiScript={$wgServer}{$wgScript}Special namespace={$special}[File]Extension=wikiURL=$url1[File 2]Extension=wikiURL=$url2CONTROL;			echo($control);			return;		}		$t = $this->mTitle->getPrefixedText() . " (Diff: {$this->mOldid}, " .		  "{$this->mNewid})";		$mtext = wfMsg( 'missingarticle', "<nowiki>$t</nowiki>" );		$wgOut->setArticleFlag( false );		if ( ! $this->loadRevisionData() ) {			$wgOut->setPagetitle( wfMsg( 'errorpagetitle' ) );			$wgOut->addWikitext( $mtext );			wfProfileOut( $fname );			return;		}				wfRunHooks( 'DiffViewHeader', array( $this, $this->mOldRev, $this->mNewRev ) );		if ( $this->mNewRev->isCurrent() ) {			$wgOut->setArticleFlag( true );		}		# mOldid is false if the difference engine is called with a "vague" query for		# a diff between a version V and its previous version V' AND the version V		# is the first version of that article. In that case, V' does not exist.		if ( $this->mOldid === false ) {			$this->showFirstRevision();			wfProfileOut( $fname );			return;		}		$wgOut->suppressQuickbar();		$oldTitle = $this->mOldPage->getPrefixedText();		$newTitle = $this->mNewPage->getPrefixedText();		if( $oldTitle == $newTitle ) {			$wgOut->setPageTitle( $newTitle );		} else {			$wgOut->setPageTitle( $oldTitle . ', ' . $newTitle );		}		$wgOut->setSubtitle( wfMsg( 'difference' ) );		$wgOut->setRobotpolicy( 'noindex,nofollow' );		if ( !( $this->mOldPage->userCanRead() && $this->mNewPage->userCanRead() ) ) {			$wgOut->loginToUse();			$wgOut->output();			wfProfileOut( $fname );			exit;		}		$sk = $wgUser->getSkin();		$talk = $wgContLang->getNsText( NS_TALK );		$contribs = wfMsg( 'contribslink' );		if ( $this->mNewRev->isCurrent() && $wgUser->isAllowed('rollback') ) {			$username = $this->mNewRev->getUserText();			$rollback = '&nbsp;&nbsp;&nbsp;<strong>[' . $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'rollbacklink' ),				'action=rollback&from=' . urlencode( $username ) .				'&token=' . urlencode( $wgUser->editToken( array( $this->mTitle->getPrefixedText(), $username ) ) ) ) .				']</strong>';		} else {			$rollback = '';		}		if( $wgUseRCPatrol && $this->mRcidMarkPatrolled != 0 && $wgUser->isAllowed( 'patrol' ) ) {			$patrol = ' [' . $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'markaspatrolleddiff' ), "action=markpatrolled&rcid={$this->mRcidMarkPatrolled}" ) . ']';		} else {			$patrol = '';		}		$prevlink = $sk->makeKnownLinkObj( $this->mTitle, wfMsgHtml( 'previousdiff' ),			'diff=prev&oldid='.$this->mOldid, '', '', 'id="differences-prevlink"' );		if ( $this->mNewRev->isCurrent() ) {			$nextlink = '&nbsp;';		} else {			$nextlink = $sk->makeKnownLinkObj( $this->mTitle, wfMsgHtml( 'nextdiff' ),				'diff=next&oldid='.$this->mNewid, '', '', 'id="differences-nextlink"' );		}		$oldHeader = "<strong>{$this->mOldtitle}</strong><br />" .			$sk->revUserTools( $this->mOldRev ) . "<br />" .			$sk->revComment( $this->mOldRev ) . "<br />" .			$prevlink;		$newHeader = "<strong>{$this->mNewtitle}</strong><br />" .			$sk->revUserTools( $this->mNewRev ) . " $rollback<br />" .			$sk->revComment( $this->mNewRev ) . "<br />" .			$nextlink . $patrol;		$this->showDiff( $oldHeader, $newHeader );		$wgOut->addHTML( "<hr /><h2>{$this->mPagetitle}</h2>\n" );		if( !$this->mNewRev->isCurrent() ) {			$oldEditSectionSetting = $wgOut->mParserOptions->setEditSection( false );		}		$this->loadNewText();		if( is_object( $this->mNewRev ) ) {			$wgOut->setRevisionId( $this->mNewRev->getId() );		}		$wgOut->addSecondaryWikiText( $this->mNewtext );		if( !$this->mNewRev->isCurrent() ) {			$wgOut->mParserOptions->setEditSection( $oldEditSectionSetting );		}		wfProfileOut( $fname );	}	/**	 * Show the first revision of an article. Uses normal diff headers in	 * contrast to normal "old revision" display style.	 */	function showFirstRevision() {		global $wgOut, $wgUser;		$fname = 'DifferenceEngine::showFirstRevision';		wfProfileIn( $fname );		# Get article text from the DB		#		if ( ! $this->loadNewText() ) {			$t = $this->mTitle->getPrefixedText() . " (Diff: {$this->mOldid}, " .			  "{$this->mNewid})";			$mtext = wfMsg( 'missingarticle', "<nowiki>$t</nowiki>" );			$wgOut->setPagetitle( wfMsg( 'errorpagetitle' ) );			$wgOut->addWikitext( $mtext );			wfProfileOut( $fname );			return;		}		if ( $this->mNewRev->isCurrent() ) {			$wgOut->setArticleFlag( true );		}		# Check if user is allowed to look at this page. If not, bail out.		#		if ( !( $this->mTitle->userCanRead() ) ) {			$wgOut->loginToUse();			$wgOut->output();			wfProfileOut( $fname );			exit;		}		# Prepare the header box		#		$sk = $wgUser->getSkin();		$nextlink = $sk->makeKnownLinkObj( $this->mTitle, wfMsgHtml( 'nextdiff' ), 'diff=next&oldid='.$this->mNewid, '', '', 'id="differences-nextlink"' );		$header = "<div class=\"firstrevisionheader\" style=\"text-align: center\"><strong>{$this->mOldtitle}</strong><br />" .			$sk->revUserTools( $this->mNewRev ) . "<br />" .			$sk->revComment( $this->mNewRev ) . "<br />" .			$nextlink . "</div>\n";		$wgOut->addHTML( $header );		$wgOut->setSubtitle( wfMsg( 'difference' ) );		$wgOut->setRobotpolicy( 'noindex,nofollow' );		# Show current revision		#		$wgOut->addHTML( "<hr /><h2>{$this->mPagetitle}</h2>\n" );		if( is_object( $this->mNewRev ) ) {			$wgOut->setRevisionId( $this->mNewRev->getId() );		}		$wgOut->addSecondaryWikiText( $this->mNewtext );		wfProfileOut( $fname );	}	/**	 * Get the diff text, send it to $wgOut	 * Returns false if the diff could not be generated, otherwise returns true	 */	function showDiff( $otitle, $ntitle ) {		global $wgOut;		$diff = $this->getDiff( $otitle, $ntitle );		if ( $diff === false ) {			$wgOut->addWikitext( wfMsg( 'missingarticle', "<nowiki>(fixme, bug)</nowiki>" ) );			return false;		} else {			$wgOut->addHTML( $diff );			return true;		}	}	/**	 * Get diff table, including header	 * Note that the interface has changed, it's no longer static.	 * Returns false on error	 */	function getDiff( $otitle, $ntitle ) {		$body = $this->getDiffBody();		if ( $body === false ) {			return false;		} else {			return $this->addHeader( $body, $otitle, $ntitle );		}	}	/**	 * Get the diff table body, without header	 * Results are cached	 * Returns false on error	 */	function getDiffBody() {		global $wgMemc, $wgDBname;		$fname = 'DifferenceEngine::getDiffBody';		wfProfileIn( $fname );				// Cacheable?		$key = false;		if ( $this->mOldid && $this->mNewid ) {			// Try cache			$key = "$wgDBname:diff:oldid:{$this->mOldid}:newid:{$this->mNewid}";			$difftext = $wgMemc->get( $key );			if ( $difftext ) {				wfIncrStats( 'diff_cache_hit' );				$difftext = $this->localiseLineNumbers( $difftext );				$difftext .= "\n<!-- diff cache key $key -->\n";				wfProfileOut( $fname );				return $difftext;			}		}		if ( !$this->loadText() ) {			wfProfileOut( $fname );			return false;		}		$difftext = $this->generateDiffBody( $this->mOldtext, $this->mNewtext );				// Save to cache for 7 days		if ( $key !== false && $difftext !== false ) {			wfIncrStats( 'diff_cache_miss' );			$wgMemc->set( $key, $difftext, 7*86400 );		} else {			wfIncrStats( 'diff_uncacheable' );		}		// Replace line numbers with the text in the user's language		if ( $difftext !== false ) {			$difftext = $this->localiseLineNumbers( $difftext );		}		wfProfileOut( $fname );		return $difftext;	}	/**	 * Generate a diff, no caching	 * $otext and $ntext must be already segmented	 */	function generateDiffBody( $otext, $ntext ) {		global $wgExternalDiffEngine, $wgContLang;		$fname = 'DifferenceEngine::generateDiffBody';		$otext = str_replace( "\r\n", "\n", $otext );		$ntext = str_replace( "\r\n", "\n", $ntext );				if ( $wgExternalDiffEngine == 'wikidiff' ) {			# For historical reasons, external diff engine expects			# input text to be HTML-escaped already			$otext = htmlspecialchars ( $wgContLang->segmentForDiff( $otext ) );			$ntext = htmlspecialchars ( $wgContLang->segmentForDiff( $ntext ) );			if( !function_exists( 'wikidiff_do_diff' ) ) {				dl('php_wikidiff.so');			}			return $wgContLang->unsegementForDiff( wikidiff_do_diff( $otext, $ntext, 2 ) );		}				if ( $wgExternalDiffEngine == 'wikidiff2' ) {			# Better external diff engine, the 2 may some day be dropped			# This one does the escaping and segmenting itself			if ( !function_exists( 'wikidiff2_do_diff' ) ) {				wfProfileIn( "$fname-dl" );				@dl('php_wikidiff2.so');				wfProfileOut( "$fname-dl" );			}			if ( function_exists( 'wikidiff2_do_diff' ) ) {				wfProfileIn( 'wikidiff2_do_diff' );				$text = wikidiff2_do_diff( $otext, $ntext, 2 );				wfProfileOut( 'wikidiff2_do_diff' );				return $text;			}		}		if ( $wgExternalDiffEngine !== false ) {			# Diff via the shell			global $wgTmpDirectory;			$tempName1 = tempnam( $wgTmpDirectory, 'diff_' );			$tempName2 = tempnam( $wgTmpDirectory, 'diff_' );			$tempFile1 = fopen( $tempName1, "w" );			if ( !$tempFile1 ) {				wfProfileOut( $fname );				return false;			}			$tempFile2 = fopen( $tempName2, "w" );			if ( !$tempFile2 ) {				wfProfileOut( $fname );				return false;			}			fwrite( $tempFile1, $otext );			fwrite( $tempFile2, $ntext );			fclose( $tempFile1 );			fclose( $tempFile2 );			$cmd = wfEscapeShellArg( $wgExternalDiffEngine, $tempName1, $tempName2 );			wfProfileIn( "$fname-shellexec" );			$difftext = wfShellExec( $cmd );			wfProfileOut( "$fname-shellexec" );			unlink( $tempName1 );			unlink( $tempName2 );			return $difftext;		}				# Native PHP diff		$ota = explode( "\n", $wgContLang->segmentForDiff( $otext ) );		$nta = explode( "\n", $wgContLang->segmentForDiff( $ntext ) );		$diffs =& new Diff( $ota, $nta );		$formatter =& new TableDiffFormatter();		return $wgContLang->unsegmentForDiff( $formatter->format( $diffs ) );	}			/**	 * Replace line numbers with the text in the user's language	 */	function localiseLineNumbers( $text ) {		return preg_replace_callback( '/<!--LINE (\d+)-->/',			array( &$this, 'localiseLineNumbersCb' ), $text );	}	function localiseLineNumbersCb( $matches ) {		global $wgLang;		return wfMsgExt( 'lineno', array('parseinline'), $wgLang->formatNum( $matches[1] ) );	}	/**	 * Add the header to a diff body	 */	function addHeader( $diff, $otitle, $ntitle ) {		$out = "			<table border='0' width='98%' cellpadding='0' cellspacing='4' class='diff'>

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?