MediaWiki
REL1_22
|
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 $mOutputHooks = array(), # Hook tags as per $wgParserOutputHooks 00045 $mWarnings = array(), # Warning text to be returned to the user. Wikitext formatted, in the key only 00046 $mSections = array(), # Table of contents 00047 $mEditSectionTokens = false, # prefix/suffix markers if edit sections were output as tokens 00048 $mProperties = array(), # Name/value pairs to be cached in the DB 00049 $mTOCHTML = '', # HTML of the TOC 00050 $mTimestamp, # Timestamp of the revision 00051 $mTOCEnabled = true; # Whether TOC should be shown, can't override __NOTOC__ 00052 private $mIndexPolicy = ''; # 'index' or 'noindex'? Any other value will result in no change. 00053 private $mAccessedOptions = array(); # List of ParserOptions (stored in the keys) 00054 private $mSecondaryDataUpdates = array(); # List of DataUpdate, used to save info from the page somewhere else. 00055 private $mExtensionData = array(); # extra data used by extensions 00056 private $mLimitReportData = array(); # Parser limit report data 00057 private $mParseStartTime = array(); # Timestamps for getTimeSinceStart() 00058 private $mPreventClickjacking = false; # Whether to emit X-Frame-Options: DENY 00059 00060 const EDITSECTION_REGEX = '#<(?:mw:)?editsection page="(.*?)" section="(.*?)"(?:/>|>(.*?)(</(?:mw:)?editsection>))#'; 00061 00062 function __construct( $text = '', $languageLinks = array(), $categoryLinks = array(), 00063 $containsOldMagic = false, $titletext = '' ) 00064 { 00065 $this->mText = $text; 00066 $this->mLanguageLinks = $languageLinks; 00067 $this->mCategories = $categoryLinks; 00068 $this->mContainsOldMagic = $containsOldMagic; 00069 $this->mTitleText = $titletext; 00070 } 00071 00072 function getText() { 00073 wfProfileIn( __METHOD__ ); 00074 $text = $this->mText; 00075 if ( $this->mEditSectionTokens ) { 00076 $text = preg_replace_callback( ParserOutput::EDITSECTION_REGEX, 00077 array( &$this, 'replaceEditSectionLinksCallback' ), $text ); 00078 } else { 00079 $text = preg_replace( ParserOutput::EDITSECTION_REGEX, '', $text ); 00080 } 00081 00082 // If you have an old cached version of this class - sorry, you can't disable the TOC 00083 if ( isset( $this->mTOCEnabled ) && $this->mTOCEnabled ) { 00084 $text = str_replace( array( Parser::TOC_START, Parser::TOC_END ), '', $text ); 00085 } else { 00086 $text = preg_replace( 00087 '#'. preg_quote( Parser::TOC_START ) . '.*?' . preg_quote( Parser::TOC_END ) . '#s', 00088 '', 00089 $text 00090 ); 00091 } 00092 wfProfileOut( __METHOD__ ); 00093 return $text; 00094 } 00095 00103 function replaceEditSectionLinksCallback( $m ) { 00104 global $wgOut, $wgLang; 00105 $args = array( 00106 htmlspecialchars_decode( $m[1] ), 00107 htmlspecialchars_decode( $m[2] ), 00108 isset( $m[4] ) ? $m[3] : null, 00109 ); 00110 $args[0] = Title::newFromText( $args[0] ); 00111 if ( !is_object( $args[0] ) ) { 00112 throw new MWException( "Bad parser output text." ); 00113 } 00114 $args[] = $wgLang->getCode(); 00115 $skin = $wgOut->getSkin(); 00116 return call_user_func_array( array( $skin, 'doEditSectionLink' ), $args ); 00117 } 00118 00119 function &getLanguageLinks() { return $this->mLanguageLinks; } 00120 function getInterwikiLinks() { return $this->mInterwikiLinks; } 00121 function getCategoryLinks() { return array_keys( $this->mCategories ); } 00122 function &getCategories() { return $this->mCategories; } 00123 function getTitleText() { return $this->mTitleText; } 00124 function getSections() { return $this->mSections; } 00125 function getEditSectionTokens() { return $this->mEditSectionTokens; } 00126 function &getLinks() { return $this->mLinks; } 00127 function &getTemplates() { return $this->mTemplates; } 00128 function &getTemplateIds() { return $this->mTemplateIds; } 00129 function &getImages() { return $this->mImages; } 00130 function &getFileSearchOptions() { return $this->mFileSearchOptions; } 00131 function &getExternalLinks() { return $this->mExternalLinks; } 00132 function getNoGallery() { return $this->mNoGallery; } 00133 function getHeadItems() { return $this->mHeadItems; } 00134 function getModules() { return $this->mModules; } 00135 function getModuleScripts() { return $this->mModuleScripts; } 00136 function getModuleStyles() { return $this->mModuleStyles; } 00137 function getModuleMessages() { return $this->mModuleMessages; } 00138 function getOutputHooks() { return (array)$this->mOutputHooks; } 00139 function getWarnings() { return array_keys( $this->mWarnings ); } 00140 function getIndexPolicy() { return $this->mIndexPolicy; } 00141 function getTOCHTML() { return $this->mTOCHTML; } 00142 function getTimestamp() { return $this->mTimestamp; } 00143 function getLimitReportData() { return $this->mLimitReportData; } 00144 function getTOCEnabled() { return $this->mTOCEnabled; } 00145 00146 function setText( $text ) { return wfSetVar( $this->mText, $text ); } 00147 function setLanguageLinks( $ll ) { return wfSetVar( $this->mLanguageLinks, $ll ); } 00148 function setCategoryLinks( $cl ) { return wfSetVar( $this->mCategories, $cl ); } 00149 00150 function setTitleText( $t ) { return wfSetVar( $this->mTitleText, $t ); } 00151 function setSections( $toc ) { return wfSetVar( $this->mSections, $toc ); } 00152 function setEditSectionTokens( $t ) { return wfSetVar( $this->mEditSectionTokens, $t ); } 00153 function setIndexPolicy( $policy ) { return wfSetVar( $this->mIndexPolicy, $policy ); } 00154 function setTOCHTML( $tochtml ) { return wfSetVar( $this->mTOCHTML, $tochtml ); } 00155 function setTimestamp( $timestamp ) { return wfSetVar( $this->mTimestamp, $timestamp ); } 00156 function setTOCEnabled( $flag ) { return wfSetVar( $this->mTOCEnabled, $flag ); } 00157 00158 function addCategory( $c, $sort ) { $this->mCategories[$c] = $sort; } 00159 function addLanguageLink( $t ) { $this->mLanguageLinks[] = $t; } 00160 function addWarning( $s ) { $this->mWarnings[$s] = 1; } 00161 00162 function addOutputHook( $hook, $data = false ) { 00163 $this->mOutputHooks[] = array( $hook, $data ); 00164 } 00165 00166 function setNewSection( $value ) { 00167 $this->mNewSection = (bool)$value; 00168 } 00169 function hideNewSection( $value ) { 00170 $this->mHideNewSection = (bool)$value; 00171 } 00172 function getHideNewSection() { 00173 return (bool)$this->mHideNewSection; 00174 } 00175 function getNewSection() { 00176 return (bool)$this->mNewSection; 00177 } 00178 00186 static function isLinkInternal( $internal, $url ) { 00187 return (bool)preg_match( '/^' . 00188 # If server is proto relative, check also for http/https links 00189 ( substr( $internal, 0, 2 ) === '//' ? '(?:https?:)?' : '' ) . 00190 preg_quote( $internal, '/' ) . 00191 # check for query/path/anchor or end of link in each case 00192 '(?:[\?\/\#]|$)/i', 00193 $url 00194 ); 00195 } 00196 00197 function addExternalLink( $url ) { 00198 # We don't register links pointing to our own server, unless... :-) 00199 global $wgServer, $wgRegisterInternalExternals; 00200 00201 $registerExternalLink = true; 00202 if ( !$wgRegisterInternalExternals ) { 00203 $registerExternalLink = !self::isLinkInternal( $wgServer, $url ); 00204 } 00205 if ( $registerExternalLink ) { 00206 $this->mExternalLinks[$url] = 1; 00207 } 00208 } 00209 00216 function addLink( Title $title, $id = null ) { 00217 if ( $title->isExternal() ) { 00218 // Don't record interwikis in pagelinks 00219 $this->addInterwikiLink( $title ); 00220 return; 00221 } 00222 $ns = $title->getNamespace(); 00223 $dbk = $title->getDBkey(); 00224 if ( $ns == NS_MEDIA ) { 00225 // Normalize this pseudo-alias if it makes it down here... 00226 $ns = NS_FILE; 00227 } elseif ( $ns == NS_SPECIAL ) { 00228 // We don't record Special: links currently 00229 // It might actually be wise to, but we'd need to do some normalization. 00230 return; 00231 } elseif ( $dbk === '' ) { 00232 // Don't record self links - [[#Foo]] 00233 return; 00234 } 00235 if ( !isset( $this->mLinks[$ns] ) ) { 00236 $this->mLinks[$ns] = array(); 00237 } 00238 if ( is_null( $id ) ) { 00239 $id = $title->getArticleID(); 00240 } 00241 $this->mLinks[$ns][$dbk] = $id; 00242 } 00243 00251 function addImage( $name, $timestamp = null, $sha1 = null ) { 00252 $this->mImages[$name] = 1; 00253 if ( $timestamp !== null && $sha1 !== null ) { 00254 $this->mFileSearchOptions[$name] = array( 'time' => $timestamp, 'sha1' => $sha1 ); 00255 } 00256 } 00257 00265 function addTemplate( $title, $page_id, $rev_id ) { 00266 $ns = $title->getNamespace(); 00267 $dbk = $title->getDBkey(); 00268 if ( !isset( $this->mTemplates[$ns] ) ) { 00269 $this->mTemplates[$ns] = array(); 00270 } 00271 $this->mTemplates[$ns][$dbk] = $page_id; 00272 if ( !isset( $this->mTemplateIds[$ns] ) ) { 00273 $this->mTemplateIds[$ns] = array(); 00274 } 00275 $this->mTemplateIds[$ns][$dbk] = $rev_id; // For versioning 00276 } 00277 00282 function addInterwikiLink( $title ) { 00283 $prefix = $title->getInterwiki(); 00284 if ( $prefix == '' ) { 00285 throw new MWException( 'Non-interwiki link passed, internal parser error.' ); 00286 } 00287 if ( !isset( $this->mInterwikiLinks[$prefix] ) ) { 00288 $this->mInterwikiLinks[$prefix] = array(); 00289 } 00290 $this->mInterwikiLinks[$prefix][$title->getDBkey()] = 1; 00291 } 00292 00298 function addHeadItem( $section, $tag = false ) { 00299 if ( $tag !== false ) { 00300 $this->mHeadItems[$tag] = $section; 00301 } else { 00302 $this->mHeadItems[] = $section; 00303 } 00304 } 00305 00306 public function addModules( $modules ) { 00307 $this->mModules = array_merge( $this->mModules, (array)$modules ); 00308 } 00309 00310 public function addModuleScripts( $modules ) { 00311 $this->mModuleScripts = array_merge( $this->mModuleScripts, (array)$modules ); 00312 } 00313 00314 public function addModuleStyles( $modules ) { 00315 $this->mModuleStyles = array_merge( $this->mModuleStyles, (array)$modules ); 00316 } 00317 00318 public function addModuleMessages( $modules ) { 00319 $this->mModuleMessages = array_merge( $this->mModuleMessages, (array)$modules ); 00320 } 00321 00327 public function addOutputPageMetadata( OutputPage $out ) { 00328 $this->addModules( $out->getModules() ); 00329 $this->addModuleScripts( $out->getModuleScripts() ); 00330 $this->addModuleStyles( $out->getModuleStyles() ); 00331 $this->addModuleMessages( $out->getModuleMessages() ); 00332 00333 $this->mHeadItems = array_merge( $this->mHeadItems, $out->getHeadItemsArray() ); 00334 $this->mPreventClickjacking = $this->mPreventClickjacking || $out->getPreventClickjacking(); 00335 } 00336 00344 public function setDisplayTitle( $text ) { 00345 $this->setTitleText( $text ); 00346 $this->setProperty( 'displaytitle', $text ); 00347 } 00348 00354 public function getDisplayTitle() { 00355 $t = $this->getTitleText(); 00356 if ( $t === '' ) { 00357 return false; 00358 } 00359 return $t; 00360 } 00361 00365 public function setFlag( $flag ) { 00366 $this->mFlags[$flag] = true; 00367 } 00368 00369 public function getFlag( $flag ) { 00370 return isset( $this->mFlags[$flag] ); 00371 } 00372 00430 public function setProperty( $name, $value ) { 00431 $this->mProperties[$name] = $value; 00432 } 00433 00434 public function getProperty( $name ) { 00435 return isset( $this->mProperties[$name] ) ? $this->mProperties[$name] : false; 00436 } 00437 00438 public function getProperties() { 00439 if ( !isset( $this->mProperties ) ) { 00440 $this->mProperties = array(); 00441 } 00442 return $this->mProperties; 00443 } 00444 00450 public function getUsedOptions() { 00451 if ( !isset( $this->mAccessedOptions ) ) { 00452 return array(); 00453 } 00454 return array_keys( $this->mAccessedOptions ); 00455 } 00456 00461 function recordOption( $option ) { 00462 $this->mAccessedOptions[$option] = true; 00463 } 00464 00473 public function addSecondaryDataUpdate( DataUpdate $update ) { 00474 $this->mSecondaryDataUpdates[] = $update; 00475 } 00476 00493 public function getSecondaryDataUpdates( Title $title = null, $recursive = true ) { 00494 if ( is_null( $title ) ) { 00495 $title = Title::newFromText( $this->getTitleText() ); 00496 } 00497 00498 $linksUpdate = new LinksUpdate( $title, $this, $recursive ); 00499 00500 return array_merge( $this->mSecondaryDataUpdates, array( $linksUpdate ) ); 00501 } 00502 00544 public function setExtensionData( $key, $value ) { 00545 if ( $value === null ) { 00546 unset( $this->mExtensionData[$key] ); 00547 } else { 00548 $this->mExtensionData[$key] = $value; 00549 } 00550 } 00551 00563 public function getExtensionData( $key ) { 00564 if ( isset( $this->mExtensionData[$key] ) ) { 00565 return $this->mExtensionData[$key]; 00566 } 00567 00568 return null; 00569 } 00570 00571 private static function getTimes( $clock = null ) { 00572 $ret = array(); 00573 if ( !$clock || $clock === 'wall' ) { 00574 $ret['wall'] = microtime( true ); 00575 } 00576 if ( ( !$clock || $clock === 'cpu' ) && function_exists( 'getrusage' ) ) { 00577 $ru = getrusage(); 00578 $ret['cpu'] = $ru['ru_utime.tv_sec'] + $ru['ru_utime.tv_usec'] / 1e6; 00579 $ret['cpu'] += $ru['ru_stime.tv_sec'] + $ru['ru_stime.tv_usec'] / 1e6; 00580 } 00581 return $ret; 00582 } 00583 00588 function resetParseStartTime() { 00589 $this->mParseStartTime = self::getTimes(); 00590 } 00591 00603 function getTimeSinceStart( $clock ) { 00604 if ( !isset( $this->mParseStartTime[$clock] ) ) { 00605 return null; 00606 } 00607 00608 $end = self::getTimes( $clock ); 00609 return $end[$clock] - $this->mParseStartTime[$clock]; 00610 } 00611 00631 function setLimitReportData( $key, $value ) { 00632 $this->mLimitReportData[$key] = $value; 00633 } 00634 00642 public function preventClickjacking( $flag = null ) { 00643 return wfSetVar( $this->mPreventClickjacking, $flag ); 00644 } 00645 }