<?php /** * Options for the PHP parser * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file * @ingroup Parser */ /** * \brief Set options of the Parser * * All member variables are supposed to be private in theory, although in practise this is not the case. * * @ingroup Parser */ class ParserOptions { /** * Interlanguage links are removed and returned in an array */ var $mInterwikiMagic; /** * Allow external images inline? */ var $mAllowExternalImages; /** * If not, any exception? */ var $mAllowExternalImagesFrom; /** * If not or it doesn't match, should we check an on-wiki whitelist? */ var $mEnableImageWhitelist; /** * Date format index */ var $mDateFormat = null; /** * Create "edit section" links? */ var $mEditSection = true; /** * Allow inclusion of special pages? */ var $mAllowSpecialInclusion; /** * Use tidy to cleanup output HTML? */ var $mTidy = false; /** * Which lang to call for PLURAL and GRAMMAR */ var $mInterfaceMessage = false; /** * Overrides $mInterfaceMessage with arbitrary language */ var $mTargetLanguage = null; /** * Maximum size of template expansions, in bytes */ var $mMaxIncludeSize; /** * Maximum number of nodes touched by PPFrame::expand() */ var $mMaxPPNodeCount; /** * Maximum number of nodes generated by Preprocessor::preprocessToObj() */ var $mMaxGeneratedPPNodeCount; /** * Maximum recursion depth in PPFrame::expand() */ var $mMaxPPExpandDepth; /** * Maximum recursion depth for templates within templates */ var $mMaxTemplateDepth; /** * Maximum number of calls per parse to expensive parser functions */ var $mExpensiveParserFunctionLimit; /** * Remove HTML comments. ONLY APPLIES TO PREPROCESS OPERATIONS */ var $mRemoveComments = true; /** * Callback for template fetching. Used as first argument to call_user_func(). */ var $mTemplateCallback = array( 'Parser', 'statelessFetchTemplate' ); /** * Enable limit report in an HTML comment on output */ var $mEnableLimitReport = false; /** * Timestamp used for {{CURRENTDAY}} etc. */ var $mTimestamp; /** * Target attribute for external links */ var $mExternalLinkTarget; /** * Clean up signature texts? * * 1) Strip ~~~, ~~~~ and ~~~~~ out of signatures * 2) Substitute all transclusions */ var $mCleanSignatures; /** * Transform wiki markup when saving the page? */ var $mPreSaveTransform = true; /** * Whether content conversion should be disabled */ var $mDisableContentConversion; /** * Whether title conversion should be disabled */ var $mDisableTitleConversion; /** * Automatically number headings? */ var $mNumberHeadings; /** * User math preference (as integer). Not used (1.19) */ var $mMath; /** * Thumb size preferred by the user. */ var $mThumbSize; /** * Maximum article size of an article to be marked as "stub" */ private $mStubThreshold; /** * Language object of the User language. */ var $mUserLang; /** * @var User * Stored user object */ var $mUser; /** * Parsing the page for a "preview" operation? */ var $mIsPreview = false; /** * Parsing the page for a "preview" operation on a single section? */ var $mIsSectionPreview = false; /** * Parsing the printable version of the page? */ var $mIsPrintable = false; /** * Extra key that should be present in the caching key. */ var $mExtraKey = ''; /** * Function to be called when an option is accessed. */ protected $onAccessCallback = null; function getInterwikiMagic() { return $this->mInterwikiMagic; } function getAllowExternalImages() { return $this->mAllowExternalImages; } function getAllowExternalImagesFrom() { return $this->mAllowExternalImagesFrom; } function getEnableImageWhitelist() { return $this->mEnableImageWhitelist; } function getEditSection() { return $this->mEditSection; } function getNumberHeadings() { $this->optionUsed( 'numberheadings' ); return $this->mNumberHeadings; } function getAllowSpecialInclusion() { return $this->mAllowSpecialInclusion; } function getTidy() { return $this->mTidy; } function getInterfaceMessage() { return $this->mInterfaceMessage; } function getTargetLanguage() { return $this->mTargetLanguage; } function getMaxIncludeSize() { return $this->mMaxIncludeSize; } function getMaxPPNodeCount() { return $this->mMaxPPNodeCount; } function getMaxGeneratedPPNodeCount() { return $this->mMaxGeneratedPPNodeCount; } function getMaxPPExpandDepth() { return $this->mMaxPPExpandDepth; } function getMaxTemplateDepth() { return $this->mMaxTemplateDepth; } /* @since 1.20 */ function getExpensiveParserFunctionLimit() { return $this->mExpensiveParserFunctionLimit; } function getRemoveComments() { return $this->mRemoveComments; } function getTemplateCallback() { return $this->mTemplateCallback; } function getEnableLimitReport() { return $this->mEnableLimitReport; } function getCleanSignatures() { return $this->mCleanSignatures; } function getExternalLinkTarget() { return $this->mExternalLinkTarget; } function getDisableContentConversion() { return $this->mDisableContentConversion; } function getDisableTitleConversion() { return $this->mDisableTitleConversion; } /** @deprecated since 1.22 use User::getOption('math') instead */ function getMath() { $this->optionUsed( 'math' ); return $this->mMath; } function getThumbSize() { $this->optionUsed( 'thumbsize' ); return $this->mThumbSize; } function getStubThreshold() { $this->optionUsed( 'stubthreshold' ); return $this->mStubThreshold; } function getIsPreview() { return $this->mIsPreview; } function getIsSectionPreview() { return $this->mIsSectionPreview; } function getIsPrintable() { $this->optionUsed( 'printable' ); return $this->mIsPrintable; } function getUser() { return $this->mUser; } function getPreSaveTransform() { return $this->mPreSaveTransform; } /** * @param $title Title * @return Skin * @deprecated since 1.18 Use Linker::* instead */ function getSkin( $title = null ) { wfDeprecated( __METHOD__, '1.18' ); return new DummyLinker; } function getDateFormat() { $this->optionUsed( 'dateformat' ); if ( !isset( $this->mDateFormat ) ) { $this->mDateFormat = $this->mUser->getDatePreference(); } return $this->mDateFormat; } function getTimestamp() { if ( !isset( $this->mTimestamp ) ) { $this->mTimestamp = wfTimestampNow(); } return $this->mTimestamp; } /** * Get the user language used by the parser for this page. * * You shouldn't use this. Really. $parser->getFunctionLang() is all you need. * * To avoid side-effects where the page will be rendered based on the language * of the user who last saved, this function will triger a cache fragmentation. * Usage of this method is discouraged for that reason. * * When saving, this will return the default language instead of the user's. * * {{int: }} uses this which used to produce inconsistent link tables (bug 14404). * * @return Language object * @since 1.19 */ function getUserLangObj() { $this->optionUsed( 'userlang' ); return $this->mUserLang; } /** * Same as getUserLangObj() but returns a string instead. * * @return String Language code * @since 1.17 */ function getUserLang() { return $this->getUserLangObj()->getCode(); } function setInterwikiMagic( $x ) { return wfSetVar( $this->mInterwikiMagic, $x ); } function setAllowExternalImages( $x ) { return wfSetVar( $this->mAllowExternalImages, $x ); } function setAllowExternalImagesFrom( $x ) { return wfSetVar( $this->mAllowExternalImagesFrom, $x ); } function setEnableImageWhitelist( $x ) { return wfSetVar( $this->mEnableImageWhitelist, $x ); } function setDateFormat( $x ) { return wfSetVar( $this->mDateFormat, $x ); } function setEditSection( $x ) { return wfSetVar( $this->mEditSection, $x ); } function setNumberHeadings( $x ) { return wfSetVar( $this->mNumberHeadings, $x ); } function setAllowSpecialInclusion( $x ) { return wfSetVar( $this->mAllowSpecialInclusion, $x ); } function setTidy( $x ) { return wfSetVar( $this->mTidy, $x ); } /** @deprecated in 1.19 */ function setSkin( $x ) { wfDeprecated( __METHOD__, '1.19' ); } function setInterfaceMessage( $x ) { return wfSetVar( $this->mInterfaceMessage, $x ); } function setTargetLanguage( $x ) { return wfSetVar( $this->mTargetLanguage, $x, true ); } function setMaxIncludeSize( $x ) { return wfSetVar( $this->mMaxIncludeSize, $x ); } function setMaxPPNodeCount( $x ) { return wfSetVar( $this->mMaxPPNodeCount, $x ); } function setMaxGeneratedPPNodeCount( $x ) { return wfSetVar( $this->mMaxGeneratedPPNodeCount, $x ); } function setMaxTemplateDepth( $x ) { return wfSetVar( $this->mMaxTemplateDepth, $x ); } /* @since 1.20 */ function setExpensiveParserFunctionLimit( $x ) { return wfSetVar( $this->mExpensiveParserFunctionLimit, $x ); } function setRemoveComments( $x ) { return wfSetVar( $this->mRemoveComments, $x ); } function setTemplateCallback( $x ) { return wfSetVar( $this->mTemplateCallback, $x ); } function enableLimitReport( $x = true ) { return wfSetVar( $this->mEnableLimitReport, $x ); } function setTimestamp( $x ) { return wfSetVar( $this->mTimestamp, $x ); } function setCleanSignatures( $x ) { return wfSetVar( $this->mCleanSignatures, $x ); } function setExternalLinkTarget( $x ) { return wfSetVar( $this->mExternalLinkTarget, $x ); } function disableContentConversion( $x = true ) { return wfSetVar( $this->mDisableContentConversion, $x ); } function disableTitleConversion( $x = true ) { return wfSetVar( $this->mDisableTitleConversion, $x ); } /** @deprecated since 1.22 */ function setMath( $x ) { return wfSetVar( $this->mMath, $x ); } function setUserLang( $x ) { if ( is_string( $x ) ) { $x = Language::factory( $x ); } return wfSetVar( $this->mUserLang, $x ); } function setThumbSize( $x ) { return wfSetVar( $this->mThumbSize, $x ); } function setStubThreshold( $x ) { return wfSetVar( $this->mStubThreshold, $x ); } function setPreSaveTransform( $x ) { return wfSetVar( $this->mPreSaveTransform, $x ); } function setIsPreview( $x ) { return wfSetVar( $this->mIsPreview, $x ); } function setIsSectionPreview( $x ) { return wfSetVar( $this->mIsSectionPreview, $x ); } function setIsPrintable( $x ) { return wfSetVar( $this->mIsPrintable, $x ); } /** * Extra key that should be present in the parser cache key. */ function addExtraKey( $key ) { $this->mExtraKey .= '!' . $key; } /** * Constructor * @param $user User object * @param $lang Language object */ function __construct( $user = null, $lang = null ) { if ( $user === null ) { global $wgUser; if ( $wgUser === null ) { $user = new User; } else { $user = $wgUser; } } if ( $lang === null ) { global $wgLang; if ( !StubObject::isRealObject( $wgLang ) ) { $wgLang->_unstub(); } $lang = $wgLang; } $this->initialiseFromUser( $user, $lang ); } /** * Get a ParserOptions object from a given user. * Language will be taken from $wgLang. * * @param $user User object * @return ParserOptions object */ public static function newFromUser( $user ) { return new ParserOptions( $user ); } /** * Get a ParserOptions object from a given user and language * * @param $user User object * @param $lang Language object * @return ParserOptions object */ public static function newFromUserAndLang( User $user, Language $lang ) { return new ParserOptions( $user, $lang ); } /** * Get a ParserOptions object from a IContextSource object * * @param $context IContextSource object * @return ParserOptions object */ public static function newFromContext( IContextSource $context ) { return new ParserOptions( $context->getUser(), $context->getLanguage() ); } /** * Get user options * * @param $user User object * @param $lang Language object */ private function initialiseFromUser( $user, $lang ) { global $wgInterwikiMagic, $wgAllowExternalImages, $wgAllowExternalImagesFrom, $wgEnableImageWhitelist, $wgAllowSpecialInclusion, $wgMaxArticleSize, $wgMaxPPNodeCount, $wgMaxTemplateDepth, $wgMaxPPExpandDepth, $wgCleanSignatures, $wgExternalLinkTarget, $wgExpensiveParserFunctionLimit, $wgMaxGeneratedPPNodeCount, $wgDisableLangConversion, $wgDisableTitleConversion; wfProfileIn( __METHOD__ ); $this->mInterwikiMagic = $wgInterwikiMagic; $this->mAllowExternalImages = $wgAllowExternalImages; $this->mAllowExternalImagesFrom = $wgAllowExternalImagesFrom; $this->mEnableImageWhitelist = $wgEnableImageWhitelist; $this->mAllowSpecialInclusion = $wgAllowSpecialInclusion; $this->mMaxIncludeSize = $wgMaxArticleSize * 1024; $this->mMaxPPNodeCount = $wgMaxPPNodeCount; $this->mMaxGeneratedPPNodeCount = $wgMaxGeneratedPPNodeCount; $this->mMaxPPExpandDepth = $wgMaxPPExpandDepth; $this->mMaxTemplateDepth = $wgMaxTemplateDepth; $this->mExpensiveParserFunctionLimit = $wgExpensiveParserFunctionLimit; $this->mCleanSignatures = $wgCleanSignatures; $this->mExternalLinkTarget = $wgExternalLinkTarget; $this->mDisableContentConversion = $wgDisableLangConversion; $this->mDisableTitleConversion = $wgDisableLangConversion || $wgDisableTitleConversion; $this->mUser = $user; $this->mNumberHeadings = $user->getOption( 'numberheadings' ); $this->mMath = $user->getOption( 'math' ); $this->mThumbSize = $user->getOption( 'thumbsize' ); $this->mStubThreshold = $user->getStubThreshold(); $this->mUserLang = $lang; wfProfileOut( __METHOD__ ); } /** * Registers a callback for tracking which ParserOptions which are used. * This is a private API with the parser. */ function registerWatcher( $callback ) { $this->onAccessCallback = $callback; } /** * Called when an option is accessed. */ protected function optionUsed( $optionName ) { if ( $this->onAccessCallback ) { call_user_func( $this->onAccessCallback, $optionName ); } } /** * Returns the full array of options that would have been used by * in 1.16. * Used to get the old parser cache entries when available. * @return array */ public static function legacyOptions() { return array( 'math', 'stubthreshold', 'numberheadings', 'userlang', 'thumbsize', 'editsection', 'printable' ); } /** * Generate a hash string with the values set on these ParserOptions * for the keys given in the array. * This will be used as part of the hash key for the parser cache, * so users sharign the options with vary for the same page share * the same cached data safely. * * Replaces User::getPageRenderingHash() * * Extensions which require it should install 'PageRenderingHash' hook, * which will give them a chance to modify this key based on their own * settings. * * @since 1.17 * @param $forOptions Array * @param $title Title: used to get the content language of the page (since r97636) * @return string Page rendering hash */ public function optionsHash( $forOptions, $title = null ) { global $wgRenderHashAppend; $confstr = ''; if ( in_array( 'math', $forOptions ) ) { $confstr .= $this->mMath; } else { $confstr .= '*'; } // Space assigned for the stubthreshold but unused // since it disables the parser cache, its value will always // be 0 when this function is called by parsercache. if ( in_array( 'stubthreshold', $forOptions ) ) { $confstr .= '!' . $this->mStubThreshold; } else { $confstr .= '!*'; } if ( in_array( 'dateformat', $forOptions ) ) { $confstr .= '!' . $this->getDateFormat(); } if ( in_array( 'numberheadings', $forOptions ) ) { $confstr .= '!' . ( $this->mNumberHeadings ? '1' : '' ); } else { $confstr .= '!*'; } if ( in_array( 'userlang', $forOptions ) ) { $confstr .= '!' . $this->mUserLang->getCode(); } else { $confstr .= '!*'; } if ( in_array( 'thumbsize', $forOptions ) ) { $confstr .= '!' . $this->mThumbSize; } else { $confstr .= '!*'; } // add in language specific options, if any // @todo FIXME: This is just a way of retrieving the url/user preferred variant if ( !is_null( $title ) ) { $confstr .= $title->getPageLanguage()->getExtraHashOptions(); } else { global $wgContLang; $confstr .= $wgContLang->getExtraHashOptions(); } $confstr .= $wgRenderHashAppend; if ( !in_array( 'editsection', $forOptions ) ) { $confstr .= '!*'; } elseif ( !$this->mEditSection ) { $confstr .= '!edit=0'; } if ( $this->mIsPrintable && in_array( 'printable', $forOptions ) ) { $confstr .= '!printable=1'; } if ( $this->mExtraKey != '' ) { $confstr .= $this->mExtraKey; } // Give a chance for extensions to modify the hash, if they have // extra options or other effects on the parser cache. wfRunHooks( 'PageRenderingHash', array( &$confstr ) ); // Make it a valid memcached key fragment $confstr = str_replace( ' ', '_', $confstr ); return $confstr; } }