MediaWiki
REL1_23
|
00001 <?php 00002 00024 class ParserOutput extends CacheTime { 00025 var $mText, # The output text 00026 $mLanguageLinks, # List of the full text of language links, in the order they appear 00027 $mCategories, # Map of category names to sort keys 00028 $mTitleText, # title text of the chosen language variant 00029 $mLinks = array(), # 2-D map of NS/DBK to ID for the links in the document. ID=zero for broken. 00030 $mTemplates = array(), # 2-D map of NS/DBK to ID for the template references. ID=zero for broken. 00031 $mTemplateIds = array(), # 2-D map of NS/DBK to rev ID for the template references. ID=zero for broken. 00032 $mImages = array(), # DB keys of the images used, in the array key only 00033 $mFileSearchOptions = array(), # DB keys of the images used mapped to sha1 and MW timestamp 00034 $mExternalLinks = array(), # External link URLs, in the key only 00035 $mInterwikiLinks = array(), # 2-D map of prefix/DBK (in keys only) for the inline interwiki links in the document. 00036 $mNewSection = false, # Show a new section link? 00037 $mHideNewSection = false, # Hide the new section link? 00038 $mNoGallery = false, # No gallery on category page? (__NOGALLERY__) 00039 $mHeadItems = array(), # Items to put in the <head> section 00040 $mModules = array(), # Modules to be loaded by the resource loader 00041 $mModuleScripts = array(), # Modules of which only the JS will be loaded by the resource loader 00042 $mModuleStyles = array(), # Modules of which only the CSSS will be loaded by the resource loader 00043 $mModuleMessages = array(), # Modules of which only the messages will be loaded by the resource loader 00044 $mJsConfigVars = array(), # JavaScript config variable for mw.config combined with this page 00045 $mOutputHooks = array(), # Hook tags as per $wgParserOutputHooks 00046 $mWarnings = array(), # Warning text to be returned to the user. Wikitext formatted, in the key only 00047 $mSections = array(), # Table of contents 00048 $mEditSectionTokens = false, # prefix/suffix markers if edit sections were output as tokens 00049 $mProperties = array(), # Name/value pairs to be cached in the DB 00050 $mTOCHTML = '', # HTML of the TOC 00051 $mTimestamp, # Timestamp of the revision 00052 $mTOCEnabled = true; # Whether TOC should be shown, can't override __NOTOC__ 00053 private $mIndexPolicy = ''; # 'index' or 'noindex'? Any other value will result in no change. 00054 private $mAccessedOptions = array(); # List of ParserOptions (stored in the keys) 00055 private $mSecondaryDataUpdates = array(); # List of DataUpdate, used to save info from the page somewhere else. 00056 private $mExtensionData = array(); # extra data used by extensions 00057 private $mLimitReportData = array(); # Parser limit report data 00058 private $mParseStartTime = array(); # Timestamps for getTimeSinceStart() 00059 private $mPreventClickjacking = false; # Whether to emit X-Frame-Options: DENY 00060 00061 const EDITSECTION_REGEX = '#<(?:mw:)?editsection page="(.*?)" section="(.*?)"(?:/>|>(.*?)(</(?:mw:)?editsection>))#'; 00062 00063 function __construct( $text = '', $languageLinks = array(), $categoryLinks = array(), 00064 $containsOldMagic = false, $titletext = '' 00065 ) { 00066 $this->mText = $text; 00067 $this->mLanguageLinks = $languageLinks; 00068 $this->mCategories = $categoryLinks; 00069 $this->mContainsOldMagic = $containsOldMagic; 00070 $this->mTitleText = $titletext; 00071 } 00072 00073 function getText() { 00074 wfProfileIn( __METHOD__ ); 00075 $text = $this->mText; 00076 if ( $this->mEditSectionTokens ) { 00077 $text = preg_replace_callback( ParserOutput::EDITSECTION_REGEX, 00078 array( &$this, 'replaceEditSectionLinksCallback' ), $text ); 00079 } else { 00080 $text = preg_replace( ParserOutput::EDITSECTION_REGEX, '', $text ); 00081 } 00082 00083 // If you have an old cached version of this class - sorry, you can't disable the TOC 00084 if ( isset( $this->mTOCEnabled ) && $this->mTOCEnabled ) { 00085 $text = str_replace( array( Parser::TOC_START, Parser::TOC_END ), '', $text ); 00086 } else { 00087 $text = preg_replace( 00088 '#' . preg_quote( Parser::TOC_START ) . '.*?' . preg_quote( Parser::TOC_END ) . '#s', 00089 '', 00090 $text 00091 ); 00092 } 00093 wfProfileOut( __METHOD__ ); 00094 return $text; 00095 } 00096 00104 function replaceEditSectionLinksCallback( $m ) { 00105 global $wgOut, $wgLang; 00106 $args = array( 00107 htmlspecialchars_decode( $m[1] ), 00108 htmlspecialchars_decode( $m[2] ), 00109 isset( $m[4] ) ? $m[3] : null, 00110 ); 00111 $args[0] = Title::newFromText( $args[0] ); 00112 if ( !is_object( $args[0] ) ) { 00113 throw new MWException( "Bad parser output text." ); 00114 } 00115 $args[] = $wgLang->getCode(); 00116 $skin = $wgOut->getSkin(); 00117 return call_user_func_array( array( $skin, 'doEditSectionLink' ), $args ); 00118 } 00119 00120 function &getLanguageLinks() { return $this->mLanguageLinks; } 00121 function getInterwikiLinks() { return $this->mInterwikiLinks; } 00122 function getCategoryLinks() { return array_keys( $this->mCategories ); } 00123 function &getCategories() { return $this->mCategories; } 00124 function getTitleText() { return $this->mTitleText; } 00125 function getSections() { return $this->mSections; } 00126 function getEditSectionTokens() { return $this->mEditSectionTokens; } 00127 function &getLinks() { return $this->mLinks; } 00128 function &getTemplates() { return $this->mTemplates; } 00129 function &getTemplateIds() { return $this->mTemplateIds; } 00130 function &getImages() { return $this->mImages; } 00131 function &getFileSearchOptions() { return $this->mFileSearchOptions; } 00132 function &getExternalLinks() { return $this->mExternalLinks; } 00133 function getNoGallery() { return $this->mNoGallery; } 00134 function getHeadItems() { return $this->mHeadItems; } 00135 function getModules() { return $this->mModules; } 00136 function getModuleScripts() { return $this->mModuleScripts; } 00137 function getModuleStyles() { return $this->mModuleStyles; } 00138 function getModuleMessages() { return $this->mModuleMessages; } 00140 function getJsConfigVars() { return $this->mJsConfigVars; } 00141 function getOutputHooks() { return (array)$this->mOutputHooks; } 00142 function getWarnings() { return array_keys( $this->mWarnings ); } 00143 function getIndexPolicy() { return $this->mIndexPolicy; } 00144 function getTOCHTML() { return $this->mTOCHTML; } 00145 function getTimestamp() { return $this->mTimestamp; } 00146 function getLimitReportData() { return $this->mLimitReportData; } 00147 function getTOCEnabled() { return $this->mTOCEnabled; } 00148 00149 function setText( $text ) { return wfSetVar( $this->mText, $text ); } 00150 function setLanguageLinks( $ll ) { return wfSetVar( $this->mLanguageLinks, $ll ); } 00151 function setCategoryLinks( $cl ) { return wfSetVar( $this->mCategories, $cl ); } 00152 00153 function setTitleText( $t ) { return wfSetVar( $this->mTitleText, $t ); } 00154 function setSections( $toc ) { return wfSetVar( $this->mSections, $toc ); } 00155 function setEditSectionTokens( $t ) { return wfSetVar( $this->mEditSectionTokens, $t ); } 00156 function setIndexPolicy( $policy ) { return wfSetVar( $this->mIndexPolicy, $policy ); } 00157 function setTOCHTML( $tochtml ) { return wfSetVar( $this->mTOCHTML, $tochtml ); } 00158 function setTimestamp( $timestamp ) { return wfSetVar( $this->mTimestamp, $timestamp ); } 00159 function setTOCEnabled( $flag ) { return wfSetVar( $this->mTOCEnabled, $flag ); } 00160 00161 function addCategory( $c, $sort ) { $this->mCategories[$c] = $sort; } 00162 function addLanguageLink( $t ) { $this->mLanguageLinks[] = $t; } 00163 function addWarning( $s ) { $this->mWarnings[$s] = 1; } 00164 00165 function addOutputHook( $hook, $data = false ) { 00166 $this->mOutputHooks[] = array( $hook, $data ); 00167 } 00168 00169 function setNewSection( $value ) { 00170 $this->mNewSection = (bool)$value; 00171 } 00172 function hideNewSection( $value ) { 00173 $this->mHideNewSection = (bool)$value; 00174 } 00175 function getHideNewSection() { 00176 return (bool)$this->mHideNewSection; 00177 } 00178 function getNewSection() { 00179 return (bool)$this->mNewSection; 00180 } 00181 00189 static function isLinkInternal( $internal, $url ) { 00190 return (bool)preg_match( '/^' . 00191 # If server is proto relative, check also for http/https links 00192 ( substr( $internal, 0, 2 ) === '//' ? '(?:https?:)?' : '' ) . 00193 preg_quote( $internal, '/' ) . 00194 # check for query/path/anchor or end of link in each case 00195 '(?:[\?\/\#]|$)/i', 00196 $url 00197 ); 00198 } 00199 00200 function addExternalLink( $url ) { 00201 # We don't register links pointing to our own server, unless... :-) 00202 global $wgServer, $wgRegisterInternalExternals; 00203 00204 $registerExternalLink = true; 00205 if ( !$wgRegisterInternalExternals ) { 00206 $registerExternalLink = !self::isLinkInternal( $wgServer, $url ); 00207 } 00208 if ( $registerExternalLink ) { 00209 $this->mExternalLinks[$url] = 1; 00210 } 00211 } 00212 00219 function addLink( Title $title, $id = null ) { 00220 if ( $title->isExternal() ) { 00221 // Don't record interwikis in pagelinks 00222 $this->addInterwikiLink( $title ); 00223 return; 00224 } 00225 $ns = $title->getNamespace(); 00226 $dbk = $title->getDBkey(); 00227 if ( $ns == NS_MEDIA ) { 00228 // Normalize this pseudo-alias if it makes it down here... 00229 $ns = NS_FILE; 00230 } elseif ( $ns == NS_SPECIAL ) { 00231 // We don't record Special: links currently 00232 // It might actually be wise to, but we'd need to do some normalization. 00233 return; 00234 } elseif ( $dbk === '' ) { 00235 // Don't record self links - [[#Foo]] 00236 return; 00237 } 00238 if ( !isset( $this->mLinks[$ns] ) ) { 00239 $this->mLinks[$ns] = array(); 00240 } 00241 if ( is_null( $id ) ) { 00242 $id = $title->getArticleID(); 00243 } 00244 $this->mLinks[$ns][$dbk] = $id; 00245 } 00246 00254 function addImage( $name, $timestamp = null, $sha1 = null ) { 00255 $this->mImages[$name] = 1; 00256 if ( $timestamp !== null && $sha1 !== null ) { 00257 $this->mFileSearchOptions[$name] = array( 'time' => $timestamp, 'sha1' => $sha1 ); 00258 } 00259 } 00260 00268 function addTemplate( $title, $page_id, $rev_id ) { 00269 $ns = $title->getNamespace(); 00270 $dbk = $title->getDBkey(); 00271 if ( !isset( $this->mTemplates[$ns] ) ) { 00272 $this->mTemplates[$ns] = array(); 00273 } 00274 $this->mTemplates[$ns][$dbk] = $page_id; 00275 if ( !isset( $this->mTemplateIds[$ns] ) ) { 00276 $this->mTemplateIds[$ns] = array(); 00277 } 00278 $this->mTemplateIds[$ns][$dbk] = $rev_id; // For versioning 00279 } 00280 00285 function addInterwikiLink( $title ) { 00286 if ( !$title->isExternal() ) { 00287 throw new MWException( 'Non-interwiki link passed, internal parser error.' ); 00288 } 00289 $prefix = $title->getInterwiki(); 00290 if ( !isset( $this->mInterwikiLinks[$prefix] ) ) { 00291 $this->mInterwikiLinks[$prefix] = array(); 00292 } 00293 $this->mInterwikiLinks[$prefix][$title->getDBkey()] = 1; 00294 } 00295 00301 function addHeadItem( $section, $tag = false ) { 00302 if ( $tag !== false ) { 00303 $this->mHeadItems[$tag] = $section; 00304 } else { 00305 $this->mHeadItems[] = $section; 00306 } 00307 } 00308 00309 public function addModules( $modules ) { 00310 $this->mModules = array_merge( $this->mModules, (array)$modules ); 00311 } 00312 00313 public function addModuleScripts( $modules ) { 00314 $this->mModuleScripts = array_merge( $this->mModuleScripts, (array)$modules ); 00315 } 00316 00317 public function addModuleStyles( $modules ) { 00318 $this->mModuleStyles = array_merge( $this->mModuleStyles, (array)$modules ); 00319 } 00320 00321 public function addModuleMessages( $modules ) { 00322 $this->mModuleMessages = array_merge( $this->mModuleMessages, (array)$modules ); 00323 } 00324 00332 public function addJsConfigVars( $keys, $value = null ) { 00333 if ( is_array( $keys ) ) { 00334 foreach ( $keys as $key => $value ) { 00335 $this->mJsConfigVars[$key] = $value; 00336 } 00337 return; 00338 } 00339 00340 $this->mJsConfigVars[$keys] = $value; 00341 } 00342 00348 public function addOutputPageMetadata( OutputPage $out ) { 00349 $this->addModules( $out->getModules() ); 00350 $this->addModuleScripts( $out->getModuleScripts() ); 00351 $this->addModuleStyles( $out->getModuleStyles() ); 00352 $this->addModuleMessages( $out->getModuleMessages() ); 00353 $this->addJsConfigVars( $out->getJsConfigVars() ); 00354 00355 $this->mHeadItems = array_merge( $this->mHeadItems, $out->getHeadItemsArray() ); 00356 $this->mPreventClickjacking = $this->mPreventClickjacking || $out->getPreventClickjacking(); 00357 } 00358 00366 public function setDisplayTitle( $text ) { 00367 $this->setTitleText( $text ); 00368 $this->setProperty( 'displaytitle', $text ); 00369 } 00370 00376 public function getDisplayTitle() { 00377 $t = $this->getTitleText(); 00378 if ( $t === '' ) { 00379 return false; 00380 } 00381 return $t; 00382 } 00383 00387 public function setFlag( $flag ) { 00388 $this->mFlags[$flag] = true; 00389 } 00390 00391 public function getFlag( $flag ) { 00392 return isset( $this->mFlags[$flag] ); 00393 } 00394 00452 public function setProperty( $name, $value ) { 00453 $this->mProperties[$name] = $value; 00454 } 00455 00456 public function getProperty( $name ) { 00457 return isset( $this->mProperties[$name] ) ? $this->mProperties[$name] : false; 00458 } 00459 00460 public function getProperties() { 00461 if ( !isset( $this->mProperties ) ) { 00462 $this->mProperties = array(); 00463 } 00464 return $this->mProperties; 00465 } 00466 00472 public function getUsedOptions() { 00473 if ( !isset( $this->mAccessedOptions ) ) { 00474 return array(); 00475 } 00476 return array_keys( $this->mAccessedOptions ); 00477 } 00478 00488 public function recordOption( $option ) { 00489 $this->mAccessedOptions[$option] = true; 00490 } 00491 00502 public function addSecondaryDataUpdate( DataUpdate $update ) { 00503 $this->mSecondaryDataUpdates[] = $update; 00504 } 00505 00522 public function getSecondaryDataUpdates( Title $title = null, $recursive = true ) { 00523 if ( is_null( $title ) ) { 00524 $title = Title::newFromText( $this->getTitleText() ); 00525 } 00526 00527 $linksUpdate = new LinksUpdate( $title, $this, $recursive ); 00528 00529 return array_merge( $this->mSecondaryDataUpdates, array( $linksUpdate ) ); 00530 } 00531 00573 public function setExtensionData( $key, $value ) { 00574 if ( $value === null ) { 00575 unset( $this->mExtensionData[$key] ); 00576 } else { 00577 $this->mExtensionData[$key] = $value; 00578 } 00579 } 00580 00592 public function getExtensionData( $key ) { 00593 if ( isset( $this->mExtensionData[$key] ) ) { 00594 return $this->mExtensionData[$key]; 00595 } 00596 00597 return null; 00598 } 00599 00600 private static function getTimes( $clock = null ) { 00601 $ret = array(); 00602 if ( !$clock || $clock === 'wall' ) { 00603 $ret['wall'] = microtime( true ); 00604 } 00605 if ( ( !$clock || $clock === 'cpu' ) && function_exists( 'getrusage' ) ) { 00606 $ru = getrusage(); 00607 $ret['cpu'] = $ru['ru_utime.tv_sec'] + $ru['ru_utime.tv_usec'] / 1e6; 00608 $ret['cpu'] += $ru['ru_stime.tv_sec'] + $ru['ru_stime.tv_usec'] / 1e6; 00609 } 00610 return $ret; 00611 } 00612 00617 function resetParseStartTime() { 00618 $this->mParseStartTime = self::getTimes(); 00619 } 00620 00632 function getTimeSinceStart( $clock ) { 00633 if ( !isset( $this->mParseStartTime[$clock] ) ) { 00634 return null; 00635 } 00636 00637 $end = self::getTimes( $clock ); 00638 return $end[$clock] - $this->mParseStartTime[$clock]; 00639 } 00640 00660 function setLimitReportData( $key, $value ) { 00661 $this->mLimitReportData[$key] = $value; 00662 } 00663 00671 public function preventClickjacking( $flag = null ) { 00672 return wfSetVar( $this->mPreventClickjacking, $flag ); 00673 } 00674 00678 function __sleep() { 00679 return array_diff( 00680 array_keys( get_object_vars( $this ) ), 00681 array( 'mSecondaryDataUpdates', 'mParseStartTime' ) 00682 ); 00683 } 00684 }