ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
Parser Class Reference
+ Inheritance diagram for Parser:
+ Collaboration diagram for Parser:

Public Member Functions

 __construct ()
 #- More...
 
 firstCallInit ()
 Do various kinds of initialisation on the first call of the parser. More...
 
 clearState ()
 Clear Parser state. More...
 
 setOutputType ($ot)
 
 uniqPrefix ()
 Accessor for mUniqPrefix. More...
 
 parse ($text, &$title, $options, $linestart=true, $clearState=true, $revid=null)
 Convert wikitext to HTML Do not call this function recursively. More...
 
 recursiveTagParse ($text)
 Recursive parser entry point that can be called from an extension tag hook. More...
 
 preprocess ($text, $title, $options)
 Expand templates and variables in the text, producing valid, static wikitext. More...
 
getTitle ()
 
 getOptions ()
 
 getFunctionLang ()
 
 strip ($text, $state, $stripcomments=false, $dontstrip=array())
 Strips and renders nowiki, pre, math, hiero If $render is set, performs necessary rendering operations on plugins Returns the text, and fills an array with data needed in unstrip() More...
 
 unstrip ($text, $state)
 Restores pre, math, and other extensions removed by strip() More...
 
 unstripNoWiki ($text, $state)
 Always call this after unstrip() to preserve the order. More...
 
 unstripForHTML ($text)
 
 insertStripItem ($text, &$state)
 Add an item to the strip state Returns the unique tag which must be inserted into the stripped text The tag will be replaced with the original text in unstrip() More...
 
 doTableStuff ($text)
 parse the wiki syntax used to render tables More...
 
 internalParse ($text)
 Helper function for parse() that transforms wiki markup into HTML. More...
 
doMagicLinks (&$text)
 Replace special strings like "ISBN xxx" and "RFC xxx" with magic external links. More...
 
 magicLinkCallback ($m)
 
 doHeadings ($text)
 Parse headers and return html. More...
 
 doAllQuotes ($text)
 Replace single quotes with HTML markup. More...
 
 doQuotes ($text)
 Helper function for doAllQuotes() More...
 
 replaceExternalLinks ($text)
 Replace external links. More...
 
 replaceFreeExternalLinks ($text)
 Replace anything that looks like a URL with a link. More...
 
 maybeMakeExternalImage ($url)
 make an image if it's allowed, either through the global option or through the exception More...
 
 replaceInternalLinks ($s)
 Process [[ ]] wikilinks. More...
 
 makeLinkHolder (&$nt, $text='', $query='', $trail='', $prefix='')
 Make a link placeholder. More...
 
 makeKnownLinkHolder ($nt, $text='', $query='', $trail='', $prefix='')
 Render a forced-blue link inline; protect against double expansion of URLs if we're in a mode that prepends full URL prefixes to internal links. More...
 
 armorLinks ($text)
 Insert a NOPARSE hacky thing into any inline links in a chunk that's going to go through further parsing steps before inline URL expansion. More...
 
 areSubpagesAllowed ()
 Return true if subpage links should be expanded on this page. More...
 
 maybeDoSubpageLink ($target, &$text)
 Handle link to subpage if necessary. More...
 
 closeParagraph ()
 #+ Used by doBlockLevels() More...
 
 getCommon ($st1, $st2)
 
 openList ($char)
 
 nextItem ($char)
 
 closeList ($char)
 
 doBlockLevels ($text, $linestart)
 #- More...
 
 findColonNoLinks ($str, &$before, &$after)
 Split up a string on ':', ignoring any occurences inside tags to prevent illegal overlapping. More...
 
 getVariableValue ($index)
 Return value of a magic variable (like PAGENAME) More...
 
 initialiseVariables ()
 initialise the magic variables (like CURRENTMONTHNAME) More...
 
 replace_callback ($text, $callbacks)
 parse any parentheses in format ((title|part|part)) and call callbacks to get a replacement text for any found piece More...
 
 replaceVariables ($text, $args=array(), $argsOnly=false)
 Replace magic variables, templates, and template arguments with the appropriate text. More...
 
 variableSubstitution ($matches)
 Replace magic variables. More...
 
 braceSubstitution ($piece)
 Return the text of a template, after recursively replacing any variables or templates within the template. More...
 
 fetchTemplate ($title)
 Fetch the unparsed text of a template and register a reference to it. More...
 
 interwikiTransclude ($title, $action)
 Transclude an interwiki link. More...
 
 fetchScaryTemplateMaybeFromCache ($url)
 
 argSubstitution ($matches)
 Triple brace replacement – used for template arguments. More...
 
 incrementIncludeSize ($type, $size)
 Increment an include size counter. More...
 
 stripNoGallery (&$text)
 Detect NOGALLERY magic word and set a placeholder. More...
 
 stripToc ($text)
 Detect TOC magic word and set a placeholder. More...
 
 formatHeadings ($text, $isMain=true)
 This function accomplishes several tasks: 1) Auto-number headings if that option is enabled 2) Add an [edit] link to sections for logged in users who have enabled the option 3) Add a Table of contents on the top for users who have enabled the option 4) Auto-anchor headings. More...
 
 preSaveTransform ($text, &$title, $user, $options, $clearState=true)
 Transform wiki markup when saving a page by doing \r
->
conversion, substitting signatures, {{subst:}} templates, etc. More...
 
 pstPass2 ($text, &$stripState, $user)
 Pre-save transform helper function. More...
 
 getUserSig (&$user)
 Fetch the user's signature text, if any, and normalize to validated, ready-to-insert wikitext. More...
 
 validateSig ($text)
 Check that the user's signature contains no bad XML. More...
 
 cleanSig ($text, $parsing=false)
 Clean up signature text. More...
 
 cleanSigInSig ($text)
 Strip ~~~, ~~~~ and ~~~~~ out of signatures. More...
 
 startExternalParse (&$title, $options, $outputType, $clearState=true)
 Set up some variables which are usually set up in parse() so that an external function can call some class members with confidence. More...
 
 transformMsg ($text, $options)
 Transform a MediaWiki message by replacing magic variables. More...
 
 setHook ($tag, $callback)
 Create an HTML-style tag, e.g. More...
 
 setFunctionHook ($id, $callback, $flags=0)
 Create a function, e.g. More...
 
 getFunctionHooks ()
 Get all registered function hook identifiers. More...
 
 replaceLinkHolders (&$text, $options=0)
 Replace link placeholders with actual links, in the buffer Placeholders created in Skin::makeLinkObj() Returns an array of links found, indexed by PDBK: 0 - broken 1 - normal link 2 - stub $options is a bit field, RLH_FOR_UPDATE to select for update. More...
 
 replaceLinkHoldersText ($text)
 Replace link placeholders with plain text of links (not HTML-formatted). More...
 
 replaceLinkHoldersTextCallback ($matches)
 
 renderPreTag ($text, $attribs)
 Tag hook handler for 'pre'. More...
 
 renderImageGallery ($text, $params)
 Renders an image gallery from a text with one line per image. More...
 
 makeImage ($nt, $options)
 Parse image options text and use it to make an image. More...
 
 disableCache ()
 Set a flag in the output object indicating that the content is dynamic and shouldn't be cached. More...
 
 attributeStripCallback (&$text, $args)
 #+ Callback from the Sanitizer for expanding items found in HTML attribute values, so they can be safely tested and escaped. More...
 
 Title ($x=null)
 #- More...
 
 Options ($x=null)
 
 OutputType ($x=null)
 
 getTags ()
 #- More...
 
 getSection ($text, $section, $deftext='')
 This function returns the text of a section, specified by a number ($section). More...
 
 replaceSection ($oldtext, $section, $text)
 
 getRevisionTimestamp ()
 Get the timestamp associated with the current revision, adjusted for the default server-local timestamp. More...
 
 setDefaultSort ($sort)
 Mutator for $mDefaultSort. More...
 
 getDefaultSort ()
 Accessor for $mDefaultSort Will use the title/prefixed title if none is set. More...
 

Static Public Member Functions

 getRandomString ()
 Get a random string. More...
 
 extractTagsAndParams ($elements, $text, &$matches, $uniq_prefix='')
 Replaces all occurrences of HTML-style comments and the given tags in the text with a random marker and returns teh next text. More...
 
 tidy ($text)
 Interface with html tidy, used if $wgUseTidy = true. More...
 
 externalTidy ($text)
 Spawn an external HTML tidy process and get corrected markup back from it. More...
 
 internalTidy ($text)
 Use the HTML tidy PECL extension to use the tidy library in-process, saving the overhead of spawning a new process. More...
 
static replaceUnusualEscapes ($url)
 Replace unusual URL escape codes with their equivalent characters. More...
 
static createAssocArgs ($args)
 Clean up argument array - refactored in 1.9 so parserfunctions can use it, too. More...
 

Data Fields

const VERSION = MW_PARSER_VERSION
 
 $mTagHooks
 #+ More...
 
 $mFunctionHooks
 
 $mFunctionSynonyms
 
 $mVariables
 
 $mOutput
 
 $mAutonumber
 
 $mDTopen
 
 $mStripState
 
 $mIncludeCount
 
 $mArgStack
 
 $mLastSection
 
 $mInPre
 
 $mInterwikiLinkHolders
 
 $mLinkHolders
 
 $mUniqPrefix
 
 $mIncludeSizes
 
 $mDefaultSort
 
 $mTemplates
 
 $mTemplatePath
 
 $mOptions
 
 $mTitle
 
 $mOutputType
 
 $ot
 
 $mRevisionId
 
 $mRevisionTimestamp
 
 $mRevIdForTs
 

Private Member Functions

 extractSections ($text, $section, $mode, $newtext='')
 #- More...
 

Static Private Member Functions

static replaceUnusualEscapesCallback ($matches)
 Callback function used in replaceUnusualEscapes(). More...
 

Detailed Description

Definition at line 90 of file Parser.php.

Constructor & Destructor Documentation

◆ __construct()

Parser::__construct ( )

#-

Constructor

Reimplemented in ilMWParserAdapter.

Definition at line 145 of file Parser.php.

148 {
149 $this->mTagHooks = array();
150 $this->mFunctionHooks = array();
151 $this->mFunctionSynonyms = array( 0 => array(), 1 => array() );

Member Function Documentation

◆ areSubpagesAllowed()

Parser::areSubpagesAllowed ( )

Return true if subpage links should be expanded on this page.

Returns
bool

Definition at line 1990 of file Parser.php.

1993 {
1994 # Some namespaces don't allow subpages
1995 global $wgNamespacesWithSubpages;

◆ argSubstitution()

Parser::argSubstitution (   $matches)

Triple brace replacement – used for template arguments.

Definition at line 3494 of file Parser.php.

3497 {
3498 $arg = trim($matches['title']);
3499 $text = $matches['text'];
3500 $inputArgs = end($this->mArgStack);
3501
3502 if (array_key_exists($arg, $inputArgs)) {
3503 $text = $inputArgs[$arg];
3504 } elseif (($this->mOutputType == OT_HTML || $this->mOutputType == OT_PREPROCESS) &&
3505 null != $matches['parts'] && count($matches['parts']) > 0) {
3506 $text = $matches['parts'][0];
3507 }
3508 if (!$this->incrementIncludeSize('arg', strlen($text))) {
3509 $text = $matches['text'] .
3510 '<!-- WARNING: argument omitted, expansion size too large -->';
3511 }
3512
const OT_PREPROCESS
Definition: Parser.php:21
const OT_HTML
Definition: Parser.php:18
incrementIncludeSize($type, $size)
Increment an include size counter.
Definition: Parser.php:3521

◆ armorLinks()

Parser::armorLinks (   $text)

Insert a NOPARSE hacky thing into any inline links in a chunk that's going to go through further parsing steps before inline URL expansion.

In particular this is important when using action=render, which causes full URLs to be included.

Oh man I hate our multi-layer parser!

Parameters
stringmore-or-less HTML
Returns
string less-or-more HTML with NOPARSE bits

Definition at line 1977 of file Parser.php.

1980 {
1981 return preg_replace(
1982 '/\b(' . wfUrlProtocols() . ')/',
1983 "{$this->mUniqPrefix}NOPARSE$1",
1984 $text
if(!defined( 'UTF8_REPLACEMENT')) wfUrlProtocols()
Returns a regular expression of url protocols.

◆ attributeStripCallback()

Parser::attributeStripCallback ( $text,
  $args 
)

#+ Callback from the Sanitizer for expanding items found in HTML attribute values, so they can be safely tested and escaped.

Parameters
string$text
array$args
Returns
string

Definition at line 4712 of file Parser.php.

4715 {
4716 $text = $this->replaceVariables($text, $args);
4717 $text = $this->mStripState->unstripBoth($text);
replaceVariables($text, $args=array(), $argsOnly=false)
Replace magic variables, templates, and template arguments with the appropriate text.
Definition: Parser.php:2921

◆ braceSubstitution()

Parser::braceSubstitution (   $piece)

Return the text of a template, after recursively replacing any variables or templates within the template.

Parameters
array$pieceThe parts of the template $piece['text']: matched text $piece['title']: the title, i.e. the part before the | $piece['parts']: the parameter array
Returns
string the text of the template

Definition at line 3038 of file Parser.php.

3041 {
3042 global $wgContLang, $wgLang, $wgAllowDisplayTitle, $wgNonincludableNamespaces;
3043 $fname = __METHOD__ /*. '-L' . count( $this->mArgStack )*/;
3044 wfProfileIn($fname);
3045 wfProfileIn(__METHOD__ . '-setup');
3046
3047 # Flags
3048 $found = false; # $text has been filled
3049 $nowiki = false; # wiki markup in $text should be escaped
3050 $noparse = false; # Unsafe HTML tags should not be stripped, etc.
3051 $noargs = false; # Don't replace triple-brace arguments in $text
3052 $replaceHeadings = false; # Make the edit section links go to the template not the article
3053 $headingOffset = 0; # Skip headings when number, to account for those that weren't transcluded.
3054 $isHTML = false; # $text is HTML, armour it against wikitext transformation
3055 $forceRawInterwiki = false; # Force interwiki transclusion to be done in raw mode not rendered
3056
3057 # Title object, where $text came from
3058 $title = null;
3059
3060 $linestart = '';
3061
3062
3063 # $part1 is the bit before the first |, and must contain only title characters
3064 # $args is a list of arguments, starting from index 0, not including $part1
3065
3066 $titleText = $part1 = $piece['title'];
3067 # If the third subpattern matched anything, it will start with |
3068
3069 if (null == $piece['parts']) {
3070 $replaceWith = $this->variableSubstitution(array($piece['text'], $piece['title']));
3071 if ($replaceWith != $piece['text']) {
3072 $text = $replaceWith;
3073 $found = true;
3074 $noparse = true;
3075 $noargs = true;
3076 }
3077 }
3078
3079 $args = (null == $piece['parts']) ? array() : $piece['parts'];
3080 wfProfileOut(__METHOD__ . '-setup');
3081
3082 # SUBST
3083 wfProfileIn(__METHOD__ . '-modifiers');
3084 if (!$found) {
3085 $mwSubst = &MagicWord::get('subst');
3086 if ($mwSubst->matchStartAndRemove($part1) xor $this->ot['wiki']) {
3087 # One of two possibilities is true:
3088 # 1) Found SUBST but not in the PST phase
3089 # 2) Didn't find SUBST and in the PST phase
3090 # In either case, return without further processing
3091 $text = $piece['text'];
3092 $found = true;
3093 $noparse = true;
3094 $noargs = true;
3095 }
3096 }
3097
3098 # MSG, MSGNW and RAW
3099 if (!$found) {
3100 # Check for MSGNW:
3101 $mwMsgnw = &MagicWord::get('msgnw');
3102 if ($mwMsgnw->matchStartAndRemove($part1)) {
3103 $nowiki = true;
3104 } else {
3105 # Remove obsolete MSG:
3106 $mwMsg = &MagicWord::get('msg');
3107 $mwMsg->matchStartAndRemove($part1);
3108 }
3109
3110 # Check for RAW:
3111 $mwRaw = &MagicWord::get('raw');
3112 if ($mwRaw->matchStartAndRemove($part1)) {
3113 $forceRawInterwiki = true;
3114 }
3115 }
3116 wfProfileOut(__METHOD__ . '-modifiers');
3117
3118 //save path level before recursing into functions & templates.
3119 $lastPathLevel = $this->mTemplatePath;
3120
3121 # Parser functions
3122 if (!$found) {
3123 wfProfileIn(__METHOD__ . '-pfunc');
3124
3125 $colonPos = strpos($part1, ':');
3126 if ($colonPos !== false) {
3127 # Case sensitive functions
3128 $function = substr($part1, 0, $colonPos);
3129 if (isset($this->mFunctionSynonyms[1][$function])) {
3130 $function = $this->mFunctionSynonyms[1][$function];
3131 } else {
3132 # Case insensitive functions
3133 $function = strtolower($function);
3134 if (isset($this->mFunctionSynonyms[0][$function])) {
3135 $function = $this->mFunctionSynonyms[0][$function];
3136 } else {
3137 $function = false;
3138 }
3139 }
3140 if ($function) {
3141 $funcArgs = array_map('trim', $args);
3142 $funcArgs = array_merge(array( &$this, trim(substr($part1, $colonPos + 1)) ), $funcArgs);
3143 $result = call_user_func_array($this->mFunctionHooks[$function], $funcArgs);
3144 $found = true;
3145
3146 // The text is usually already parsed, doesn't need triple-brace tags expanded, etc.
3147 //$noargs = true;
3148 //$noparse = true;
3149
3150 if (is_array($result)) {
3151 if (isset($result[0])) {
3152 $text = $linestart . $result[0];
3153 unset($result[0]);
3154 }
3155
3156 // Extract flags into the local scope
3157 // This allows callers to set flags such as nowiki, noparse, found, etc.
3158 extract($result);
3159 } else {
3160 $text = $linestart . $result;
3161 }
3162 }
3163 }
3164 wfProfileOut(__METHOD__ . '-pfunc');
3165 }
3166
3167 # Template table test
3168
3169 # Did we encounter this template already? If yes, it is in the cache
3170 # and we need to check for loops.
3171 if (!$found && isset($this->mTemplates[$piece['title']])) {
3172 $found = true;
3173
3174 # Infinite loop test
3175 if (isset($this->mTemplatePath[$part1])) {
3176 $noparse = true;
3177 $noargs = true;
3178 $found = true;
3179 $text = $linestart .
3180 "[[$part1]]<!-- WARNING: template loop detected -->";
3181 wfDebug(__METHOD__ . ": template loop broken at '$part1'\n");
3182 } else {
3183 # set $text to cached message.
3184 $text = $linestart . $this->mTemplates[$piece['title']];
3185 #treat title for cached page the same as others
3186 $ns = NS_TEMPLATE;
3187 $subpage = '';
3188 $part1 = $this->maybeDoSubpageLink($part1, $subpage);
3189 if ($subpage !== '') {
3190 $ns = $this->mTitle->getNamespace();
3191 }
3192 $title = Title::newFromText($part1, $ns);
3193 //used by include size checking
3194 $titleText = $title->getPrefixedText();
3195 //used by edit section links
3196 $replaceHeadings = true;
3197 }
3198 }
3199
3200 # Load from database
3201 if (!$found) {
3202 wfProfileIn(__METHOD__ . '-loadtpl');
3203 $ns = NS_TEMPLATE;
3204 # declaring $subpage directly in the function call
3205 # does not work correctly with references and breaks
3206 # {{/subpage}}-style inclusions
3207 $subpage = '';
3208 $part1 = $this->maybeDoSubpageLink($part1, $subpage);
3209 if ($subpage !== '') {
3210 $ns = $this->mTitle->getNamespace();
3211 }
3212 $title = Title::newFromText($part1, $ns);
3213
3214
3215 if (!is_null($title)) {
3216 $titleText = $title->getPrefixedText();
3217 # Check for language variants if the template is not found
3218 if ($wgContLang->hasVariants() && $title->getArticleID() == 0) {
3219 $wgContLang->findVariantLink($part1, $title);
3220 }
3221
3222 if (!$title->isExternal()) {
3223 if ($title->getNamespace() == NS_SPECIAL && $this->mOptions->getAllowSpecialInclusion() && $this->ot['html']) {
3224 $text = SpecialPage::capturePath($title);
3225 if (is_string($text)) {
3226 $found = true;
3227 $noparse = true;
3228 $noargs = true;
3229 $isHTML = true;
3230 $this->disableCache();
3231 }
3232 } elseif ($wgNonincludableNamespaces && in_array($title->getNamespace(), $wgNonincludableNamespaces)) {
3233 $found = false; //access denied
3234 wfDebug("$fname: template inclusion denied for " . $title->getPrefixedDBkey());
3235 } else {
3236 $articleContent = $this->fetchTemplate($title);
3237 if ($articleContent !== false) {
3238 $found = true;
3239 $text = $articleContent;
3240 $replaceHeadings = true;
3241 }
3242 }
3243
3244 # If the title is valid but undisplayable, make a link to it
3245 if (!$found && ($this->ot['html'] || $this->ot['pre'])) {
3246 $text = "[[:$titleText]]";
3247 $found = true;
3248 }
3249 } elseif ($title->isTrans()) {
3250 // Interwiki transclusion
3251 if ($this->ot['html'] && !$forceRawInterwiki) {
3252 $text = $this->interwikiTransclude($title, 'render');
3253 $isHTML = true;
3254 $noparse = true;
3255 } else {
3256 $text = $this->interwikiTransclude($title, 'raw');
3257 $replaceHeadings = true;
3258 }
3259 $found = true;
3260 }
3261
3262 # Template cache array insertion
3263 # Use the original $piece['title'] not the mangled $part1, so that
3264 # modifiers such as RAW: produce separate cache entries
3265 if ($found) {
3266 if ($isHTML) {
3267 // A special page; don't store it in the template cache.
3268 } else {
3269 $this->mTemplates[$piece['title']] = $text;
3270 }
3271 $text = $linestart . $text;
3272 }
3273 }
3274 wfProfileOut(__METHOD__ . '-loadtpl');
3275 }
3276
3277 if ($found && !$this->incrementIncludeSize('pre-expand', strlen($text))) {
3278 # Error, oversize inclusion
3279 $text = $linestart .
3280 "[[$titleText]]<!-- WARNING: template omitted, pre-expand include size too large -->";
3281 $noparse = true;
3282 $noargs = true;
3283 }
3284
3285 # Recursive parsing, escaping and link table handling
3286 # Only for HTML output
3287 if ($nowiki && $found && ($this->ot['html'] || $this->ot['pre'])) {
3288 $text = wfEscapeWikiText($text);
3289 } elseif (!$this->ot['msg'] && $found) {
3290 if ($noargs) {
3291 $assocArgs = array();
3292 } else {
3293 # Clean up argument array
3294 $assocArgs = self::createAssocArgs($args);
3295 # Add a new element to the templace recursion path
3296 $this->mTemplatePath[$part1] = 1;
3297 }
3298
3299 if (!$noparse) {
3300 # If there are any <onlyinclude> tags, only include them
3301 if (in_string('<onlyinclude>', $text) && in_string('</onlyinclude>', $text)) {
3302 $replacer = new OnlyIncludeReplacer;
3303 StringUtils::delimiterReplaceCallback(
3304 '<onlyinclude>',
3305 '</onlyinclude>',
3306 array( &$replacer, 'replace' ),
3307 $text
3308 );
3309 $text = $replacer->output;
3310 }
3311 # Remove <noinclude> sections and <includeonly> tags
3312 $text = StringUtils::delimiterReplace('<noinclude>', '</noinclude>', '', $text);
3313 $text = strtr($text, array( '<includeonly>' => '' , '</includeonly>' => '' ));
3314
3315 if ($this->ot['html'] || $this->ot['pre']) {
3316 # Strip <nowiki>, <pre>, etc.
3317 $text = $this->strip($text, $this->mStripState);
3318 if ($this->ot['html']) {
3319 $text = Sanitizer::removeHTMLtags($text, array( &$this, 'replaceVariables' ), $assocArgs);
3320 } elseif ($this->ot['pre'] && $this->mOptions->getRemoveComments()) {
3321 $text = Sanitizer::removeHTMLcomments($text);
3322 }
3323 }
3324 $text = $this->replaceVariables($text, $assocArgs);
3325
3326 # If the template begins with a table or block-level
3327 # element, it should be treated as beginning a new line.
3328 if (!$piece['lineStart'] && preg_match('/^(?:{\\||:|;|#|\*)/', $text)) /*}*/{
3329 $text = "\n" . $text;
3330 }
3331 } elseif (!$noargs) {
3332 # $noparse and !$noargs
3333 # Just replace the arguments, not any double-brace items
3334 # This is used for rendered interwiki transclusion
3335 $text = $this->replaceVariables($text, $assocArgs, true);
3336 }
3337 }
3338 # Prune lower levels off the recursion check path
3339 $this->mTemplatePath = $lastPathLevel;
3340
3341 if ($found && !$this->incrementIncludeSize('post-expand', strlen($text))) {
3342 # Error, oversize inclusion
3343 $text = $linestart .
3344 "[[$titleText]]<!-- WARNING: template omitted, post-expand include size too large -->";
3345 $noparse = true;
3346 $noargs = true;
3347 }
3348
3349 if (!$found) {
3350 wfProfileOut($fname);
3351 return $piece['text'];
3352 } else {
3353 wfProfileIn(__METHOD__ . '-placeholders');
3354 if ($isHTML) {
3355 # Replace raw HTML by a placeholder
3356 # Add a blank line preceding, to prevent it from mucking up
3357 # immediately preceding headings
3358 $text = "\n\n" . $this->insertStripItem($text, $this->mStripState);
3359 } else {
3360 # replace ==section headers==
3361 # XXX this needs to go away once we have a better parser.
3362 if (!$this->ot['wiki'] && !$this->ot['pre'] && $replaceHeadings) {
3363 if (!is_null($title)) {
3364 $encodedname = base64_encode($title->getPrefixedDBkey());
3365 } else {
3366 $encodedname = base64_encode("");
3367 }
3368 $m = preg_split(
3369 '/(^={1,6}.*?={1,6}\s*?$)/m',
3370 $text,
3371 -1,
3372 PREG_SPLIT_DELIM_CAPTURE
3373 );
3374 $text = '';
3375 $nsec = $headingOffset;
3376 for ($i = 0; $i < count($m); $i += 2) {
3377 $text .= $m[$i];
3378 if (!isset($m[$i + 1]) || $m[$i + 1] == "") {
3379 continue;
3380 }
3381 $hl = $m[$i + 1];
3382 if (strstr($hl, "<!--MWTEMPLATESECTION")) {
3383 $text .= $hl;
3384 continue;
3385 }
3386 $m2 = array();
3387 preg_match('/^(={1,6})(.*?)(={1,6})\s*?$/m', $hl, $m2);
3388 $text .= $m2[1] . $m2[2] . "<!--MWTEMPLATESECTION="
3389 . $encodedname . "&" . base64_encode("$nsec") . "-->" . $m2[3];
3390
3391 $nsec++;
3392 }
3393 }
3394 }
3395 wfProfileOut(__METHOD__ . '-placeholders');
3396 }
3397
3398 # Prune lower levels off the recursion check path
3399 $this->mTemplatePath = $lastPathLevel;
3400
3401 if (!$found) {
3402 wfProfileOut($fname);
3403 return $piece['text'];
3404 } else {
3405 wfProfileOut($fname);
3406 return $text;
$result
const NS_SPECIAL
Definition: Title.php:16
maybeDoSubpageLink($target, &$text)
Handle link to subpage if necessary.
Definition: Parser.php:2004
disableCache()
Set a flag in the output object indicating that the content is dynamic and shouldn't be cached.
Definition: Parser.php:4698
$mTemplatePath
Definition: Parser.php:119
insertStripItem($text, &$state)
Add an item to the strip state Returns the unique tag which must be inserted into the stripped text T...
Definition: Parser.php:720
static createAssocArgs($args)
Clean up argument array - refactored in 1.9 so parserfunctions can use it, too.
Definition: Parser.php:3004
strip($text, $state, $stripcomments=false, $dontstrip=array())
Strips and renders nowiki, pre, math, hiero If $render is set, performs necessary rendering operation...
Definition: Parser.php:570
interwikiTransclude($title, $action)
Transclude an interwiki link.
Definition: Parser.php:3443
variableSubstitution($matches)
Replace magic variables.
Definition: Parser.php:2968
fetchTemplate($title)
Fetch the unparsed text of a template and register a reference to it.
Definition: Parser.php:3411
static removeHTMLtags($text, $processCallback=null, $args=array())
Cleans up HTML, removes dangerous tags and attributes, and removes HTML comments.
Definition: Sanitizer.php:343
static removeHTMLcomments($text)
Remove '', and everything between.
Definition: Sanitizer.php:533
static newFromText($text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:124
$i
Definition: metadata.php:24
get(string $class_name)
has(string $class_name)

◆ cleanSig()

Parser::cleanSig (   $text,
  $parsing = false 
)

Clean up signature text.

1) Strip ~~~, ~~~~ and ~~~~~ out of signatures

See also
cleanSigInSig 2) Substitute all transclusions
Parameters
string$text
$parsingWhether we're cleaning (preferences save) or parsing
Returns
string Signature text

Definition at line 3984 of file Parser.php.

3987 {
3988 global $wgTitle;
3989 $this->startExternalParse($wgTitle, new ParserOptions(), $parsing ? OT_WIKI : OT_MSG);
3990
3991 $substWord = MagicWord::get('subst');
3992 $substRegex = '/\{\{(?!(?:' . $substWord->getBaseRegex() . '))/x' . $substWord->getRegexCase();
3993 $substText = '{{' . $substWord->getSynonym(0);
3994
3995 $text = preg_replace($substRegex, $substText, $text);
3996 $text = $this->cleanSigInSig($text);
3997 $text = $this->replaceVariables($text);
3998
3999 $this->clearState();
const OT_WIKI
Definition: Parser.php:19
const OT_MSG
Definition: Parser.php:20
startExternalParse(&$title, $options, $outputType, $clearState=true)
Set up some variables which are usually set up in parse() so that an external function can call some ...
Definition: Parser.php:4017
cleanSigInSig($text)
Strip ~~~, ~~~~ and ~~~~~ out of signatures.
Definition: Parser.php:4006
clearState()
Clear Parser state.
Definition: Parser.php:211

◆ cleanSigInSig()

Parser::cleanSigInSig (   $text)

Strip ~~~, ~~~~ and ~~~~~ out of signatures.

Parameters
string$text
Returns
string Signature text with /~{3,5}/ removed

Definition at line 4006 of file Parser.php.

4006 {3,5}/ removed
4007 */
4008 public function cleanSigInSig($text)
4009 {
4010 $text = preg_replace('/~{3,5}/', '', $text);

◆ clearState()

Parser::clearState ( )

Clear Parser state.

Prefix for temporary replacement strings for the multipass parser. \x07 should never appear in input as it's disallowed in XML. Using it at the front also gives us a little extra robustness since it shouldn't match when butted up against identifier-like string constructs.

Definition at line 211 of file Parser.php.

214 {
215 wfProfileIn(__METHOD__);
216 if ($this->mFirstCall) {
217 $this->firstCallInit();
218 }
219 $this->mOutput = new ParserOutput;
220 $this->mAutonumber = 0;
221 $this->mLastSection = '';
222 $this->mDTopen = false;
223 $this->mIncludeCount = array();
224 $this->mStripState = new StripState;
225 $this->mArgStack = array();
226 $this->mInPre = false;
227 $this->mInterwikiLinkHolders = array(
228 'texts' => array(),
229 'titles' => array()
230 );
231 $this->mLinkHolders = array(
232 'namespaces' => array(),
233 'dbkeys' => array(),
234 'queries' => array(),
235 'texts' => array(),
236 'titles' => array()
237 );
238 $this->mRevisionTimestamp = $this->mRevisionId = null;
239
247 $this->mUniqPrefix = "\x07UNIQ" . Parser::getRandomString();
248
249 # Clear these on every parse, bug 4549
250 $this->mTemplates = array();
251 $this->mTemplatePath = array();
252
253 $this->mShowToc = true;
254 $this->mForceTocPosition = false;
255 $this->mIncludeSizes = array(
256 'pre-expand' => 0,
257 'post-expand' => 0,
258 'arg' => 0
259 );
260 $this->mDefaultSort = false;
261
262 wfRunHooks('ParserClearState', array( &$this ));
getRandomString()
Get a random string.
Definition: Parser.php:452
firstCallInit()
Do various kinds of initialisation on the first call of the parser.
Definition: Parser.php:156

◆ closeList()

Parser::closeList (   $char)

Definition at line 2145 of file Parser.php.

2148 {
2149 if ('*' == $char) {
2150 $text = '</li></ul>';
2151 } elseif ('#' == $char) {
2152 $text = '</li></ol>';
2153 } elseif (':' == $char) {
2154 if ($this->mDTopen) {
2155 $this->mDTopen = false;
2156 $text = '</dt></dl>';
2157 } else {
2158 $text = '</dd></dl>';
2159 }
2160 } else {
2161 return '<!-- ERR 3 -->';
2162 }

◆ closeParagraph()

Parser::closeParagraph ( )

#+ Used by doBlockLevels()

Definition at line 2074 of file Parser.php.

2077 {
2078 $result = '';
2079 if ('' != $this->mLastSection) {
2080 $result = '</' . $this->mLastSection . ">\n";
2081 }
2082 $this->mInPre = false;
2083 $this->mLastSection = '';

◆ createAssocArgs()

static Parser::createAssocArgs (   $args)
static

Clean up argument array - refactored in 1.9 so parserfunctions can use it, too.

Definition at line 3004 of file Parser.php.

3007 {
3008 $assocArgs = array();
3009 $index = 1;
3010 foreach ($args as $arg) {
3011 $eqpos = strpos($arg, '=');
3012 if ($eqpos === false) {
3013 $assocArgs[$index++] = $arg;
3014 } else {
3015 $name = trim(substr($arg, 0, $eqpos));
3016 $value = trim(substr($arg, $eqpos + 1));
3017 if ($value === false) {
3018 $value = '';
3019 }
3020 if ($name !== false) {
3021 $assocArgs[$name] = $value;
3022 }
3023 }
3024 }
3025
if($format !==null) $name
Definition: metadata.php:230
$index
Definition: metadata.php:128

References $index, and $name.

◆ disableCache()

Parser::disableCache ( )

Set a flag in the output object indicating that the content is dynamic and shouldn't be cached.

Definition at line 4698 of file Parser.php.

4701 {
4702 wfDebug("Parser output marked as uncacheable.\n");

◆ doAllQuotes()

Parser::doAllQuotes (   $text)

Replace single quotes with HTML markup.

Returns
string the altered text

Definition at line 1176 of file Parser.php.

1179 {
1180 $fname = 'Parser::doAllQuotes';
1181 wfProfileIn($fname);
1182 $outtext = '';
1183 $lines = explode("\n", $text);
1184 foreach ($lines as $line) {
1185 $outtext .= $this->doQuotes($line) . "\n";
1186 }
1187 $outtext = substr($outtext, 0, -1);
1188 wfProfileOut($fname);
doQuotes($text)
Helper function for doAllQuotes()
Definition: Parser.php:1194

◆ doBlockLevels()

Parser::doBlockLevels (   $text,
  $linestart 
)

#-

Make lists from lines starting with ':', '*', '#', etc.

Returns
string the lists rendered as HTML

Definition at line 2171 of file Parser.php.

2174 {
2175 $fname = 'Parser::doBlockLevels';
2176 wfProfileIn($fname);
2177
2178 # Parsing through the text line by line. The main thing
2179 # happening here is handling of block-level elements p, pre,
2180 # and making lists from lines starting with * # : etc.
2181 #
2182 $textLines = explode("\n", $text);
2183
2184 $lastPrefix = $output = '';
2185 $this->mDTopen = $inBlockElem = false;
2186 $prefixLength = 0;
2187 $paragraphStack = false;
2188
2189 if (!$linestart) {
2190 $output .= array_shift($textLines);
2191 }
2192 foreach ($textLines as $oLine) {
2193 $lastPrefixLength = strlen($lastPrefix);
2194 $preCloseMatch = preg_match('/<\\/pre/i', $oLine);
2195 $preOpenMatch = preg_match('/<pre/i', $oLine);
2196 if (!$this->mInPre) {
2197 # Multiple prefixes may abut each other for nested lists.
2198 $prefixLength = strspn($oLine, '*#:;');
2199 $pref = substr($oLine, 0, $prefixLength);
2200
2201 # eh?
2202 $pref2 = str_replace(';', ':', $pref);
2203 $t = substr($oLine, $prefixLength);
2204 $this->mInPre = !empty($preOpenMatch);
2205 } else {
2206 # Don't interpret any other prefixes in preformatted text
2207 $prefixLength = 0;
2208 $pref = $pref2 = '';
2209 $t = $oLine;
2210 }
2211
2212 # List generation
2213 if ($prefixLength && 0 == strcmp($lastPrefix, $pref2)) {
2214 # Same as the last item, so no need to deal with nesting or opening stuff
2215 $output .= $this->nextItem(substr($pref, -1));
2216 $paragraphStack = false;
2217
2218 if (substr($pref, -1) == ';') {
2219 # The one nasty exception: definition lists work like this:
2220 # ; title : definition text
2221 # So we check for : in the remainder text to split up the
2222 # title and definition, without b0rking links.
2223 $term = $t2 = '';
2224 if ($this->findColonNoLinks($t, $term, $t2) !== false) {
2225 $t = $t2;
2226 $output .= $term . $this->nextItem(':');
2227 }
2228 }
2229 } elseif ($prefixLength || $lastPrefixLength) {
2230 # Either open or close a level...
2231 $commonPrefixLength = $this->getCommon($pref, $lastPrefix);
2232 $paragraphStack = false;
2233
2234 while ($commonPrefixLength < $lastPrefixLength) {
2235 $output .= $this->closeList($lastPrefix[$lastPrefixLength - 1]);
2236 --$lastPrefixLength;
2237 }
2238 if ($prefixLength <= $commonPrefixLength && $commonPrefixLength > 0) {
2239 $output .= $this->nextItem($pref[$commonPrefixLength - 1]);
2240 }
2241 while ($prefixLength > $commonPrefixLength) {
2242 $char = substr($pref, $commonPrefixLength, 1);
2243 $output .= $this->openList($char);
2244
2245 if (';' == $char) {
2246 # FIXME: This is dupe of code above
2247 if ($this->findColonNoLinks($t, $term, $t2) !== false) {
2248 $t = $t2;
2249 $output .= $term . $this->nextItem(':');
2250 }
2251 }
2252 ++$commonPrefixLength;
2253 }
2254 $lastPrefix = $pref2;
2255 }
2256 if (0 == $prefixLength) {
2257 wfProfileIn("$fname-paragraph");
2258 # No prefix (not in list)--go to paragraph mode
2259 // XXX: use a stack for nestable elements like span, table and div
2260 $openmatch = preg_match('/(?:<table|<blockquote|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|<p|<ul|<ol|<li|<\\/tr|<\\/td|<\\/th)/iS', $t);
2261 $closematch = preg_match(
2262 '/(?:<\\/table|<\\/blockquote|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|' .
2263 '<td|<th|<\\/?div|<hr|<\\/pre|<\\/p|' . $this->mUniqPrefix . '-pre|<\\/li|<\\/ul|<\\/ol|<\\/?center)/iS',
2264 $t
2265 );
2266 if ($openmatch or $closematch) {
2267 $paragraphStack = false;
2268 # TODO bug 5718: paragraph closed
2269 $output .= $this->closeParagraph();
2270 if ($preOpenMatch and !$preCloseMatch) {
2271 $this->mInPre = true;
2272 }
2273 if ($closematch) {
2274 $inBlockElem = false;
2275 } else {
2276 $inBlockElem = true;
2277 }
2278 } elseif (!$inBlockElem && !$this->mInPre) {
2279 if (' ' == $t[0] and ($this->mLastSection == 'pre' or trim($t) != '')) {
2280 // pre
2281 if ($this->mLastSection != 'pre') {
2282 $paragraphStack = false;
2283 $output .= $this->closeParagraph() . '<pre>';
2284 $this->mLastSection = 'pre';
2285 }
2286 $t = substr($t, 1);
2287 } else {
2288 // paragraph
2289 if ('' == trim($t)) {
2290 if ($paragraphStack) {
2291 $output .= $paragraphStack . '<br />';
2292 $paragraphStack = false;
2293 $this->mLastSection = 'p';
2294 } else {
2295 if ($this->mLastSection != 'p') {
2296 $output .= $this->closeParagraph();
2297 $this->mLastSection = '';
2298 $paragraphStack = '<p>';
2299 } else {
2300 $paragraphStack = '</p><p>';
2301 }
2302 }
2303 } else {
2304 if ($paragraphStack) {
2305 $output .= $paragraphStack;
2306 $paragraphStack = false;
2307 $this->mLastSection = 'p';
2308 } elseif ($this->mLastSection != 'p') {
2309 $output .= $this->closeParagraph() . '<p>';
2310 $this->mLastSection = 'p';
2311 }
2312 }
2313 }
2314 }
2315 wfProfileOut("$fname-paragraph");
2316 }
2317 // somewhere above we forget to get out of pre block (bug 785)
2318 if ($preCloseMatch && $this->mInPre) {
2319 $this->mInPre = false;
2320 }
2321 if ($paragraphStack === false) {
2322 $output .= $t . "\n";
2323 }
2324 }
2325 while ($prefixLength) {
2326 $output .= $this->closeList($pref2[$prefixLength - 1]);
2327 --$prefixLength;
2328 }
2329 if ('' != $this->mLastSection) {
2330 $output .= '</' . $this->mLastSection . '>';
2331 $this->mLastSection = '';
2332 }
2333
2334 wfProfileOut($fname);
getCommon($st1, $st2)
Definition: Parser.php:2087
findColonNoLinks($str, &$before, &$after)
Split up a string on ':', ignoring any occurences inside tags to prevent illegal overlapping.
Definition: Parser.php:2344
closeList($char)
Definition: Parser.php:2145
openList($char)
Definition: Parser.php:2105
nextItem($char)
Definition: Parser.php:2125
closeParagraph()
#+ Used by doBlockLevels()
Definition: Parser.php:2074

◆ doHeadings()

Parser::doHeadings (   $text)

Parse headers and return html.

Definition at line 1155 of file Parser.php.

1158 {
1159 $fname = 'Parser::doHeadings';
1160 wfProfileIn($fname);
1161 for ($i = 6; $i >= 1; --$i) {
1162 $h = str_repeat('=', $i);
1163 $text = preg_replace(
1164 "/^{$h}(.+){$h}\\s*$/m",
1165 "<h{$i}>\\1</h{$i}>\\2",
1166 $text
1167 );
1168 }
1169 wfProfileOut($fname);

◆ doMagicLinks()

& Parser::doMagicLinks ( $text)

Replace special strings like "ISBN xxx" and "RFC xxx" with magic external links.

Definition at line 1091 of file Parser.php.

1094 {
1095 wfProfileIn(__METHOD__);
1096 $text = preg_replace_callback(
1097 '!(?: # Start cases
1098 <a.*?</a> | # Skip link text
1099 <.*?> | # Skip stuff inside HTML elements
1100 (?:RFC|PMID)\s+([0-9]+) | # RFC or PMID, capture number as m[1]
1101 ISBN\s+(\b # ISBN, capture number as m[2]
1102 (?: 97[89] [\ \-]? )? # optional 13-digit ISBN prefix
1103 (?: [0-9] [\ \-]? ){9} # 9 digits with opt. delimiters
1104 [0-9Xx] # check digit
1105 \b)
1106 )!x',
1107 array( &$this, 'magicLinkCallback' ),
1108 $text
1109 );
1110 wfProfileOut(__METHOD__);

◆ doQuotes()

Parser::doQuotes (   $text)

Helper function for doAllQuotes()

Definition at line 1194 of file Parser.php.

1197 {
1198 $arr = preg_split("/(''+)/", $text, -1, PREG_SPLIT_DELIM_CAPTURE);
1199 if (count($arr) == 1) {
1200 return $text;
1201 } else {
1202 # First, do some preliminary work. This may shift some apostrophes from
1203 # being mark-up to being text. It also counts the number of occurrences
1204 # of bold and italics mark-ups.
1205 $i = 0;
1206 $numbold = 0;
1207 $numitalics = 0;
1208 foreach ($arr as $r) {
1209 if (($i % 2) == 1) {
1210 # If there are ever four apostrophes, assume the first is supposed to
1211 # be text, and the remaining three constitute mark-up for bold text.
1212 if (strlen($arr[$i]) == 4) {
1213 $arr[$i - 1] .= "'";
1214 $arr[$i] = "'''";
1215 }
1216 # If there are more than 5 apostrophes in a row, assume they're all
1217 # text except for the last 5.
1218 elseif (strlen($arr[$i]) > 5) {
1219 $arr[$i - 1] .= str_repeat("'", strlen($arr[$i]) - 5);
1220 $arr[$i] = "'''''";
1221 }
1222 # Count the number of occurrences of bold and italics mark-ups.
1223 # We are not counting sequences of five apostrophes.
1224 if (strlen($arr[$i]) == 2) {
1225 $numitalics++;
1226 } elseif (strlen($arr[$i]) == 3) {
1227 $numbold++;
1228 } elseif (strlen($arr[$i]) == 5) {
1229 $numitalics++;
1230 $numbold++;
1231 }
1232 }
1233 $i++;
1234 }
1235
1236 # If there is an odd number of both bold and italics, it is likely
1237 # that one of the bold ones was meant to be an apostrophe followed
1238 # by italics. Which one we cannot know for certain, but it is more
1239 # likely to be one that has a single-letter word before it.
1240 if (($numbold % 2 == 1) && ($numitalics % 2 == 1)) {
1241 $i = 0;
1242 $firstsingleletterword = -1;
1243 $firstmultiletterword = -1;
1244 $firstspace = -1;
1245 foreach ($arr as $r) {
1246 if (($i % 2 == 1) and (strlen($r) == 3)) {
1247 $x1 = substr($arr[$i - 1], -1);
1248 $x2 = substr($arr[$i - 1], -2, 1);
1249 if ($x1 == ' ') {
1250 if ($firstspace == -1) {
1251 $firstspace = $i;
1252 }
1253 } elseif ($x2 == ' ') {
1254 if ($firstsingleletterword == -1) {
1255 $firstsingleletterword = $i;
1256 }
1257 } else {
1258 if ($firstmultiletterword == -1) {
1259 $firstmultiletterword = $i;
1260 }
1261 }
1262 }
1263 $i++;
1264 }
1265
1266 # If there is a single-letter word, use it!
1267 if ($firstsingleletterword > -1) {
1268 $arr [ $firstsingleletterword ] = "''";
1269 $arr [ $firstsingleletterword - 1 ] .= "'";
1270 }
1271 # If not, but there's a multi-letter word, use that one.
1272 elseif ($firstmultiletterword > -1) {
1273 $arr [ $firstmultiletterword ] = "''";
1274 $arr [ $firstmultiletterword - 1 ] .= "'";
1275 }
1276 # ... otherwise use the first one that has neither.
1277 # (notice that it is possible for all three to be -1 if, for example,
1278 # there is only one pentuple-apostrophe in the line)
1279 elseif ($firstspace > -1) {
1280 $arr [ $firstspace ] = "''";
1281 $arr [ $firstspace - 1 ] .= "'";
1282 }
1283 }
1284
1285 # Now let's actually convert our apostrophic mush to HTML!
1286 $output = '';
1287 $buffer = '';
1288 $state = '';
1289 $i = 0;
1290 foreach ($arr as $r) {
1291 if (($i % 2) == 0) {
1292 if ($state == 'both') {
1293 $buffer .= $r;
1294 } else {
1295 $output .= $r;
1296 }
1297 } else {
1298 if (strlen($r) == 2) {
1299 if ($state == 'i') {
1300 $output .= '</i>';
1301 $state = '';
1302 } elseif ($state == 'bi') {
1303 $output .= '</i>';
1304 $state = 'b';
1305 } elseif ($state == 'ib') {
1306 $output .= '</b></i><b>';
1307 $state = 'b';
1308 } elseif ($state == 'both') {
1309 $output .= '<b><i>' . $buffer . '</i>';
1310 $state = 'b';
1311 } else { # $state can be 'b' or ''
1312 $output .= '<i>';
1313 $state .= 'i';
1314 }
1315 } elseif (strlen($r) == 3) {
1316 if ($state == 'b') {
1317 $output .= '</b>';
1318 $state = '';
1319 } elseif ($state == 'bi') {
1320 $output .= '</i></b><i>';
1321 $state = 'i';
1322 } elseif ($state == 'ib') {
1323 $output .= '</b>';
1324 $state = 'i';
1325 } elseif ($state == 'both') {
1326 $output .= '<i><b>' . $buffer . '</b>';
1327 $state = 'i';
1328 } else { # $state can be 'i' or ''
1329 $output .= '<b>';
1330 $state .= 'b';
1331 }
1332 } elseif (strlen($r) == 5) {
1333 if ($state == 'b') {
1334 $output .= '</b><i>';
1335 $state = 'i';
1336 } elseif ($state == 'i') {
1337 $output .= '</i><b>';
1338 $state = 'b';
1339 } elseif ($state == 'bi') {
1340 $output .= '</i></b>';
1341 $state = '';
1342 } elseif ($state == 'ib') {
1343 $output .= '</b></i>';
1344 $state = '';
1345 } elseif ($state == 'both') {
1346 $output .= '<i><b>' . $buffer . '</b></i>';
1347 $state = '';
1348 } else { # ($state == '')
1349 $buffer = '';
1350 $state = 'both';
1351 }
1352 }
1353 }
1354 $i++;
1355 }
1356 # Now close all remaining tags. Notice that the order is important.
1357 if ($state == 'b' || $state == 'ib') {
1358 $output .= '</b>';
1359 }
1360 if ($state == 'i' || $state == 'bi' || $state == 'ib') {
1361 $output .= '</i>';
1362 }
1363 if ($state == 'bi') {
1364 $output .= '</b>';
1365 }
1366 # There might be lonely ''''', so make sure we have a buffer
1367 if ($state == 'both' && $buffer) {
1368 $output .= '<b><i>' . $buffer . '</i></b>';
1369 }
1370 return $output;

◆ doTableStuff()

Parser::doTableStuff (   $text)

parse the wiki syntax used to render tables

Definition at line 843 of file Parser.php.

846 {
847 $fname = 'Parser::doTableStuff';
848 wfProfileIn($fname);
849
850 $lines = explode("\n", $text);
851 $td_history = array(); // Is currently a td tag open?
852 $last_tag_history = array(); // Save history of last lag activated (td, th or caption)
853 $tr_history = array(); // Is currently a tr tag open?
854 $tr_attributes = array(); // history of tr attributes
855 $has_opened_tr = array(); // Did this table open a <tr> element?
856 $indent_level = 0; // indent level of the table
857 foreach ($lines as $key => $line) {
858 $line = trim($line);
859
860 if ($line == '') { // empty line, go to next line
861 continue;
862 }
863 $first_character = $line[0];
864 $matches = array();
865
866 if (preg_match('/^(:*)\{\|(.*)$/', $line, $matches)) {
867 // First check if we are starting a new table
868 $indent_level = strlen($matches[1]);
869
870 $attributes = $this->mStripState->unstripBoth($matches[2]);
872
873 $lines[$key] = str_repeat('<dl><dd>', $indent_level) . "<table{$attributes}>";
874 array_push($td_history, false);
875 array_push($last_tag_history, '');
876 array_push($tr_history, false);
877 array_push($tr_attributes, '');
878 array_push($has_opened_tr, false);
879 } elseif (count($td_history) == 0) {
880 // Don't do any of the following
881 continue;
882 } elseif (substr($line, 0, 2) == '|}') {
883 // We are ending a table
884 $line = '</table>' . substr($line, 2);
885 $last_tag = array_pop($last_tag_history);
886
887 if (!array_pop($has_opened_tr)) {
888 $line = "<tr><td></td></tr>{$line}";
889 }
890
891 if (array_pop($tr_history)) {
892 $line = "</tr>{$line}";
893 }
894
895 if (array_pop($td_history)) {
896 $line = "</{$last_tag}>{$line}";
897 }
898 array_pop($tr_attributes);
899 $lines[$key] = $line . str_repeat('</dd></dl>', $indent_level);
900 } elseif (substr($line, 0, 2) == '|-') {
901 // Now we have a table row
902 $line = preg_replace('#^\|-+#', '', $line);
903
904 // Whats after the tag is now only attributes
905 $attributes = $this->mStripState->unstripBoth($line);
907 array_pop($tr_attributes);
908 array_push($tr_attributes, $attributes);
909
910 $line = '';
911 $last_tag = array_pop($last_tag_history);
912 array_pop($has_opened_tr);
913 array_push($has_opened_tr, true);
914
915 if (array_pop($tr_history)) {
916 $line = '</tr>';
917 }
918
919 if (array_pop($td_history)) {
920 $line = "</{$last_tag}>{$line}";
921 }
922
923 $lines[$key] = $line;
924 array_push($tr_history, false);
925 array_push($td_history, false);
926 array_push($last_tag_history, '');
927 } elseif ($first_character == '|' || $first_character == '!' || substr($line, 0, 2) == '|+') {
928 // This might be cell elements, td, th or captions
929 if (substr($line, 0, 2) == '|+') {
930 $first_character = '+';
931 $line = substr($line, 1);
932 }
933
934 $line = substr($line, 1);
935
936 if ($first_character == '!') {
937 $line = str_replace('!!', '||', $line);
938 }
939
940 // Split up multiple cells on the same line.
941 // FIXME : This can result in improper nesting of tags processed
942 // by earlier parser steps, but should avoid splitting up eg
943 // attribute values containing literal "||".
944 $cells = StringUtils::explodeMarkup('||', $line);
945
946 $lines[$key] = '';
947
948 // Loop through each table cell
949 foreach ($cells as $cell) {
950 $previous = '';
951 if ($first_character != '+') {
952 $tr_after = array_pop($tr_attributes);
953 if (!array_pop($tr_history)) {
954 $previous = "<tr{$tr_after}>\n";
955 }
956 array_push($tr_history, true);
957 array_push($tr_attributes, '');
958 array_pop($has_opened_tr);
959 array_push($has_opened_tr, true);
960 }
961
962 $last_tag = array_pop($last_tag_history);
963
964 if (array_pop($td_history)) {
965 $previous = "</{$last_tag}>{$previous}";
966 }
967
968 if ($first_character == '|') {
969 $last_tag = 'td';
970 } elseif ($first_character == '!') {
971 $last_tag = 'th';
972 } elseif ($first_character == '+') {
973 $last_tag = 'caption';
974 } else {
975 $last_tag = '';
976 }
977
978 array_push($last_tag_history, $last_tag);
979
980 // A cell could contain both parameters and data
981 $cell_data = explode('|', $cell, 2);
982
983 // Bug 553: Note that a '|' inside an invalid link should not
984 // be mistaken as delimiting cell parameters
985 if (strpos($cell_data[0], '[[') !== false) {
986 $cell = "{$previous}<{$last_tag}>{$cell}";
987 } elseif (count($cell_data) == 1) {
988 $cell = "{$previous}<{$last_tag}>{$cell_data[0]}";
989 } else {
990 $attributes = $this->mStripState->unstripBoth($cell_data[0]);
992 $cell = "{$previous}<{$last_tag}{$attributes}>{$cell_data[1]}";
993 }
994
995 $lines[$key] .= $cell;
996 array_push($td_history, true);
997 }
998 }
999 }
1000
1001 // Closing open td, tr && table
1002 while (count($td_history) > 0) {
1003 if (array_pop($td_history)) {
1004 $lines[] = '</td>' ;
1005 }
1006 if (array_pop($tr_history)) {
1007 $lines[] = '</tr>' ;
1008 }
1009 if (!array_pop($has_opened_tr)) {
1010 $lines[] = "<tr><td></td></tr>" ;
1011 }
1012
1013 $lines[] = '</table>' ;
1014 }
1015
1016 $output = implode("\n", $lines) ;
1017
1018 // special case: don't return empty table
1019 if ($output == "<table>\n<tr><td></td></tr>\n</table>") {
1020 $output = '';
1021 }
1022
1023 wfProfileOut($fname);
1024
static fixTagAttributes($text, $element)
Take a tag soup fragment listing an HTML element's attributes and normalize it to well-formed XML,...
Definition: Sanitizer.php:669
$attributes
Definition: metadata.php:231

◆ externalTidy()

Parser::externalTidy (   $text)
static

Spawn an external HTML tidy process and get corrected markup back from it.

Definition at line 765 of file Parser.php.

768 {
769 global $wgTidyConf, $wgTidyBin, $wgTidyOpts;
770 $fname = 'Parser::externalTidy';
771 wfProfileIn($fname);
772
773 $cleansource = '';
774 $opts = ' -utf8';
775
776 $descriptorspec = array(
777 0 => array('pipe', 'r'),
778 1 => array('pipe', 'w'),
779 2 => array('file', '/dev/null', 'a') // FIXME: this line in UNIX-specific, it generates a warning on Windows, because /dev/null is not a valid Windows file.
780 );
781 $pipes = array();
782 $process = proc_open("$wgTidyBin -config $wgTidyConf $wgTidyOpts$opts", $descriptorspec, $pipes);
783 if (is_resource($process)) {
784 // Theoretically, this style of communication could cause a deadlock
785 // here. If the stdout buffer fills up, then writes to stdin could
786 // block. This doesn't appear to happen with tidy, because tidy only
787 // writes to stdout after it's finished reading from stdin. Search
788 // for tidyParseStdin and tidySaveStdout in console/tidy.c
789 fwrite($pipes[0], $text);
790 fclose($pipes[0]);
791 while (!feof($pipes[1])) {
792 $cleansource .= fgets($pipes[1], 1024);
793 }
794 fclose($pipes[1]);
795 proc_close($process);
796 }
797
798 wfProfileOut($fname);
799
800 if ($cleansource == '' && $text != '') {
801 // Some kind of error happened, so we couldn't get the corrected text.
802 // Just give up; we'll use the source text and append a warning.
803 return null;
804 } else {
805 return $cleansource;

◆ extractSections()

Parser::extractSections (   $text,
  $section,
  $mode,
  $newtext = '' 
)
private

#-

Break wikitext input into sections, and either pull or replace some particular section's text.

External callers should use the getSection and replaceSection methods.

Parameters
$textPage wikitext
$sectionNumbered section. 0 pulls the text before the first heading; other numbers will pull the given section along with its lower-level subsections.
$modeOne of "get" or "replace"
$newtextReplacement text for section data.
Returns
string for "get", the extracted section text. for "replace", the whole page with the section replaced.

Definition at line 4763 of file Parser.php.

4766 {
4767 # strip NOWIKI etc. to avoid confusion (true-parameter causes HTML
4768 # comments to be stripped as well)
4769 $stripState = new StripState;
4770
4771 $oldOutputType = $this->mOutputType;
4772 $oldOptions = $this->mOptions;
4773 $this->mOptions = new ParserOptions();
4774 $this->setOutputType(OT_WIKI);
4775
4776 $striptext = $this->strip($text, $stripState, true);
4777
4778 $this->setOutputType($oldOutputType);
4779 $this->mOptions = $oldOptions;
4780
4781 # now that we can be sure that no pseudo-sections are in the source,
4782 # split it up by section
4783 $uniq = preg_quote($this->uniqPrefix(), '/');
4784 $comment = "(?:$uniq-!--.*?QINU)";
4785 $secs = preg_split(
4786 "/
4787 (
4788 ^
4789 (?:$comment|<\/?noinclude>)* # Initial comments will be stripped
4790 (=+) # Should this be limited to 6?
4791 .+? # Section title...
4792 \\2 # Ending = count must match start
4793 (?:$comment|<\/?noinclude>|[ \\t]+)* # Trailing whitespace ok
4794 $
4795 |
4796 <h([1-6])\b.*?>
4797 .*?
4798 <\/h\\3\s*>
4799 )
4800 /mix",
4801 $striptext,
4802 -1,
4803 PREG_SPLIT_DELIM_CAPTURE
4804 );
4805
4806 if ($mode == "get") {
4807 if ($section == 0) {
4808 // "Section 0" returns the content before any other section.
4809 $rv = $secs[0];
4810 } else {
4811 //track missing section, will replace if found.
4812 $rv = $newtext;
4813 }
4814 } elseif ($mode == "replace") {
4815 if ($section == 0) {
4816 $rv = $newtext . "\n\n";
4817 $remainder = true;
4818 } else {
4819 $rv = $secs[0];
4820 $remainder = false;
4821 }
4822 }
4823 $count = 0;
4824 $sectionLevel = 0;
4825 for ($index = 1; $index < count($secs);) {
4826 $headerLine = $secs[$index++];
4827 if ($secs[$index]) {
4828 // A wiki header
4829 $headerLevel = strlen($secs[$index++]);
4830 } else {
4831 // An HTML header
4832 $index++;
4833 $headerLevel = intval($secs[$index++]);
4834 }
4835 $content = $secs[$index++];
4836
4837 $count++;
4838 if ($mode == "get") {
4839 if ($count == $section) {
4840 $rv = $headerLine . $content;
4841 $sectionLevel = $headerLevel;
4842 } elseif ($count > $section) {
4843 if ($sectionLevel && $headerLevel > $sectionLevel) {
4844 $rv .= $headerLine . $content;
4845 } else {
4846 // Broke out to a higher-level section
4847 break;
4848 }
4849 }
4850 } elseif ($mode == "replace") {
4851 if ($count < $section) {
4852 $rv .= $headerLine . $content;
4853 } elseif ($count == $section) {
4854 $rv .= $newtext . "\n\n";
4855 $sectionLevel = $headerLevel;
4856 } elseif ($count > $section) {
4857 if ($headerLevel <= $sectionLevel) {
4858 // Passed the section's sub-parts.
4859 $remainder = true;
4860 }
4861 if ($remainder) {
4862 $rv .= $headerLine . $content;
4863 }
4864 }
4865 }
4866 }
4867 if (is_string($rv)) {
4868 # reinsert stripped tags
4869 $rv = trim($stripState->unstripBoth($rv));
4870 }
4871
$section
Definition: Utf8Test.php:83
$comment
Definition: buildRTE.php:83
uniqPrefix()
Accessor for mUniqPrefix.
Definition: Parser.php:281
$mOutputType
Definition: Parser.php:128
$mOptions
Definition: Parser.php:124
setOutputType($ot)
Definition: Parser.php:264

◆ extractTagsAndParams()

Parser::extractTagsAndParams (   $elements,
  $text,
$matches,
  $uniq_prefix = '' 
)
static

Replaces all occurrences of HTML-style comments and the given tags in the text with a random marker and returns teh next text.

The output parameter $matches will be an associative array filled with data in the form: 'UNIQ-xxxxx' => array( 'element', 'tag content', array( 'param' => 'x' ), '<element param="x">tag content</element>' ) )

Parameters
$elementslist of element names. Comments are always extracted.
$textSource text string.
$uniq_prefix

Definition at line 490 of file Parser.php.

493 {
494 static $n = 1;
495 $stripped = '';
496 $matches = array();
497
498 $taglist = implode('|', $elements);
499 $start = "/<($taglist)(\\s+[^>]*?|\\s*?)(\/?>)|<(!--)/i";
500
501 while ('' != $text) {
502 $p = preg_split($start, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
503 $stripped .= $p[0];
504 if (count($p) < 5) {
505 break;
506 }
507 if (count($p) > 5) {
508 // comment
509 $element = $p[4];
510 $attributes = '';
511 $close = '';
512 $inside = $p[5];
513 } else {
514 // tag
515 $element = $p[1];
516 $attributes = $p[2];
517 $close = $p[3];
518 $inside = $p[4];
519 }
520
521 $marker = "$uniq_prefix-$element-" . sprintf('%08X', $n++) . '-QINU';
522 $stripped .= $marker;
523
524 if ($close === '/>') {
525 // Empty element tag, <tag />
526 $content = null;
527 $text = $inside;
528 $tail = null;
529 } else {
530 if ($element == '!--') {
531 $end = '/(-->)/';
532 } else {
533 $end = "/(<\\/$element\\s*>)/i";
534 }
535 $q = preg_split($end, $inside, 2, PREG_SPLIT_DELIM_CAPTURE);
536 $content = $q[0];
537 if (count($q) < 3) {
538 # No end tag -- let it run out to the end of the text.
539 $tail = '';
540 $text = '';
541 } else {
542 $tail = $q[1];
543 $text = $q[2];
544 }
545 }
546
547 $matches[$marker] = array( $element,
548 $content,
550 "<$element$attributes$close$content$tail" );
551 }
$n
Definition: RandomTest.php:85
static decodeTagAttributes($text)
Return an associative array of attribute names and values from a partial tag string.
Definition: Sanitizer.php:812

◆ fetchScaryTemplateMaybeFromCache()

Parser::fetchScaryTemplateMaybeFromCache (   $url)

Definition at line 3459 of file Parser.php.

3462 {
3463 global $wgTranscludeCacheExpiry;
3464 $dbr = wfGetDB(DB_SLAVE);
3465 $obj = $dbr->selectRow(
3466 'transcache',
3467 array('tc_time', 'tc_contents'),
3468 array('tc_url' => $url)
3469 );
3470 if ($obj) {
3471 $time = $obj->tc_time;
3472 $text = $obj->tc_contents;
3473 if ($time && time() < $time + $wgTranscludeCacheExpiry) {
3474 return $text;
3475 }
3476 }
3477
3478 $text = Http::get($url);
3479 if (!$text) {
3480 return wfMsg('scarytranscludefailed', $url);
3481 }
3482
3483 $dbw = wfGetDB(DB_MASTER);
3484 $dbw->replace('transcache', array('tc_url'), array(
3485 'tc_url' => $url,
3486 'tc_time' => time(),
3487 'tc_contents' => $text));
wfMsg($x)
Definition: RandomTest.php:63
$url

◆ fetchTemplate()

Parser::fetchTemplate (   $title)

Fetch the unparsed text of a template and register a reference to it.

Definition at line 3411 of file Parser.php.

3414 {
3415 $text = false;
3416 // Loop to fetch the article, with up to 1 redirect
3417 for ($i = 0; $i < 2 && is_object($title); $i++) {
3418 $rev = Revision::newFromTitle($title);
3419 $this->mOutput->addTemplate($title, $title->getArticleID());
3420 if ($rev) {
3421 $text = $rev->getText();
3422 } elseif ($title->getNamespace() == NS_MEDIAWIKI) {
3423 global $wgLang;
3424 $message = $wgLang->lcfirst($title->getText());
3425 $text = wfMsgForContentNoTrans($message);
3426 if (wfEmptyMsg($message, $text)) {
3427 $text = false;
3428 break;
3429 }
3430 } else {
3431 break;
3432 }
3433 if ($text === false) {
3434 break;
3435 }
3436 // Redirect?
3437 $title = Title::newFromRedirect($text);
3438 }
static newFromRedirect($text)
Create a new Title for a redirect.
Definition: Title.php:301
$message
Definition: xapiexit.php:14

◆ findColonNoLinks()

Parser::findColonNoLinks (   $str,
$before,
$after 
)

Split up a string on ':', ignoring any occurences inside tags to prevent illegal overlapping.

Parameters
string$strthe string to split
string&$beforeset to everything before the ':'
string&$afterset to everything after the ':' return string the position of the ':', or false if none found

Definition at line 2344 of file Parser.php.

2344 :', or false if none found
2345 */
2346 public function findColonNoLinks($str, &$before, &$after)
2347 {
2348 $fname = 'Parser::findColonNoLinks';
2349 wfProfileIn($fname);
2350
2351 $pos = strpos($str, ':');
2352 if ($pos === false) {
2353 // Nothing to find!
2354 wfProfileOut($fname);
2355 return false;
2356 }
2357
2358 $lt = strpos($str, '<');
2359 if ($lt === false || $lt > $pos) {
2360 // Easy; no tag nesting to worry about
2361 $before = substr($str, 0, $pos);
2362 $after = substr($str, $pos + 1);
2363 wfProfileOut($fname);
2364 return $pos;
2365 }
2366
2367 // Ugly state machine to walk through avoiding tags.
2368 $state = MW_COLON_STATE_TEXT;
2369 $stack = 0;
2370 $len = strlen($str);
2371 for ($i = 0; $i < $len; $i++) {
2372 $c = $str[$i];
2373
2374 switch ($state) {
2375 // (Using the number is a performance hack for common cases)
2376 case 0: // MW_COLON_STATE_TEXT:
2377 switch ($c) {
2378 case "<":
2379 // Could be either a <start> tag or an </end> tag
2380 $state = MW_COLON_STATE_TAGSTART;
2381 break;
2382 case ":":
2383 if ($stack == 0) {
2384 // We found it!
2385 $before = substr($str, 0, $i);
2386 $after = substr($str, $i + 1);
2387 wfProfileOut($fname);
2388 return $i;
2389 }
2390 // Embedded in a tag; don't break it.
2391 break;
2392 default:
2393 // Skip ahead looking for something interesting
2394 $colon = strpos($str, ':', $i);
2395 if ($colon === false) {
2396 // Nothing else interesting
2397 wfProfileOut($fname);
2398 return false;
2399 }
2400 $lt = strpos($str, '<', $i);
2401 if ($stack === 0) {
2402 if ($lt === false || $colon < $lt) {
2403 // We found it!
2404 $before = substr($str, 0, $colon);
2405 $after = substr($str, $colon + 1);
2406 wfProfileOut($fname);
2407 return $i;
2408 }
2409 }
2410 if ($lt === false) {
2411 // Nothing else interesting to find; abort!
2412 // We're nested, but there's no close tags left. Abort!
2413 break 2;
2414 }
2415 // Skip ahead to next tag start
2416 $i = $lt;
2417 $state = MW_COLON_STATE_TAGSTART;
2418 }
2419 break;
2420 case 1: // MW_COLON_STATE_TAG:
2421 // In a <tag>
2422 switch ($c) {
2423 case ">":
2424 $stack++;
2425 $state = MW_COLON_STATE_TEXT;
2426 break;
2427 case "/":
2428 // Slash may be followed by >?
2429 $state = MW_COLON_STATE_TAGSLASH;
2430 break;
2431 default:
2432 // ignore
2433 }
2434 break;
2435 case 2: // MW_COLON_STATE_TAGSTART:
2436 switch ($c) {
2437 case "/":
2438 $state = MW_COLON_STATE_CLOSETAG;
2439 break;
2440 case "!":
2441 $state = MW_COLON_STATE_COMMENT;
2442 break;
2443 case ">":
2444 // Illegal early close? This shouldn't happen D:
2445 $state = MW_COLON_STATE_TEXT;
2446 break;
2447 default:
2448 $state = MW_COLON_STATE_TAG;
2449 }
2450 break;
2451 case 3: // MW_COLON_STATE_CLOSETAG:
2452 // In a </tag>
2453 if ($c == ">") {
2454 $stack--;
2455 if ($stack < 0) {
2456 wfDebug("Invalid input in $fname; too many close tags\n");
2457 wfProfileOut($fname);
2458 return false;
2459 }
2460 $state = MW_COLON_STATE_TEXT;
2461 }
2462 break;
2464 if ($c == ">") {
2465 // Yes, a self-closed tag <blah/>
2466 $state = MW_COLON_STATE_TEXT;
2467 } else {
2468 // Probably we're jumping the gun, and this is an attribute
2469 $state = MW_COLON_STATE_TAG;
2470 }
2471 break;
2472 case 5: // MW_COLON_STATE_COMMENT:
2473 if ($c == "-") {
2475 }
2476 break;
2478 if ($c == "-") {
2480 } else {
2481 $state = MW_COLON_STATE_COMMENT;
2482 }
2483 break;
2485 if ($c == ">") {
2486 $state = MW_COLON_STATE_TEXT;
2487 } else {
2488 $state = MW_COLON_STATE_COMMENT;
2489 }
2490 break;
2491 default:
2492 throw new MWException("State machine error in $fname");
2493 }
2494 }
2495 if ($stack > 0) {
2496 wfDebug("Invalid input in $fname; not enough close tags (stack $stack, state $state)\n");
2497 return false;
2498 }
2499 wfProfileOut($fname);
const MW_COLON_STATE_TAGSTART
Definition: Parser.php:50
const MW_COLON_STATE_COMMENTDASHDASH
Definition: Parser.php:55
const MW_COLON_STATE_TAG
Definition: Parser.php:49
const MW_COLON_STATE_CLOSETAG
Definition: Parser.php:51
const MW_COLON_STATE_TEXT
Definition: Parser.php:48
const MW_COLON_STATE_COMMENTDASH
Definition: Parser.php:54
const MW_COLON_STATE_TAGSLASH
Definition: Parser.php:52
const MW_COLON_STATE_COMMENT
Definition: Parser.php:53

◆ firstCallInit()

Parser::firstCallInit ( )

Do various kinds of initialisation on the first call of the parser.

Definition at line 156 of file Parser.php.

159 {
160 if (!$this->mFirstCall) {
161 return;
162 }
163
164 wfProfileIn(__METHOD__);
165 global $wgAllowDisplayTitle, $wgAllowSlowParserFunctions;
166
167 $this->setHook('pre', array( $this, 'renderPreTag' ));
168
169 $this->setFunctionHook('int', array( 'CoreParserFunctions', 'intFunction' ), SFH_NO_HASH);
170 $this->setFunctionHook('ns', array( 'CoreParserFunctions', 'ns' ), SFH_NO_HASH);
171 $this->setFunctionHook('urlencode', array( 'CoreParserFunctions', 'urlencode' ), SFH_NO_HASH);
172 $this->setFunctionHook('lcfirst', array( 'CoreParserFunctions', 'lcfirst' ), SFH_NO_HASH);
173 $this->setFunctionHook('ucfirst', array( 'CoreParserFunctions', 'ucfirst' ), SFH_NO_HASH);
174 $this->setFunctionHook('lc', array( 'CoreParserFunctions', 'lc' ), SFH_NO_HASH);
175 $this->setFunctionHook('uc', array( 'CoreParserFunctions', 'uc' ), SFH_NO_HASH);
176 $this->setFunctionHook('localurl', array( 'CoreParserFunctions', 'localurl' ), SFH_NO_HASH);
177 $this->setFunctionHook('localurle', array( 'CoreParserFunctions', 'localurle' ), SFH_NO_HASH);
178 $this->setFunctionHook('fullurl', array( 'CoreParserFunctions', 'fullurl' ), SFH_NO_HASH);
179 $this->setFunctionHook('fullurle', array( 'CoreParserFunctions', 'fullurle' ), SFH_NO_HASH);
180 $this->setFunctionHook('formatnum', array( 'CoreParserFunctions', 'formatnum' ), SFH_NO_HASH);
181 $this->setFunctionHook('grammar', array( 'CoreParserFunctions', 'grammar' ), SFH_NO_HASH);
182 $this->setFunctionHook('plural', array( 'CoreParserFunctions', 'plural' ), SFH_NO_HASH);
183 $this->setFunctionHook('numberofpages', array( 'CoreParserFunctions', 'numberofpages' ), SFH_NO_HASH);
184 $this->setFunctionHook('numberofusers', array( 'CoreParserFunctions', 'numberofusers' ), SFH_NO_HASH);
185 $this->setFunctionHook('numberofarticles', array( 'CoreParserFunctions', 'numberofarticles' ), SFH_NO_HASH);
186 $this->setFunctionHook('numberoffiles', array( 'CoreParserFunctions', 'numberoffiles' ), SFH_NO_HASH);
187 $this->setFunctionHook('numberofadmins', array( 'CoreParserFunctions', 'numberofadmins' ), SFH_NO_HASH);
188 $this->setFunctionHook('numberofedits', array( 'CoreParserFunctions', 'numberofedits' ), SFH_NO_HASH);
189 $this->setFunctionHook('language', array( 'CoreParserFunctions', 'language' ), SFH_NO_HASH);
190 $this->setFunctionHook('padleft', array( 'CoreParserFunctions', 'padleft' ), SFH_NO_HASH);
191 $this->setFunctionHook('padright', array( 'CoreParserFunctions', 'padright' ), SFH_NO_HASH);
192 $this->setFunctionHook('anchorencode', array( 'CoreParserFunctions', 'anchorencode' ), SFH_NO_HASH);
193 $this->setFunctionHook('special', array( 'CoreParserFunctions', 'special' ));
194 $this->setFunctionHook('defaultsort', array( 'CoreParserFunctions', 'defaultsort' ), SFH_NO_HASH);
195
196 if ($wgAllowDisplayTitle) {
197 $this->setFunctionHook('displaytitle', array( 'CoreParserFunctions', 'displaytitle' ), SFH_NO_HASH);
198 }
199 if ($wgAllowSlowParserFunctions) {
200 $this->setFunctionHook('pagesinnamespace', array( 'CoreParserFunctions', 'pagesinnamespace' ), SFH_NO_HASH);
201 }
202
203 $this->initialiseVariables();
204 $this->mFirstCall = false;
const SFH_NO_HASH
Definition: Parser.php:24
setFunctionHook($id, $callback, $flags=0)
Create a function, e.g.
Definition: Parser.php:4113
setHook($tag, $callback)
Create an HTML-style tag, e.g.
Definition: Parser.php:4080
initialiseVariables()
initialise the magic variables (like CURRENTMONTHNAME)
Definition: Parser.php:2704

◆ formatHeadings()

Parser::formatHeadings (   $text,
  $isMain = true 
)

This function accomplishes several tasks: 1) Auto-number headings if that option is enabled 2) Add an [edit] link to sections for logged in users who have enabled the option 3) Add a Table of contents on the top for users who have enabled the option 4) Auto-anchor headings.

It loops through all headlines, collects the necessary data, then splits up the string and re-inserts the newly formatted headlines.

Parameters
string$text
boolean$isMain

Definition at line 3582 of file Parser.php.

3585 {
3586 global $wgMaxTocLevel, $wgContLang;
3587
3588 $doNumberHeadings = $this->mOptions->getNumberHeadings();
3589 if (!$this->mTitle->quickUserCan('edit')) {
3590 $showEditLink = 0;
3591 } else {
3592 $showEditLink = $this->mOptions->getEditSection();
3593 }
3594
3595 # Inhibit editsection links if requested in the page
3596 $esw = &MagicWord::get('noeditsection');
3597 if ($esw->matchAndRemove($text)) {
3598 $showEditLink = 0;
3599 }
3600
3601 # Get all headlines for numbering them and adding funky stuff like [edit]
3602 # links - this is for later, but we need the number of headlines right now
3603 $matches = array();
3604 $numMatches = preg_match_all('/<H(?P<level>[1-6])(?P<attrib>.*?' . '>)(?P<header>.*?)<\/H[1-6] *>/i', $text, $matches);
3605
3606 # if there are fewer than 4 headlines in the article, do not show TOC
3607 # unless it's been explicitly enabled.
3608 $enoughToc = $this->mShowToc &&
3609 (($numMatches >= 4) || $this->mForceTocPosition);
3610
3611 # Allow user to stipulate that a page should have a "new section"
3612 # link added via __NEWSECTIONLINK__
3613 $mw = &MagicWord::get('newsectionlink');
3614 if ($mw->matchAndRemove($text)) {
3615 $this->mOutput->setNewSection(true);
3616 }
3617
3618 # if the string __FORCETOC__ (not case-sensitive) occurs in the HTML,
3619 # override above conditions and always show TOC above first header
3620 $mw = &MagicWord::get('forcetoc');
3621 if ($mw->matchAndRemove($text)) {
3622 $this->mShowToc = true;
3623 $enoughToc = true;
3624 }
3625
3626 # Never ever show TOC if no headers
3627 if ($numMatches < 1) {
3628 $enoughToc = false;
3629 }
3630
3631 # We need this to perform operations on the HTML
3632 $sk = $this->mOptions->getSkin();
3633
3634 # headline counter
3635 $headlineCount = 0;
3636 $sectionCount = 0; # headlineCount excluding template sections
3637
3638 # Ugh .. the TOC should have neat indentation levels which can be
3639 # passed to the skin functions. These are determined here
3640 $toc = '';
3641 $full = '';
3642 $head = array();
3643 $sublevelCount = array();
3644 $levelCount = array();
3645 $toclevel = 0;
3646 $level = 0;
3647 $prevlevel = 0;
3648 $toclevel = 0;
3649 $prevtoclevel = 0;
3650
3651 foreach ($matches[3] as $headline) {
3652 $istemplate = 0;
3653 $templatetitle = '';
3654 $templatesection = 0;
3655 $numbering = '';
3656 $mat = array();
3657 if (preg_match("/<!--MWTEMPLATESECTION=([^&]+)&([^_]+)-->/", $headline, $mat)) {
3658 $istemplate = 1;
3659 $templatetitle = base64_decode($mat[1]);
3660 $templatesection = 1 + (int) base64_decode($mat[2]);
3661 $headline = preg_replace("/<!--MWTEMPLATESECTION=([^&]+)&([^_]+)-->/", "", $headline);
3662 }
3663
3664 if ($toclevel) {
3665 $prevlevel = $level;
3666 $prevtoclevel = $toclevel;
3667 }
3668 $level = $matches[1][$headlineCount];
3669
3670 if ($doNumberHeadings || $enoughToc) {
3671 if ($level > $prevlevel) {
3672 # Increase TOC level
3673 $toclevel++;
3674 $sublevelCount[$toclevel] = 0;
3675 if ($toclevel < $wgMaxTocLevel) {
3676 $toc .= $sk->tocIndent();
3677 }
3678 } elseif ($level < $prevlevel && $toclevel > 1) {
3679 # Decrease TOC level, find level to jump to
3680
3681 if ($toclevel == 2 && $level <= $levelCount[1]) {
3682 # Can only go down to level 1
3683 $toclevel = 1;
3684 } else {
3685 for ($i = $toclevel; $i > 0; $i--) {
3686 if ($levelCount[$i] == $level) {
3687 # Found last matching level
3688 $toclevel = $i;
3689 break;
3690 } elseif ($levelCount[$i] < $level) {
3691 # Found first matching level below current level
3692 $toclevel = $i + 1;
3693 break;
3694 }
3695 }
3696 }
3697 if ($toclevel < $wgMaxTocLevel) {
3698 $toc .= $sk->tocUnindent($prevtoclevel - $toclevel);
3699 }
3700 } else {
3701 # No change in level, end TOC line
3702 if ($toclevel < $wgMaxTocLevel) {
3703 $toc .= $sk->tocLineEnd();
3704 }
3705 }
3706
3707 $levelCount[$toclevel] = $level;
3708
3709 # count number of headlines for each level
3710 @$sublevelCount[$toclevel]++;
3711 $dot = 0;
3712 for ($i = 1; $i <= $toclevel; $i++) {
3713 if (!empty($sublevelCount[$i])) {
3714 if ($dot) {
3715 $numbering .= '.';
3716 }
3717 $numbering .= $wgContLang->formatNum($sublevelCount[$i]);
3718 $dot = 1;
3719 }
3720 }
3721 }
3722
3723 # The canonized header is a version of the header text safe to use for links
3724 # Avoid insertion of weird stuff like <math> by expanding the relevant sections
3725 $canonized_headline = $this->mStripState->unstripBoth($headline);
3726
3727 # Remove link placeholders by the link text.
3728 # <!--LINK number-->
3729 # turns into
3730 # link text with suffix
3731 $canonized_headline = preg_replace_callback(
3732 '/<!--LINK ([0-9]*)-->/',
3733 function ($hit) {
3734 return $this->mLinkHolders['texts'][$hit[1]];
3735 },
3736 $canonized_headline
3737 );
3738 $canonized_headline = preg_replace_callback(
3739 '/<!--IWLINK ([0-9]*)-->/',
3740 function ($hit) {
3741 return $this->mInterwikiLinkHolders['texts'][$hit[1]];
3742 },
3743 $canonized_headline
3744 );
3745
3746 # strip out HTML
3747 $canonized_headline = preg_replace('/<.*?' . '>/', '', $canonized_headline);
3748 $tocline = trim($canonized_headline);
3749 # Save headline for section edit hint before it's escaped
3750 $headline_hint = trim($canonized_headline);
3751 $canonized_headline = Sanitizer::escapeId($tocline);
3752 $refers[$headlineCount] = $canonized_headline;
3753
3754 # count how many in assoc. array so we can track dupes in anchors
3755 isset($refers[$canonized_headline]) ? $refers[$canonized_headline]++ : $refers[$canonized_headline] = 1;
3756 $refcount[$headlineCount] = $refers[$canonized_headline];
3757
3758 # Don't number the heading if it is the only one (looks silly)
3759 if ($doNumberHeadings && count($matches[3]) > 1) {
3760 # the two are different if the line contains a link
3761 $headline = $numbering . ' ' . $headline;
3762 }
3763
3764 # Create the anchor for linking from the TOC to the section
3765 $anchor = $canonized_headline;
3766 if ($refcount[$headlineCount] > 1) {
3767 $anchor .= '_' . $refcount[$headlineCount];
3768 }
3769 if ($enoughToc && (!isset($wgMaxTocLevel) || $toclevel < $wgMaxTocLevel)) {
3770 $toc .= $sk->tocLine($anchor, $tocline, $numbering, $toclevel);
3771 }
3772 # give headline the correct <h#> tag
3773 if ($showEditLink && (!$istemplate || $templatetitle !== "")) {
3774 if ($istemplate) {
3775 $editlink = $sk->editSectionLinkForOther($templatetitle, $templatesection);
3776 } else {
3777 $editlink = $sk->editSectionLink($this->mTitle, $sectionCount + 1, $headline_hint);
3778 }
3779 } else {
3780 $editlink = '';
3781 }
3782 $head[$headlineCount] = $sk->makeHeadline($level, $matches['attrib'][$headlineCount], $anchor, $headline, $editlink);
3783
3784 $headlineCount++;
3785 if (!$istemplate) {
3786 $sectionCount++;
3787 }
3788 }
3789
3790 if ($enoughToc) {
3791 if ($toclevel < $wgMaxTocLevel) {
3792 $toc .= $sk->tocUnindent($toclevel - 1);
3793 }
3794 $toc = $sk->tocList($toc);
3795 }
3796
3797 # split up and insert constructed headlines
3798
3799 $blocks = preg_split('/<H[1-6].*?' . '>.*?<\/H[1-6]>/i', $text);
3800 $i = 0;
3801
3802 foreach ($blocks as $block) {
3803 if ($showEditLink && $headlineCount > 0 && $i == 0 && $block != "\n") {
3804 # This is the [edit] link that appears for the top block of text when
3805 # section editing is enabled
3806
3807 # Disabled because it broke block formatting
3808 # For example, a bullet point in the top line
3809 # $full .= $sk->editSectionLink(0);
3810 }
3811 $full .= $block;
3812 if ($enoughToc && !$i && $isMain && !$this->mForceTocPosition) {
3813 # Top anchor now in skin
3814 $full = $full . $toc;
3815 }
3816
3817 if (!empty($head[$i])) {
3818 $full .= $head[$i];
3819 }
3820 $i++;
3821 }
3822 if ($this->mForceTocPosition) {
3823 return str_replace('<!--MWTOC-->', $toc, $full);
3824 } else {
3825 return $full;
static escapeId($id)
Given a value escape it so that it can be used in an id attribute and return it, this does not valida...
Definition: Sanitizer.php:760

◆ getCommon()

Parser::getCommon (   $st1,
  $st2 
)

Definition at line 2087 of file Parser.php.

2090 {
2091 $fl = strlen($st1);
2092 $shorter = strlen($st2);
2093 if ($fl < $shorter) {
2094 $shorter = $fl;
2095 }
2096
2097 for ($i = 0; $i < $shorter; ++$i) {
2098 if ($st1[$i] != $st2[$i]) {
2099 break;
2100 }
2101 }

References $i.

◆ getDefaultSort()

Parser::getDefaultSort ( )

Accessor for $mDefaultSort Will use the title/prefixed title if none is set.

Returns
string

Definition at line 4947 of file Parser.php.

4950 {
4951 if ($this->mDefaultSort !== false) {
4952 return $this->mDefaultSort;
4953 } else {
4954 return $this->mTitle->getNamespace() == NS_CATEGORY
4955 ? $this->mTitle->getText()
4956 : $this->mTitle->getPrefixedText();
$mDefaultSort
Definition: Parser.php:115

◆ getFunctionHooks()

Parser::getFunctionHooks ( )

Get all registered function hook identifiers.

Returns
array

Definition at line 4150 of file Parser.php.

4153 {

◆ getFunctionLang()

Parser::getFunctionLang ( )

Definition at line 466 of file Parser.php.

469 {
470 global $wgLang, $wgContLang;

◆ getOptions()

Parser::getOptions ( )

Definition at line 461 of file Parser.php.

464 {

◆ getRandomString()

Parser::getRandomString ( )
static

Get a random string.

Definition at line 452 of file Parser.php.

455 {

◆ getRevisionTimestamp()

Parser::getRevisionTimestamp ( )

Get the timestamp associated with the current revision, adjusted for the default server-local timestamp.

Definition at line 4899 of file Parser.php.

4902 {
4903 if (is_null($this->mRevisionTimestamp)) {
4904 wfProfileIn(__METHOD__);
4905 global $wgContLang;
4906 $dbr = wfGetDB(DB_SLAVE);
4907 $timestamp = $dbr->selectField(
4908 'revision',
4909 'rev_timestamp',
4910 array( 'rev_id' => $this->mRevisionId ),
4911 __METHOD__
4912 );
4913
4914 // Normalize timestamp to internal MW format for timezone processing.
4915 // This has the added side-effect of replacing a null value with
4916 // the current time, which gives us more sensible behavior for
4917 // previews.
4918 $timestamp = wfTimestamp(TS_MW, $timestamp);
4919
4920 // The cryptic '' timezone parameter tells to use the site-default
4921 // timezone offset instead of the user settings.
4922 //
4923 // Since this value will be saved into the parser cache, served
4924 // to other users, and potentially even used inside links and such,
4925 // it needs to be consistent for all visitors.
4926 $this->mRevisionTimestamp = $wgContLang->userAdjust($timestamp, '');
4927
4928 wfProfileOut(__METHOD__);
4929 }
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:81

◆ getSection()

Parser::getSection (   $text,
  $section,
  $deftext = '' 
)

This function returns the text of a section, specified by a number ($section).

A section is text under a heading like == Heading == or <h1>Heading</h1>, or the first section before any such heading (section 0).

If a section contains subsections, these are also returned.

Parameters
$textString: text to look in
$sectionInteger: section number
$deftextdefault to return if section is not found
Returns
string text of the requested section

Definition at line 4885 of file Parser.php.

4888 {

◆ getTags()

Parser::getTags ( )

#-

#+ Accessor

Definition at line 4741 of file Parser.php.

4744 {

◆ getTitle()

& Parser::getTitle ( )

Definition at line 457 of file Parser.php.

460 {

◆ getUserSig()

Parser::getUserSig ( $user)

Fetch the user's signature text, if any, and normalize to validated, ready-to-insert wikitext.

Parameters
User$user
Returns
string

Definition at line 3937 of file Parser.php.

3940 {
3941 $username = $user->getName();
3942 $nickname = $user->getOption('nickname');
3943 $nickname = $nickname === '' ? $username : $nickname;
3944
3945 if ($user->getBoolOption('fancysig') !== false) {
3946 # Sig. might contain markup; validate this
3947 if ($this->validateSig($nickname) !== false) {
3948 # Validated; clean up (if needed) and return it
3949 return $this->cleanSig($nickname, true);
3950 } else {
3951 # Failed to validate; fall back to the default
3952 $nickname = $username;
3953 wfDebug("Parser::getUserSig: $username has bad XML tags in signature.\n");
3954 }
3955 }
3956
3957 // Make sure nickname doesnt get a sig in a sig
3958 $nickname = $this->cleanSigInSig($nickname);
3959
3960 # If we're still here, make it a link to the user page
3961 $userpage = $user->getUserPage();
cleanSig($text, $parsing=false)
Clean up signature text.
Definition: Parser.php:3984
validateSig($text)
Check that the user's signature contains no bad XML.
Definition: Parser.php:3969

◆ getVariableValue()

Parser::getVariableValue (   $index)

Return value of a magic variable (like PAGENAME)

Some of these require message or data lookups and can be expensive to check many times.

Definition at line 2506 of file Parser.php.

2509 {
2510 global $wgContLang, $wgSitename, $wgServer, $wgServerName, $wgScriptPath;
2511
2516 static $varCache = array();
2517 if (wfRunHooks('ParserGetVariableValueVarCache', array( &$this, &$varCache ))) {
2518 if (isset($varCache[$index])) {
2519 return $varCache[$index];
2520 }
2521 }
2522
2523 $ts = time();
2524 wfRunHooks('ParserGetVariableValueTs', array( &$this, &$ts ));
2525
2526 # Use the time zone
2527 global $wgLocaltimezone;
2528 if (isset($wgLocaltimezone)) {
2529 $oldtz = getenv('TZ');
2530 putenv('TZ=' . $wgLocaltimezone);
2531 }
2532 $localTimestamp = date('YmdHis', $ts);
2533 $localMonth = date('m', $ts);
2534 $localMonthName = date('n', $ts);
2535 $localDay = date('j', $ts);
2536 $localDay2 = date('d', $ts);
2537 $localDayOfWeek = date('w', $ts);
2538 $localWeek = date('W', $ts);
2539 $localYear = date('Y', $ts);
2540 $localHour = date('H', $ts);
2541 if (isset($wgLocaltimezone)) {
2542 putenv('TZ=' . $oldtz);
2543 }
2544
2545 switch ($index) {
2546 case 'currentmonth':
2547 return $varCache[$index] = $wgContLang->formatNum(date('m', $ts));
2548 case 'currentmonthname':
2549 return $varCache[$index] = $wgContLang->getMonthName(date('n', $ts));
2550 case 'currentmonthnamegen':
2551 return $varCache[$index] = $wgContLang->getMonthNameGen(date('n', $ts));
2552 case 'currentmonthabbrev':
2553 return $varCache[$index] = $wgContLang->getMonthAbbreviation(date('n', $ts));
2554 case 'currentday':
2555 return $varCache[$index] = $wgContLang->formatNum(date('j', $ts));
2556 case 'currentday2':
2557 return $varCache[$index] = $wgContLang->formatNum(date('d', $ts));
2558 case 'localmonth':
2559 return $varCache[$index] = $wgContLang->formatNum($localMonth);
2560 case 'localmonthname':
2561 return $varCache[$index] = $wgContLang->getMonthName($localMonthName);
2562 case 'localmonthnamegen':
2563 return $varCache[$index] = $wgContLang->getMonthNameGen($localMonthName);
2564 case 'localmonthabbrev':
2565 return $varCache[$index] = $wgContLang->getMonthAbbreviation($localMonthName);
2566 case 'localday':
2567 return $varCache[$index] = $wgContLang->formatNum($localDay);
2568 case 'localday2':
2569 return $varCache[$index] = $wgContLang->formatNum($localDay2);
2570 case 'pagename':
2571 return $this->mTitle->getText();
2572 case 'pagenamee':
2573 return $this->mTitle->getPartialURL();
2574 case 'fullpagename':
2575 return $this->mTitle->getPrefixedText();
2576 case 'fullpagenamee':
2577 return $this->mTitle->getPrefixedURL();
2578 case 'subpagename':
2579 return $this->mTitle->getSubpageText();
2580 case 'subpagenamee':
2581 return $this->mTitle->getSubpageUrlForm();
2582 case 'basepagename':
2583 return $this->mTitle->getBaseText();
2584 case 'basepagenamee':
2585 return wfUrlEncode(str_replace(' ', '_', $this->mTitle->getBaseText()));
2586 case 'talkpagename':
2587 if ($this->mTitle->canTalk()) {
2588 $talkPage = $this->mTitle->getTalkPage();
2589 return $talkPage->getPrefixedText();
2590 } else {
2591 return '';
2592 }
2593 // no break
2594 case 'talkpagenamee':
2595 if ($this->mTitle->canTalk()) {
2596 $talkPage = $this->mTitle->getTalkPage();
2597 return $talkPage->getPrefixedUrl();
2598 } else {
2599 return '';
2600 }
2601 // no break
2602 case 'subjectpagename':
2603 $subjPage = $this->mTitle->getSubjectPage();
2604 return $subjPage->getPrefixedText();
2605 case 'subjectpagenamee':
2606 $subjPage = $this->mTitle->getSubjectPage();
2607 return $subjPage->getPrefixedUrl();
2608 case 'revisionid':
2609 return $this->mRevisionId;
2610 case 'revisionday':
2611 return intval(substr($this->getRevisionTimestamp(), 6, 2));
2612 case 'revisionday2':
2613 return substr($this->getRevisionTimestamp(), 6, 2);
2614 case 'revisionmonth':
2615 return intval(substr($this->getRevisionTimestamp(), 4, 2));
2616 case 'revisionyear':
2617 return substr($this->getRevisionTimestamp(), 0, 4);
2618 case 'revisiontimestamp':
2619 return $this->getRevisionTimestamp();
2620 case 'namespace':
2621 return str_replace('_', ' ', $wgContLang->getNsText($this->mTitle->getNamespace()));
2622 case 'namespacee':
2623 return wfUrlencode($wgContLang->getNsText($this->mTitle->getNamespace()));
2624 case 'talkspace':
2625 return $this->mTitle->canTalk() ? str_replace('_', ' ', $this->mTitle->getTalkNsText()) : '';
2626 case 'talkspacee':
2627 return $this->mTitle->canTalk() ? wfUrlencode($this->mTitle->getTalkNsText()) : '';
2628 case 'subjectspace':
2629 return $this->mTitle->getSubjectNsText();
2630 case 'subjectspacee':
2631 return(wfUrlencode($this->mTitle->getSubjectNsText()));
2632 case 'currentdayname':
2633 return $varCache[$index] = $wgContLang->getWeekdayName(date('w', $ts) + 1);
2634 case 'currentyear':
2635 return $varCache[$index] = $wgContLang->formatNum(date('Y', $ts), true);
2636 case 'currenttime':
2637 return $varCache[$index] = $wgContLang->time(wfTimestamp(TS_MW, $ts), false, false);
2638 case 'currenthour':
2639 return $varCache[$index] = $wgContLang->formatNum(date('H', $ts), true);
2640 case 'currentweek':
2641 // @bug 4594 PHP5 has it zero padded, PHP4 does not, cast to
2642 // int to remove the padding
2643 return $varCache[$index] = $wgContLang->formatNum((int) date('W', $ts));
2644 case 'currentdow':
2645 return $varCache[$index] = $wgContLang->formatNum(date('w', $ts));
2646 case 'localdayname':
2647 return $varCache[$index] = $wgContLang->getWeekdayName($localDayOfWeek + 1);
2648 case 'localyear':
2649 return $varCache[$index] = $wgContLang->formatNum($localYear, true);
2650 case 'localtime':
2651 return $varCache[$index] = $wgContLang->time($localTimestamp, false, false);
2652 case 'localhour':
2653 return $varCache[$index] = $wgContLang->formatNum($localHour, true);
2654 case 'localweek':
2655 // @bug 4594 PHP5 has it zero padded, PHP4 does not, cast to
2656 // int to remove the padding
2657 return $varCache[$index] = $wgContLang->formatNum((int) $localWeek);
2658 case 'localdow':
2659 return $varCache[$index] = $wgContLang->formatNum($localDayOfWeek);
2660 case 'numberofarticles':
2661 return $varCache[$index] = $wgContLang->formatNum(SiteStats::articles());
2662 case 'numberoffiles':
2663 return $varCache[$index] = $wgContLang->formatNum(SiteStats::images());
2664 case 'numberofusers':
2665 return $varCache[$index] = $wgContLang->formatNum(SiteStats::users());
2666 case 'numberofpages':
2667 return $varCache[$index] = $wgContLang->formatNum(SiteStats::pages());
2668 case 'numberofadmins':
2669 return $varCache[$index] = $wgContLang->formatNum(SiteStats::admins());
2670 case 'numberofedits':
2671 return $varCache[$index] = $wgContLang->formatNum(SiteStats::edits());
2672 case 'currenttimestamp':
2673 return $varCache[$index] = wfTimestampNow();
2674 case 'localtimestamp':
2675 return $varCache[$index] = $localTimestamp;
2676 case 'currentversion':
2677 return $varCache[$index] = SpecialVersion::getVersion();
2678 case 'sitename':
2679 return $wgSitename;
2680 case 'server':
2681 return $wgServer;
2682 case 'servername':
2683 return $wgServerName;
2684 case 'scriptpath':
2685 return $wgScriptPath;
2686 case 'directionmark':
2687 return $wgContLang->getDirMark();
2688 case 'contentlanguage':
2689 global $wgContLanguageCode;
2690 return $wgContLanguageCode;
2691 default:
2692 $ret = null;
2693 if (wfRunHooks('ParserGetVariableValueSwitch', array( &$this, &$varCache, &$index, &$ret ))) {
2694 return $ret;
2695 } else {
2696 return null;
2697 }
getRevisionTimestamp()
Get the timestamp associated with the current revision, adjusted for the default server-local timesta...
Definition: Parser.php:4899
$mRevisionId
Definition: Parser.php:132
$ret
Definition: parser.php:6

◆ incrementIncludeSize()

Parser::incrementIncludeSize (   $type,
  $size 
)

Increment an include size counter.

Parameters
string$typeThe type of expansion
integer$sizeThe size of the text
Returns
boolean False if this inclusion would take it over the maximum, true otherwise

Definition at line 3521 of file Parser.php.

3524 {
3525 if ($this->mIncludeSizes[$type] + $size > $this->mOptions->getMaxIncludeSize()) {
3526 return false;
3527 } else {
3528 $this->mIncludeSizes[$type] += $size;
3529 return true;
$size
Definition: RandomTest.php:84
$type

◆ initialiseVariables()

Parser::initialiseVariables ( )

initialise the magic variables (like CURRENTMONTHNAME)

Definition at line 2704 of file Parser.php.

2707 {
2708 $fname = 'Parser::initialiseVariables';
2709 wfProfileIn($fname);
2710 $variableIDs = MagicWord::getVariableIDs();
2711
2712 $this->mVariables = array();
2713 foreach ($variableIDs as $id) {
2714 $mw = &MagicWord::get($id);
2715 $mw->addToArray($this->mVariables, $id);
2716 }

◆ insertStripItem()

Parser::insertStripItem (   $text,
$state 
)

Add an item to the strip state Returns the unique tag which must be inserted into the stripped text The tag will be replaced with the original text in unstrip()

Definition at line 720 of file Parser.php.

723 {
724 $rnd = $this->mUniqPrefix . '-item' . Parser::getRandomString();
725 $state->general->setPair($rnd, $text);

◆ internalParse()

Parser::internalParse (   $text)

Helper function for parse() that transforms wiki markup into HTML.

Only called for $mOutputType == OT_HTML.

Definition at line 1032 of file Parser.php.

1035 {
1036 $args = array();
1037 $isMain = true;
1038 $fname = 'Parser::internalParse';
1039 wfProfileIn($fname);
1040
1041 # Hook to suspend the parser in this state
1042 if (!wfRunHooks('ParserBeforeInternalParse', array( &$this, &$text, &$this->mStripState ))) {
1043 wfProfileOut($fname);
1044 return $text ;
1045 }
1046
1047 # Remove <noinclude> tags and <includeonly> sections
1048 $text = strtr($text, array( '<onlyinclude>' => '' , '</onlyinclude>' => '' ));
1049 $text = strtr($text, array( '<noinclude>' => '', '</noinclude>' => ''));
1050 $text = StringUtils::delimiterReplace('<includeonly>', '</includeonly>', '', $text);
1051
1052 $text = Sanitizer::removeHTMLtags($text, array( &$this, 'attributeStripCallback' ));
1053
1054 $text = $this->replaceVariables($text, $args);
1055 wfRunHooks('InternalParseBeforeLinks', array( &$this, &$text, &$this->mStripState ));
1056
1057 // Tables need to come after variable replacement for things to work
1058 // properly; putting them before other transformations should keep
1059 // exciting things like link expansions from showing up in surprising
1060 // places.
1061 $text = $this->doTableStuff($text);
1062
1063 $text = preg_replace('/(^|\n)-----*/', '\\1<hr />', $text);
1064
1065 $text = $this->stripToc($text);
1066 $this->stripNoGallery($text);
1067 $text = $this->doHeadings($text);
1068 if ($this->mOptions->getUseDynamicDates()) {
1069 $df = &DateFormatter::getInstance();
1070 $text = $df->reformat($this->mOptions->getDateFormat(), $text);
1071 }
1072 $text = $this->doAllQuotes($text);
1073 $text = $this->replaceInternalLinks($text);
1074 $text = $this->replaceExternalLinks($text);
1075
1076 # replaceInternalLinks may sometimes leave behind
1077 # absolute URLs, which have to be masked to hide them from replaceExternalLinks
1078 $text = str_replace($this->mUniqPrefix . "NOPARSE", "", $text);
1079
1080 $text = $this->doMagicLinks($text);
1081 $text = $this->formatHeadings($text, $isMain);
1082
1083 wfProfileOut($fname);
doTableStuff($text)
parse the wiki syntax used to render tables
Definition: Parser.php:843
stripToc($text)
Detect TOC magic word and set a placeholder.
Definition: Parser.php:3545
replaceInternalLinks($s)
Process [[ ]] wikilinks.
Definition: Parser.php:1610
& doMagicLinks(&$text)
Replace special strings like "ISBN xxx" and "RFC xxx" with magic external links.
Definition: Parser.php:1091
replaceExternalLinks($text)
Replace external links.
Definition: Parser.php:1380
stripNoGallery(&$text)
Detect NOGALLERY magic word and set a placeholder.
Definition: Parser.php:3534
doAllQuotes($text)
Replace single quotes with HTML markup.
Definition: Parser.php:1176
formatHeadings($text, $isMain=true)
This function accomplishes several tasks: 1) Auto-number headings if that option is enabled 2) Add an...
Definition: Parser.php:3582
doHeadings($text)
Parse headers and return html.
Definition: Parser.php:1155

◆ internalTidy()

Parser::internalTidy (   $text)
static

Use the HTML tidy PECL extension to use the tidy library in-process, saving the overhead of spawning a new process.

Currently written to the PHP 4.3.x version of the extension, may not work on PHP 5.

'pear install tidy' should be able to compile the extension module.

Definition at line 817 of file Parser.php.

820 {
821 global $wgTidyConf;
822 $fname = 'Parser::internalTidy';
823 wfProfileIn($fname);
824
825 tidy_load_config($wgTidyConf);
826 tidy_set_encoding('utf8');
827 tidy_parse_string($text);
828 tidy_clean_repair();
829 if (tidy_get_status() == 2) {
830 // 2 is magic number for fatal error
831 // http://www.php.net/manual/en/function.tidy-get-status.php
832 $cleansource = null;
833 } else {
834 $cleansource = tidy_get_output();
835 }
836 wfProfileOut($fname);

◆ interwikiTransclude()

Parser::interwikiTransclude (   $title,
  $action 
)

Transclude an interwiki link.

Definition at line 3443 of file Parser.php.

3446 {
3447 global $wgEnableScaryTranscluding;
3448
3449 if (!$wgEnableScaryTranscluding) {
3450 return wfMsg('scarytranscludedisabled');
3451 }
3452
3453 $url = $title->getFullUrl("action=$action");
3454
3455 if (strlen($url) > 255) {
3456 return wfMsg('scarytranscludetoolong');
3457 }

◆ magicLinkCallback()

Parser::magicLinkCallback (   $m)

Definition at line 1112 of file Parser.php.

1115 {
1116 if (substr($m[0], 0, 1) == '<') {
1117 # Skip HTML element
1118 return $m[0];
1119 } elseif (substr($m[0], 0, 4) == 'ISBN') {
1120 $isbn = $m[2];
1121 $num = strtr($isbn, array(
1122 '-' => '',
1123 ' ' => '',
1124 'x' => 'X',
1125 ));
1126 $titleObj = SpecialPage::getTitleFor('Booksources');
1127 $text = '<a href="' .
1128 $titleObj->escapeLocalUrl("isbn=$num") .
1129 "\" class=\"internal\">ISBN $isbn</a>";
1130 } else {
1131 if (substr($m[0], 0, 3) == 'RFC') {
1132 $keyword = 'RFC';
1133 $urlmsg = 'rfcurl';
1134 $id = $m[1];
1135 } elseif (substr($m[0], 0, 4) == 'PMID') {
1136 $keyword = 'PMID';
1137 $urlmsg = 'pubmedurl';
1138 $id = $m[1];
1139 } else {
1140 throw new MWException(__METHOD__ . ': unrecognised match type "' .
1141 substr($m[0], 0, 20) . '"');
1142 }
1143
1144 $url = wfMsg($urlmsg, $id);
1145 $sk = $this->mOptions->getSkin();
1146 $la = $sk->getExternalLinkAttributes($url, $keyword . $id);
1147 $text = "<a href=\"{$url}\"{$la}>{$keyword} {$id}</a>";
1148 }

◆ makeImage()

Parser::makeImage (   $nt,
  $options 
)

Parse image options text and use it to make an image.

Definition at line 4598 of file Parser.php.

4601 {
4602 # @TODO: let the MediaHandler specify its transform parameters
4603 #
4604 # Check if the options text is of the form "options|alt text"
4605 # Options are:
4606 # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
4607 # * left no resizing, just left align. label is used for alt= only
4608 # * right same, but right aligned
4609 # * none same, but not aligned
4610 # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
4611 # * center center the image
4612 # * framed Keep original image size, no magnify-button.
4613 # vertical-align values (no % or length right now):
4614 # * baseline
4615 # * sub
4616 # * super
4617 # * top
4618 # * text-top
4619 # * middle
4620 # * bottom
4621 # * text-bottom
4622
4623
4624 $part = array_map('trim', explode('|', $options));
4625
4626 $mwAlign = array();
4627 $alignments = array( 'left', 'right', 'center', 'none', 'baseline', 'sub', 'super', 'top', 'text-top', 'middle', 'bottom', 'text-bottom' );
4628 foreach ($alignments as $alignment) {
4629 $mwAlign[$alignment] = &MagicWord::get('img_' . $alignment);
4630 }
4631 $mwThumb = &MagicWord::get('img_thumbnail');
4632 $mwManualThumb = &MagicWord::get('img_manualthumb');
4633 $mwWidth = &MagicWord::get('img_width');
4634 $mwFramed = &MagicWord::get('img_framed');
4635 $mwPage = &MagicWord::get('img_page');
4636 $caption = '';
4637
4638 $params = array();
4639 $framed = $thumb = false;
4640 $manual_thumb = '' ;
4641 $align = $valign = '';
4642 $sk = $this->mOptions->getSkin();
4643
4644 foreach ($part as $val) {
4645 if (!is_null($mwThumb->matchVariableStartToEnd($val))) {
4646 $thumb = true;
4647 } elseif (!is_null($match = $mwManualThumb->matchVariableStartToEnd($val))) {
4648 # use manually specified thumbnail
4649 $thumb = true;
4650 $manual_thumb = $match;
4651 } else {
4652 foreach ($alignments as $alignment) {
4653 if (!is_null($mwAlign[$alignment]->matchVariableStartToEnd($val))) {
4654 switch ($alignment) {
4655 case 'left': case 'right': case 'center': case 'none':
4656 $align = $alignment; break;
4657 default:
4658 $valign = $alignment;
4659 }
4660 continue 2;
4661 }
4662 }
4663 if (!is_null($match = $mwPage->matchVariableStartToEnd($val))) {
4664 # Select a page in a multipage document
4665 $params['page'] = $match;
4666 } elseif (!isset($params['width']) && !is_null($match = $mwWidth->matchVariableStartToEnd($val))) {
4667 wfDebug("img_width match: $match\n");
4668 # $match is the image width in pixels
4669 $m = array();
4670 if (preg_match('/^([0-9]*)x([0-9]*)$/', $match, $m)) {
4671 $params['width'] = intval($m[1]);
4672 $params['height'] = intval($m[2]);
4673 } else {
4674 $params['width'] = intval($match);
4675 }
4676 } elseif (!is_null($mwFramed->matchVariableStartToEnd($val))) {
4677 $framed = true;
4678 } else {
4679 $caption = $val;
4680 }
4681 }
4682 }
4683 # Strip bad stuff out of the alt text
4684 $alt = $this->replaceLinkHoldersText($caption);
4685
4686 # make sure there are no placeholders in thumbnail attributes
4687 # that are later expanded to html- so expand them now and
4688 # remove the tags
4689 $alt = $this->mStripState->unstripBoth($alt);
4690 $alt = Sanitizer::stripAllTags($alt);
4691
4692 # Linker does the rest
replaceLinkHoldersText($text)
Replace link placeholders with plain text of links (not HTML-formatted).
Definition: Parser.php:4470
static stripAllTags($text)
Take a fragment of (potentially invalid) HTML and return a version with any tags removed,...
Definition: Sanitizer.php:1255

◆ makeKnownLinkHolder()

Parser::makeKnownLinkHolder (   $nt,
  $text = '',
  $query = '',
  $trail = '',
  $prefix = '' 
)

Render a forced-blue link inline; protect against double expansion of URLs if we're in a mode that prepends full URL prefixes to internal links.

Since this little disaster has to split off the trail text to avoid breaking URLs in the following text without breaking trails on the wiki links, it's been made into a horrible function.

Parameters
Title$nt
string$text
string$query
string$trail
string$prefix
Returns
string HTML-wikitext mix oh yuck

Definition at line 1957 of file Parser.php.

1960 {
1961 list($inside, $trail) = Linker::splitTrail($trail);
1962 $sk = $this->mOptions->getSkin();
1963 $link = $sk->makeKnownLinkObj($nt, $text, $query, $inside, $prefix);
$query

◆ makeLinkHolder()

Parser::makeLinkHolder ( $nt,
  $text = '',
  $query = '',
  $trail = '',
  $prefix = '' 
)

Make a link placeholder.

The text returned can be later resolved to a real link with replaceLinkHolders(). This is done for two reasons: firstly to avoid further parsing of interwiki links, and secondly to allow all existence checks and article length checks (for stub links) to be bundled into a single query.

Definition at line 1915 of file Parser.php.

1918 {
1919 wfProfileIn(__METHOD__);
1920 if (!is_object($nt)) {
1921 # Fail gracefully
1922 $retVal = "<!-- ERROR -->{$prefix}{$text}{$trail}";
1923 } else {
1924 # Separate the link trail from the rest of the link
1925 list($inside, $trail) = Linker::splitTrail($trail);
1926
1927 if ($nt->isExternal()) {
1928 $nr = array_push($this->mInterwikiLinkHolders['texts'], $prefix . $text . $inside);
1929 $this->mInterwikiLinkHolders['titles'][] = $nt;
1930 $retVal = '<!--IWLINK ' . ($nr - 1) . "-->{$trail}";
1931 } else {
1932 $nr = array_push($this->mLinkHolders['namespaces'], $nt->getNamespace());
1933 $this->mLinkHolders['dbkeys'][] = $nt->getDBkey();
1934 $this->mLinkHolders['queries'][] = $query;
1935 $this->mLinkHolders['texts'][] = $prefix . $text . $inside;
1936 $this->mLinkHolders['titles'][] = $nt;
1937
1938 $retVal = '<!--LINK ' . ($nr - 1) . "-->{$trail}";
1939 }
1940 }
1941 wfProfileOut(__METHOD__);

◆ maybeDoSubpageLink()

Parser::maybeDoSubpageLink (   $target,
$text 
)

Handle link to subpage if necessary.

Parameters
string$targetthe source of the link
string&$textthe link text, modified as necessary
Returns
string the full name of the link

Definition at line 2004 of file Parser.php.

2007 {
2008 # Valid link forms:
2009 # Foobar -- normal
2010 # :Foobar -- override special treatment of prefix (images, language links)
2011 # /Foobar -- convert to CurrentPage/Foobar
2012 # /Foobar/ -- convert to CurrentPage/Foobar, strip the initial / from text
2013 # ../ -- convert to CurrentPage, from CurrentPage/CurrentSubPage
2014 # ../Foobar -- convert to CurrentPage/Foobar, from CurrentPage/CurrentSubPage
2015
2016 $fname = 'Parser::maybeDoSubpageLink';
2017 wfProfileIn($fname);
2018 $ret = $target; # default return value is no change
2019
2020 # bug 7425
2021 $target = trim($target);
2022
2023 # Some namespaces don't allow subpages,
2024 # so only perform processing if subpages are allowed
2025 if ($this->areSubpagesAllowed()) {
2026 # Look at the first character
2027 if ($target != '' && $target[0] == '/') {
2028 # / at end means we don't want the slash to be shown
2029 $trailingSlashes = preg_match_all('%(/+)$%', $target, $m);
2030 if ($trailingSlashes) {
2031 $noslash = $target = substr($target, 1, -strlen($m[0][0]));
2032 } else {
2033 $noslash = substr($target, 1);
2034 }
2035
2036 $ret = $this->mTitle->getPrefixedText() . '/' . trim($noslash);
2037 if ('' === $text) {
2038 $text = $target;
2039 } # this might be changed for ugliness reasons
2040 } else {
2041 # check for .. subpage backlinks
2042 $dotdotcount = 0;
2043 $nodotdot = $target;
2044 while (strncmp($nodotdot, "../", 3) == 0) {
2045 ++$dotdotcount;
2046 $nodotdot = substr($nodotdot, 3);
2047 }
2048 if ($dotdotcount > 0) {
2049 $exploded = explode('/', $this->mTitle->GetPrefixedText());
2050 if (count($exploded) > $dotdotcount) { # not allowed to go below top level page
2051 $ret = implode('/', array_slice($exploded, 0, -$dotdotcount));
2052 # / at the end means don't show full path
2053 if (substr($nodotdot, -1, 1) == '/') {
2054 $nodotdot = substr($nodotdot, 0, -1);
2055 if ('' === $text) {
2056 $text = $nodotdot;
2057 }
2058 }
2059 $nodotdot = trim($nodotdot);
2060 if ($nodotdot != '') {
2061 $ret .= '/' . $nodotdot;
2062 }
2063 }
2064 }
2065 }
2066 }
2067
2068 wfProfileOut($fname);
areSubpagesAllowed()
Return true if subpage links should be expanded on this page.
Definition: Parser.php:1990

◆ maybeMakeExternalImage()

Parser::maybeMakeExternalImage (   $url)

make an image if it's allowed, either through the global option or through the exception

Reimplemented in ilMWParserAdapter.

Definition at line 1589 of file Parser.php.

1592 {
1593 $sk = $this->mOptions->getSkin();
1594 $imagesfrom = $this->mOptions->getAllowExternalImagesFrom();
1595 $imagesexception = !empty($imagesfrom);
1596 $text = false;
1597 if ($this->mOptions->getAllowExternalImages()
1598 || ($imagesexception && strpos($url, $imagesfrom) === 0)) {
1599 if (preg_match(EXT_IMAGE_REGEX, $url)) {
1600 # Image found
1601 $text = $sk->makeExternalImage(htmlspecialchars($url));
1602 }
1603 }
const EXT_IMAGE_REGEX
Definition: Parser.php:42

◆ nextItem()

Parser::nextItem (   $char)

Definition at line 2125 of file Parser.php.

2128 {
2129 if ('*' == $char || '#' == $char) {
2130 return '</li><li>';
2131 } elseif (':' == $char || ';' == $char) {
2132 $close = '</dd>';
2133 if ($this->mDTopen) {
2134 $close = '</dt>';
2135 }
2136 if (';' == $char) {
2137 $this->mDTopen = true;
2138 return $close . '<dt>';
2139 } else {
2140 $this->mDTopen = false;
2141 return $close . '<dd>';
2142 }
2143 }

◆ openList()

Parser::openList (   $char)

Definition at line 2105 of file Parser.php.

2108 {
2109 $result = $this->closeParagraph();
2110
2111 if ('*' == $char) {
2112 $result .= '<ul><li>';
2113 } elseif ('#' == $char) {
2114 $result .= '<ol><li>';
2115 } elseif (':' == $char) {
2116 $result .= '<dl><dd>';
2117 } elseif (';' == $char) {
2118 $result .= '<dl><dt>';
2119 $this->mDTopen = true;
2120 } else {
2121 $result = '<!-- ERR 1 -->';
2122 }
2123

References $result.

◆ Options()

Parser::Options (   $x = null)

Definition at line 4728 of file Parser.php.

4731 {

◆ OutputType()

Parser::OutputType (   $x = null)

Definition at line 4732 of file Parser.php.

4735 {

◆ parse()

Parser::parse (   $text,
$title,
  $options,
  $linestart = true,
  $clearState = true,
  $revid = null 
)

Convert wikitext to HTML Do not call this function recursively.

Parameters
string$textText we want to parse
Title&$titleA title object
array$options
boolean$linestart
boolean$clearState
int$revidnumber to pass in {{REVISIONID}}
Returns
ParserOutput a ParserOutput

First pass–just handle <nowiki> sections, pass the rest off to internalParse() which does all the real work.

Definition at line 298 of file Parser.php.

301 {
307 global $wgUseTidy, $wgAlwaysUseTidy, $wgContLang;
308 $fname = 'Parser::parse-' . wfGetCaller();
309 wfProfileIn(__METHOD__);
310 wfProfileIn($fname);
311
312 if ($clearState) {
313 $this->clearState();
314 }
315
316 $this->mOptions = $options;
317 $this->mTitle = &$title;
318 $oldRevisionId = $this->mRevisionId;
319 $oldRevisionTimestamp = $this->mRevisionTimestamp;
320 if ($revid !== null) {
321 $this->mRevisionId = $revid;
322 $this->mRevisionTimestamp = null;
323 }
324 $this->setOutputType(OT_HTML);
325 wfRunHooks('ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ));
326 $text = $this->strip($text, $this->mStripState);
327 wfRunHooks('ParserAfterStrip', array( &$this, &$text, &$this->mStripState ));
328 $text = $this->internalParse($text);
329 $text = $this->mStripState->unstripGeneral($text);
330
331 # Clean up special characters, only run once, next-to-last before doBlockLevels
332 $fixtags = array(
333 # french spaces, last one Guillemet-left
334 # only if there is something before the space
335 '/(.) (?=\\?|:|;|!|\\302\\273)/' => '\\1&nbsp;\\2',
336 # french spaces, Guillemet-right
337 '/(\\302\\253) /' => '\\1&nbsp;',
338 );
339 $text = preg_replace(array_keys($fixtags), array_values($fixtags), $text);
340
341 # only once and last
342 $text = $this->doBlockLevels($text, $linestart);
343
344 $this->replaceLinkHolders($text);
345
346 # the position of the parserConvert() call should not be changed. it
347 # assumes that the links are all replaced and the only thing left
348 # is the <nowiki> mark.
349 # Side-effects: this calls $this->mOutput->setTitleText()
350 $text = $wgContLang->parserConvert($text, $this);
351
352 $text = $this->mStripState->unstripNoWiki($text);
353
354 wfRunHooks('ParserBeforeTidy', array( &$this, &$text ));
355
357
358 if (($wgUseTidy and $this->mOptions->mTidy) or $wgAlwaysUseTidy) {
359 $text = Parser::tidy($text);
360 } else {
361 # attempt to sanitize at least some nesting problems
362 # (bug #2702 and quite a few others)
363 $tidyregs = array(
364 # ''Something [http://www.cool.com cool''] -->
365 # <i>Something</i><a href="http://www.cool.com"..><i>cool></i></a>
366 '/(<([bi])>)(<([bi])>)?([^<]*)(<\/?a[^<]*>)([^<]*)(<\/\\4>)?(<\/\\2>)/' =>
367 '\\1\\3\\5\\8\\9\\6\\1\\3\\7\\8\\9',
368 # fix up an anchor inside another anchor, only
369 # at least for a single single nested link (bug 3695)
370 '/(<a[^>]+>)([^<]*)(<a[^>]+>[^<]*)<\/a>(.*)<\/a>/' =>
371 '\\1\\2</a>\\3</a>\\1\\4</a>',
372 # fix div inside inline elements- doBlockLevels won't wrap a line which
373 # contains a div, so fix it up here; replace
374 # div with escaped text
375 '/(<([aib]) [^>]+>)([^<]*)(<div([^>]*)>)(.*)(<\/div>)([^<]*)(<\/\\2>)/' =>
376 '\\1\\3&lt;div\\5&gt;\\6&lt;/div&gt;\\8\\9',
377 # remove empty italic or bold tag pairs, some
378 # introduced by rules above
379 '/<([bi])><\/\\1>/' => '',
380 );
381
382 $text = preg_replace(
383 array_keys($tidyregs),
384 array_values($tidyregs),
385 $text
386 );
387 }
388
389 wfRunHooks('ParserAfterTidy', array( &$this, &$text ));
390
391 # Information on include size limits, for the benefit of users who try to skirt them
392 if (max($this->mIncludeSizes) > 1000) {
393 $max = $this->mOptions->getMaxIncludeSize();
394 $text .= "<!-- \n" .
395 "Pre-expand include size: {$this->mIncludeSizes['pre-expand']} bytes\n" .
396 "Post-expand include size: {$this->mIncludeSizes['post-expand']} bytes\n" .
397 "Template argument size: {$this->mIncludeSizes['arg']} bytes\n" .
398 "Maximum: $max bytes\n" .
399 "-->\n";
400 }
401 $this->mOutput->setText($text);
402 $this->mRevisionId = $oldRevisionId;
403 $this->mRevisionTimestamp = $oldRevisionTimestamp;
404 wfProfileOut($fname);
405 wfProfileOut(__METHOD__);
406
$mRevisionTimestamp
Definition: Parser.php:134
internalParse($text)
Helper function for parse() that transforms wiki markup into HTML.
Definition: Parser.php:1032
tidy($text)
Interface with html tidy, used if $wgUseTidy = true.
Definition: Parser.php:741
doBlockLevels($text, $linestart)
#-
Definition: Parser.php:2171
replaceLinkHolders(&$text, $options=0)
Replace link placeholders with actual links, in the buffer Placeholders created in Skin::makeLinkObj(...
Definition: Parser.php:4164
static normalizeCharReferences($text)
Ensure that any entities and character references are legal for XML and XHTML specifically.
Definition: Sanitizer.php:921
expand()
Definition: expand.php:2
static http()
Fetches the global http state from ILIAS.
up()
Definition: up.php:2

◆ preprocess()

Parser::preprocess (   $text,
  $title,
  $options 
)

Expand templates and variables in the text, producing valid, static wikitext.

Also removes comments.

Definition at line 427 of file Parser.php.

430 {
431 wfProfileIn(__METHOD__);
432 $this->clearState();
434 $this->mOptions = $options;
435 $this->mTitle = $title;
436 wfRunHooks('ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ));
437 $text = $this->strip($text, $this->mStripState);
438 wfRunHooks('ParserAfterStrip', array( &$this, &$text, &$this->mStripState ));
439 if ($this->mOptions->getRemoveComments()) {
440 $text = Sanitizer::removeHTMLcomments($text);
441 }
442 $text = $this->replaceVariables($text);
443 $text = $this->mStripState->unstripBoth($text);
444 wfProfileOut(__METHOD__);

◆ preSaveTransform()

Parser::preSaveTransform (   $text,
$title,
  $user,
  $options,
  $clearState = true 
)

Transform wiki markup when saving a page by doing \r
->
conversion, substitting signatures, {{subst:}} templates, etc.

Parameters
string$textthe text to transform
Title&$titlethe Title object for the current article
User&$userthe User object describing the current user
ParserOptions$optionsparsing options
bool$clearStatewhether to clear the parser state first
Returns
string the altered wiki markup

Definition at line 3839 of file Parser.php.

3842 {
3843 $this->mOptions = $options;
3844 $this->mTitle = &$title;
3845 $this->setOutputType(OT_WIKI);
3846
3847 if ($clearState) {
3848 $this->clearState();
3849 }
3850
3851 $stripState = new StripState;
3852 $pairs = array(
3853 "\r\n" => "\n",
3854 );
3855 $text = str_replace(array_keys($pairs), array_values($pairs), $text);
3856 $text = $this->strip($text, $stripState, true, array( 'gallery' ));
3857 $text = $this->pstPass2($text, $stripState, $user);
3858 $text = $stripState->unstripBoth($text);
pstPass2($text, &$stripState, $user)
Pre-save transform helper function.
Definition: Parser.php:3864

◆ pstPass2()

Parser::pstPass2 (   $text,
$stripState,
  $user 
)

Pre-save transform helper function.

Definition at line 3864 of file Parser.php.

3867 {
3868 global $wgContLang, $wgLocaltimezone;
3869
3870 /* Note: This is the timestamp saved as hardcoded wikitext to
3871 * the database, we use $wgContLang here in order to give
3872 * everyone the same signature and use the default one rather
3873 * than the one selected in each user's preferences.
3874 */
3875 if (isset($wgLocaltimezone)) {
3876 $oldtz = getenv('TZ');
3877 putenv('TZ=' . $wgLocaltimezone);
3878 }
3879 $d = $wgContLang->timeanddate(date('YmdHis'), false, false) .
3880 ' (' . date('T') . ')';
3881 if (isset($wgLocaltimezone)) {
3882 putenv('TZ=' . $oldtz);
3883 }
3884
3885 # Variable replacement
3886 # Because mOutputType is OT_WIKI, this will only process {{subst:xxx}} type tags
3887 $text = $this->replaceVariables($text);
3888
3889 # Strip out <nowiki> etc. added via replaceVariables
3890 $text = $this->strip($text, $stripState, false, array( 'gallery' ));
3891
3892 # Signatures
3893 $sigText = $this->getUserSig($user);
3894 $text = strtr($text, array(
3895 '~~~~~' => $d,
3896 '~~~~' => "$sigText $d",
3897 '~~~' => $sigText
3898 ));
3899
3900 # Context links: [[|name]] and [[name (context)|]]
3901 #
3902 global $wgLegalTitleChars;
3903 $tc = "[$wgLegalTitleChars]";
3904 $nc = '[ _0-9A-Za-z\x80-\xff]'; # Namespaces can use non-ascii!
3905
3906 $p1 = "/\[\[(:?$nc+:|:|)($tc+?)( \\($tc+\\))\\|]]/"; # [[ns:page (context)|]]
3907 $p3 = "/\[\[(:?$nc+:|:|)($tc+?)( \\($tc+\\)|)(, $tc+|)\\|]]/"; # [[ns:page (context), context|]]
3908 $p2 = "/\[\[\\|($tc+)]]/"; # [[|page]]
3909
3910 # try $p1 first, to turn "[[A, B (C)|]]" into "[[A, B (C)|A, B]]"
3911 $text = preg_replace($p1, '[[\\1\\2\\3|\\2]]', $text);
3912 $text = preg_replace($p3, '[[\\1\\2\\3\\4|\\2]]', $text);
3913
3914 $t = $this->mTitle->getText();
3915 $m = array();
3916 if (preg_match("/^($nc+:|)$tc+?( \\($tc+\\))$/", $t, $m)) {
3917 $text = preg_replace($p2, "[[$m[1]\\1$m[2]|\\1]]", $text);
3918 } elseif (preg_match("/^($nc+:|)$tc+?(, $tc+|)$/", $t, $m) && '' != "$m[1]$m[2]") {
3919 $text = preg_replace($p2, "[[$m[1]\\1$m[2]|\\1]]", $text);
3920 } else {
3921 # if there's no context, don't bother duplicating the title
3922 $text = preg_replace($p2, '[[\\1]]', $text);
3923 }
3924
3925 # Trim trailing whitespace
3926 $text = rtrim($text);
3927
getUserSig(&$user)
Fetch the user's signature text, if any, and normalize to validated, ready-to-insert wikitext.
Definition: Parser.php:3937
for( $i=6;$i< 13;$i++) for($i=1; $i< 13; $i++) $d
Definition: date.php:296

◆ recursiveTagParse()

Parser::recursiveTagParse (   $text)

Recursive parser entry point that can be called from an extension tag hook.

Definition at line 412 of file Parser.php.

415 {
416 wfProfileIn(__METHOD__);
417 wfRunHooks('ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ));
418 $text = $this->strip($text, $this->mStripState);
419 wfRunHooks('ParserAfterStrip', array( &$this, &$text, &$this->mStripState ));
420 $text = $this->internalParse($text);
421 wfProfileOut(__METHOD__);

◆ renderImageGallery()

Parser::renderImageGallery (   $text,
  $params 
)

Renders an image gallery from a text with one line per image.

text labels may be given by using |-style alternative text. E.g. Image:one.jpg|The number "1" Image:tree.jpg|A tree given as text will return the HTML of a gallery with two images, labeled 'The number "1"' and 'A tree'.

Definition at line 4529 of file Parser.php.

4532 {
4533 $ig = new ImageGallery();
4534 $ig->setContextTitle($this->mTitle);
4535 $ig->setShowBytes(false);
4536 $ig->setShowFilename(false);
4537 $ig->setParsing();
4538 $ig->useSkin($this->mOptions->getSkin());
4539
4540 if (isset($params['caption'])) {
4541 $caption = $params['caption'];
4542 $caption = htmlspecialchars($caption);
4543 $caption = $this->replaceInternalLinks($caption);
4544 $ig->setCaptionHtml($caption);
4545 }
4546 if (isset($params['perrow'])) {
4547 $ig->setPerRow($params['perrow']);
4548 }
4549 if (isset($params['widths'])) {
4550 $ig->setWidths($params['widths']);
4551 }
4552 if (isset($params['heights'])) {
4553 $ig->setHeights($params['heights']);
4554 }
4555
4556 $lines = explode("\n", $text);
4557 foreach ($lines as $line) {
4558 # match lines like these:
4559 # Image:someimage.jpg|This is some image
4560 $matches = array();
4561 preg_match("/^([^|]+)(\\|(.*))?$/", $line, $matches);
4562 # Skip empty lines
4563 if (count($matches) == 0) {
4564 continue;
4565 }
4566 $tp = Title::newFromText($matches[1]);
4567 $nt = &$tp;
4568 if (is_null($nt)) {
4569 # Bogus title. Ignore these so we don't bomb out later.
4570 continue;
4571 }
4572 if (isset($matches[3])) {
4573 $label = $matches[3];
4574 } else {
4575 $label = '';
4576 }
4577
4578 $pout = $this->parse(
4579 $label,
4580 $this->mTitle,
4581 $this->mOptions,
4582 false, // Strip whitespace...?
4583 false // Don't clear state!
4584 );
4585 $html = $pout->getText();
4586
4587 $ig->add(new Image($nt), $html);
4588
4589 # Only add real images (bug #5586)
4590 if ($nt->getNamespace() == NS_IMAGE) {
4591 $this->mOutput->addImage($nt->getDBkey());
4592 }
4593 }
parse($text, &$title, $options, $linestart=true, $clearState=true, $revid=null)
Convert wikitext to HTML Do not call this function recursively.
Definition: Parser.php:298

◆ renderPreTag()

Parser::renderPreTag (   $text,
  $attribs 
)

Tag hook handler for 'pre'.

Definition at line 4509 of file Parser.php.

4512 {
4513 // Backwards-compatibility hack
4514 $content = StringUtils::delimiterReplace('<nowiki>', '</nowiki>', '$1', $text, 'i');
4515
4516 $attribs = Sanitizer::validateTagAttributes($attribs, 'pre');
4517 return wfOpenElement('pre', $attribs) .
4518 Xml::escapeTagsOnly($content) .
static validateTagAttributes($attribs, $element)
Take an array of attribute names and values and normalize or discard illegal values for the given ele...
Definition: Sanitizer.php:583

◆ replace_callback()

Parser::replace_callback (   $text,
  $callbacks 
)

parse any parentheses in format ((title|part|part)) and call callbacks to get a replacement text for any found piece

Parameters
string$textThe text to parse
array$callbacksrules in form: '{' => array( # opening parentheses 'end' => '}', # closing parentheses 'cb' => array(2 => callback, # replacement callback to call if {{..}} is found 3 => callback # replacement callback to call if {{{..}}} is found ) ) 'min' => 2, # Minimum parenthesis count in cb 'max' => 3, # Maximum parenthesis count in cb

Definition at line 2734 of file Parser.php.

2737 {
2738 wfProfileIn(__METHOD__);
2739 $openingBraceStack = array(); # this array will hold a stack of parentheses which are not closed yet
2740 $lastOpeningBrace = -1; # last not closed parentheses
2741
2742 $validOpeningBraces = implode('', array_keys($callbacks));
2743
2744 $i = 0;
2745 while ($i < strlen($text)) {
2746 # Find next opening brace, closing brace or pipe
2747 if ($lastOpeningBrace == -1) {
2748 $currentClosing = '';
2749 $search = $validOpeningBraces;
2750 } else {
2751 $currentClosing = $openingBraceStack[$lastOpeningBrace]['braceEnd'];
2752 $search = $validOpeningBraces . '|' . $currentClosing;
2753 }
2754 $rule = null;
2755 $i += strcspn($text, $search, $i);
2756 if ($i < strlen($text)) {
2757 if ($text[$i] == '|') {
2758 $found = 'pipe';
2759 } elseif ($text[$i] == $currentClosing) {
2760 $found = 'close';
2761 } elseif (isset($callbacks[$text[$i]])) {
2762 $found = 'open';
2763 $rule = $callbacks[$text[$i]];
2764 } else {
2765 # Some versions of PHP have a strcspn which stops on null characters
2766 # Ignore and continue
2767 ++$i;
2768 continue;
2769 }
2770 } else {
2771 # All done
2772 break;
2773 }
2774
2775 if ($found == 'open') {
2776 # found opening brace, let's add it to parentheses stack
2777 $piece = array('brace' => $text[$i],
2778 'braceEnd' => $rule['end'],
2779 'title' => '',
2780 'parts' => null);
2781
2782 # count opening brace characters
2783 $piece['count'] = strspn($text, $piece['brace'], $i);
2784 $piece['startAt'] = $piece['partStart'] = $i + $piece['count'];
2785 $i += $piece['count'];
2786
2787 # we need to add to stack only if opening brace count is enough for one of the rules
2788 if ($piece['count'] >= $rule['min']) {
2789 $lastOpeningBrace++;
2790 $openingBraceStack[$lastOpeningBrace] = $piece;
2791 }
2792 } elseif ($found == 'close') {
2793 # lets check if it is enough characters for closing brace
2794 $maxCount = $openingBraceStack[$lastOpeningBrace]['count'];
2795 $count = strspn($text, $text[$i], $i, $maxCount);
2796
2797 # check for maximum matching characters (if there are 5 closing
2798 # characters, we will probably need only 3 - depending on the rules)
2799 $matchingCount = 0;
2800 $matchingCallback = null;
2801 $cbType = $callbacks[$openingBraceStack[$lastOpeningBrace]['brace']];
2802 if ($count > $cbType['max']) {
2803 # The specified maximum exists in the callback array, unless the caller
2804 # has made an error
2805 $matchingCount = $cbType['max'];
2806 } else {
2807 # Count is less than the maximum
2808 # Skip any gaps in the callback array to find the true largest match
2809 # Need to use array_key_exists not isset because the callback can be null
2810 $matchingCount = $count;
2811 while ($matchingCount > 0 && !array_key_exists($matchingCount, $cbType['cb'])) {
2812 --$matchingCount;
2813 }
2814 }
2815
2816 if ($matchingCount <= 0) {
2817 $i += $count;
2818 continue;
2819 }
2820 $matchingCallback = $cbType['cb'][$matchingCount];
2821
2822 # let's set a title or last part (if '|' was found)
2823 if (null === $openingBraceStack[$lastOpeningBrace]['parts']) {
2824 $openingBraceStack[$lastOpeningBrace]['title'] =
2825 substr(
2826 $text,
2827 $openingBraceStack[$lastOpeningBrace]['partStart'],
2828 $i - $openingBraceStack[$lastOpeningBrace]['partStart']
2829 );
2830 } else {
2831 $openingBraceStack[$lastOpeningBrace]['parts'][] =
2832 substr(
2833 $text,
2834 $openingBraceStack[$lastOpeningBrace]['partStart'],
2835 $i - $openingBraceStack[$lastOpeningBrace]['partStart']
2836 );
2837 }
2838
2839 $pieceStart = $openingBraceStack[$lastOpeningBrace]['startAt'] - $matchingCount;
2840 $pieceEnd = $i + $matchingCount;
2841
2842 if (is_callable($matchingCallback)) {
2843 $cbArgs = array(
2844 'text' => substr($text, $pieceStart, $pieceEnd - $pieceStart),
2845 'title' => trim($openingBraceStack[$lastOpeningBrace]['title']),
2846 'parts' => $openingBraceStack[$lastOpeningBrace]['parts'],
2847 'lineStart' => (($pieceStart > 0) && ($text[$pieceStart - 1] == "\n")),
2848 );
2849 # finally we can call a user callback and replace piece of text
2850 $replaceWith = call_user_func($matchingCallback, $cbArgs);
2851 $text = substr($text, 0, $pieceStart) . $replaceWith . substr($text, $pieceEnd);
2852 $i = $pieceStart + strlen($replaceWith);
2853 } else {
2854 # null value for callback means that parentheses should be parsed, but not replaced
2855 $i += $matchingCount;
2856 }
2857
2858 # reset last opening parentheses, but keep it in case there are unused characters
2859 $piece = array('brace' => $openingBraceStack[$lastOpeningBrace]['brace'],
2860 'braceEnd' => $openingBraceStack[$lastOpeningBrace]['braceEnd'],
2861 'count' => $openingBraceStack[$lastOpeningBrace]['count'],
2862 'title' => '',
2863 'parts' => null,
2864 'startAt' => $openingBraceStack[$lastOpeningBrace]['startAt']);
2865 $openingBraceStack[$lastOpeningBrace--] = null;
2866
2867 if ($matchingCount < $piece['count']) {
2868 $piece['count'] -= $matchingCount;
2869 $piece['startAt'] -= $matchingCount;
2870 $piece['partStart'] = $piece['startAt'];
2871 # do we still qualify for any callback with remaining count?
2872 $currentCbList = $callbacks[$piece['brace']]['cb'];
2873 while ($piece['count']) {
2874 if (array_key_exists($piece['count'], $currentCbList)) {
2875 $lastOpeningBrace++;
2876 $openingBraceStack[$lastOpeningBrace] = $piece;
2877 break;
2878 }
2879 --$piece['count'];
2880 }
2881 }
2882 } elseif ($found == 'pipe') {
2883 # lets set a title if it is a first separator, or next part otherwise
2884 if (null === $openingBraceStack[$lastOpeningBrace]['parts']) {
2885 $openingBraceStack[$lastOpeningBrace]['title'] =
2886 substr(
2887 $text,
2888 $openingBraceStack[$lastOpeningBrace]['partStart'],
2889 $i - $openingBraceStack[$lastOpeningBrace]['partStart']
2890 );
2891 $openingBraceStack[$lastOpeningBrace]['parts'] = array();
2892 } else {
2893 $openingBraceStack[$lastOpeningBrace]['parts'][] =
2894 substr(
2895 $text,
2896 $openingBraceStack[$lastOpeningBrace]['partStart'],
2897 $i - $openingBraceStack[$lastOpeningBrace]['partStart']
2898 );
2899 }
2900 $openingBraceStack[$lastOpeningBrace]['partStart'] = ++$i;
2901 }
2902 }
2903
2904 wfProfileOut(__METHOD__);

◆ replaceExternalLinks()

Parser::replaceExternalLinks (   $text)

Replace external links.

Note: this is all very hackish and the order of execution matters a lot. Make sure to run maintenance/parserTests.php if you change this code.

Definition at line 1380 of file Parser.php.

1383 {
1384 global $wgContLang;
1385 $fname = 'Parser::replaceExternalLinks';
1386 wfProfileIn($fname);
1387
1388 $sk = $this->mOptions->getSkin();
1389
1390 $bits = preg_split(EXT_LINK_BRACKETED, $text, -1, PREG_SPLIT_DELIM_CAPTURE);
1391
1392 $s = $this->replaceFreeExternalLinks(array_shift($bits));
1393
1394 $i = 0;
1395 while ($i < count($bits)) {
1396 $url = $bits[$i++];
1397 $protocol = $bits[$i++];
1398 $text = $bits[$i++];
1399 $trail = $bits[$i++];
1400
1401 # The characters '<' and '>' (which were escaped by
1402 # removeHTMLtags()) should not be included in
1403 # URLs, per RFC 2396.
1404 $m2 = array();
1405 if (preg_match('/&(lt|gt);/', $url, $m2, PREG_OFFSET_CAPTURE)) {
1406 $text = substr($url, $m2[0][1]) . ' ' . $text;
1407 $url = substr($url, 0, $m2[0][1]);
1408 }
1409
1410 # If the link text is an image URL, replace it with an <img> tag
1411 # This happened by accident in the original parser, but some people used it extensively
1412 $img = $this->maybeMakeExternalImage($text);
1413 if ($img !== false) {
1414 $text = $img;
1415 }
1416
1417 $dtrail = '';
1418
1419 # Set linktype for CSS - if URL==text, link is essentially free
1420 $linktype = ($text == $url) ? 'free' : 'text';
1421
1422 # No link text, e.g. [http://domain.tld/some.link]
1423 if ($text == '') {
1424 # Autonumber if allowed. See bug #5918
1425 if (strpos(wfUrlProtocols(), substr($protocol, 0, strpos($protocol, ':'))) !== false) {
1426 $text = '[' . ++$this->mAutonumber . ']';
1427 $linktype = 'autonumber';
1428 } else {
1429 # Otherwise just use the URL
1430 $text = htmlspecialchars($url);
1431 $linktype = 'free';
1432 }
1433 } else {
1434 # Have link text, e.g. [http://domain.tld/some.link text]s
1435 # Check for trail
1436 list($dtrail, $trail) = Linker::splitTrail($trail);
1437 }
1438
1439 $text = $wgContLang->markNoConversion($text);
1440
1442
1443 # Process the trail (i.e. everything after this link up until start of the next link),
1444 # replacing any non-bracketed links
1445 $trail = $this->replaceFreeExternalLinks($trail);
1446
1447 # Use the encoded URL
1448 # This means that users can paste URLs directly into the text
1449 # Funny characters like &ouml; aren't valid in URLs anyway
1450 # This was changed in August 2004
1451 $s .= $sk->makeExternalLink($url, $text, false, $linktype, $this->mTitle->getNamespace()) . $dtrail . $trail;
1452
1453 # Register link in the output object.
1454 # Replace unnecessary URL escape codes with the referenced character
1455 # This prevents spammers from hiding links from the filters
1456 $pasteurized = Parser::replaceUnusualEscapes($url);
1457 $this->mOutput->addExternalLink($pasteurized);
1458 }
1459
1460 wfProfileOut($fname);
const EXT_LINK_BRACKETED
Definition: Parser.php:40
maybeMakeExternalImage($url)
make an image if it's allowed, either through the global option or through the exception
Definition: Parser.php:1589
static replaceUnusualEscapes($url)
Replace unusual URL escape codes with their equivalent characters.
Definition: Parser.php:1554
replaceFreeExternalLinks($text)
Replace anything that looks like a URL with a link.
Definition: Parser.php:1466
static cleanUrl($url, $hostname=true)
Definition: Sanitizer.php:1288

◆ replaceFreeExternalLinks()

Parser::replaceFreeExternalLinks (   $text)

Replace anything that looks like a URL with a link.

Definition at line 1466 of file Parser.php.

1469 {
1470 global $wgContLang;
1471
1472 $fname = 'Parser::replaceFreeExternalLinks';
1473 wfProfileIn($fname);
1474
1475 $bits = preg_split('/(\b(?:' . wfUrlProtocols() . '))/S', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
1476 $s = array_shift($bits);
1477 $i = 0;
1478
1479 $sk = $this->mOptions->getSkin();
1480
1481 while ($i < count($bits)) {
1482 $protocol = $bits[$i++];
1483 $remainder = $bits[$i++];
1484
1485 $m = array();
1486 if (preg_match('/^(' . EXT_LINK_URL_CLASS . '+)(.*)$/s', $remainder, $m)) {
1487 # Found some characters after the protocol that look promising
1488 $url = $protocol . $m[1];
1489 $trail = $m[2];
1490
1491 # special case: handle urls as url args:
1492 # http://www.example.com/foo?=http://www.example.com/bar
1493 if (strlen($trail) == 0 &&
1494 isset($bits[$i]) &&
1495 preg_match('/^' . wfUrlProtocols() . '$/S', $bits[$i]) &&
1496 preg_match('/^(' . EXT_LINK_URL_CLASS . '+)(.*)$/s', $bits[$i + 1], $m)) {
1497 # add protocol, arg
1498 $url .= $bits[$i] . $m[1]; # protocol, url as arg to previous link
1499 $i += 2;
1500 $trail = $m[2];
1501 }
1502
1503 # The characters '<' and '>' (which were escaped by
1504 # removeHTMLtags()) should not be included in
1505 # URLs, per RFC 2396.
1506 $m2 = array();
1507 if (preg_match('/&(lt|gt);/', $url, $m2, PREG_OFFSET_CAPTURE)) {
1508 $trail = substr($url, $m2[0][1]) . $trail;
1509 $url = substr($url, 0, $m2[0][1]);
1510 }
1511
1512 # Move trailing punctuation to $trail
1513 $sep = ',;\.:!?';
1514 # If there is no left bracket, then consider right brackets fair game too
1515 if (strpos($url, '(') === false) {
1516 $sep .= ')';
1517 }
1518
1519 $numSepChars = strspn(strrev($url), $sep);
1520 if ($numSepChars) {
1521 $trail = substr($url, -$numSepChars) . $trail;
1522 $url = substr($url, 0, -$numSepChars);
1523 }
1524
1526 # Is this an external image?
1527 $text = $this->maybeMakeExternalImage($url);
1528 if ($text === false) {
1529 # Not an image, make a link
1530 $text = $sk->makeExternalLink($url, $wgContLang->markNoConversion($url), true, 'free', $this->mTitle->getNamespace());
1531 # Register it in the output object...
1532 # Replace unnecessary URL escape codes with their equivalent characters
1533 $pasteurized = Parser::replaceUnusualEscapes($url);
1534
1535 $this->mOutput->addExternalLink($pasteurized);
1536 }
1537 $s .= $text . $trail;
1538 } else {
1539 $s .= $protocol . $remainder;
1540 }
1541 }
1542 wfProfileOut($fname);
const EXT_LINK_URL_CLASS
Definition: Parser.php:35

◆ replaceInternalLinks()

Parser::replaceInternalLinks (   $s)

Process [[ ]] wikilinks.

Strip the whitespace Category links produce, see bug 87

Todo:
We might want to use trim($tmp, "\n") here.

Definition at line 1610 of file Parser.php.

1613 {
1614 global $wgContLang;
1615 static $fname = 'Parser::replaceInternalLinks' ;
1616
1617 wfProfileIn($fname);
1618
1619 wfProfileIn($fname . '-setup');
1620 static $tc = false;
1621 # the % is needed to support urlencoded titles as well
1622 if (!$tc) {
1623 $tc = Title::legalChars() . '#%';
1624 }
1625
1626 $sk = $this->mOptions->getSkin();
1627
1628 #split the entire text string on occurences of [[
1629 $a = explode('[[', ' ' . $s);
1630 #get the first element (all text up to first [[), and remove the space we added
1631 $s = array_shift($a);
1632 $s = substr($s, 1);
1633
1634 # Match a link having the form [[namespace:link|alternate]]trail
1635 static $e1 = false;
1636 if (!$e1) {
1637 $e1 = "/^([{$tc}]+)(?:\\|(.+?))?]](.*)\$/sD";
1638 }
1639 # Match cases where there is no "]]", which might still be images
1640 static $e1_img = false;
1641 if (!$e1_img) {
1642 $e1_img = "/^([{$tc}]+)\\|(.*)\$/sD";
1643 }
1644 # Match the end of a line for a word that's not followed by whitespace,
1645 # e.g. in the case of 'The Arab al[[Razi]]', 'al' will be matched
1646 $e2 = wfMsgForContent('linkprefix');
1647
1648 $useLinkPrefixExtension = $wgContLang->linkPrefixExtension();
1649 if (is_null($this->mTitle)) {
1650 throw new MWException(__METHOD__ . ": \$this->mTitle is null\n");
1651 }
1652 $nottalk = !$this->mTitle->isTalkPage();
1653
1654 if ($useLinkPrefixExtension) {
1655 $m = array();
1656 if (preg_match($e2, $s, $m)) {
1657 $first_prefix = $m[2];
1658 } else {
1659 $first_prefix = false;
1660 }
1661 } else {
1662 $prefix = '';
1663 }
1664
1665 if ($wgContLang->hasVariants()) {
1666 $selflink = $wgContLang->convertLinkToAllVariants($this->mTitle->getPrefixedText());
1667 } else {
1668 $selflink = array($this->mTitle->getPrefixedText());
1669 }
1670 $useSubpages = $this->areSubpagesAllowed();
1671 wfProfileOut($fname . '-setup');
1672
1673 # Loop for each link
1674 for ($k = 0; isset($a[$k]); $k++) {
1675 $line = $a[$k];
1676 if ($useLinkPrefixExtension) {
1677 wfProfileIn($fname . '-prefixhandling');
1678 if (preg_match($e2, $s, $m)) {
1679 $prefix = $m[2];
1680 $s = $m[1];
1681 } else {
1682 $prefix = '';
1683 }
1684 # first link
1685 if ($first_prefix) {
1686 $prefix = $first_prefix;
1687 $first_prefix = false;
1688 }
1689 wfProfileOut($fname . '-prefixhandling');
1690 }
1691
1692 $might_be_img = false;
1693
1694 wfProfileIn("$fname-e1");
1695 if (preg_match($e1, $line, $m)) { # page with normal text or alt
1696 $text = $m[2];
1697 # If we get a ] at the beginning of $m[3] that means we have a link that's something like:
1698 # [[Image:Foo.jpg|[http://example.com desc]]] <- having three ] in a row fucks up,
1699 # the real problem is with the $e1 regex
1700 # See bug 1300.
1701 #
1702 # Still some problems for cases where the ] is meant to be outside punctuation,
1703 # and no image is in sight. See bug 2095.
1704 #
1705 if ($text !== '' &&
1706 substr($m[3], 0, 1) === ']' &&
1707 strpos($text, '[') !== false
1708 ) {
1709 $text .= ']'; # so that replaceExternalLinks($text) works later
1710 $m[3] = substr($m[3], 1);
1711 }
1712 # fix up urlencoded title texts
1713 if (strpos($m[1], '%') !== false) {
1714 # Should anchors '#' also be rejected?
1715 $m[1] = str_replace(array('<', '>'), array('&lt;', '&gt;'), urldecode($m[1]));
1716 }
1717 $trail = $m[3];
1718 } elseif (preg_match($e1_img, $line, $m)) { # Invalid, but might be an image with a link in its caption
1719 $might_be_img = true;
1720 $text = $m[2];
1721 if (strpos($m[1], '%') !== false) {
1722 $m[1] = urldecode($m[1]);
1723 }
1724 $trail = "";
1725 } else { # Invalid form; output directly
1726 $s .= $prefix . '[[' . $line ;
1727 wfProfileOut("$fname-e1");
1728 continue;
1729 }
1730 wfProfileOut("$fname-e1");
1731 wfProfileIn("$fname-misc");
1732
1733 # Don't allow internal links to pages containing
1734 # PROTO: where PROTO is a valid URL protocol; these
1735 # should be external links.
1736 if (preg_match('/^\b(?:' . wfUrlProtocols() . ')/', $m[1])) {
1737 $s .= $prefix . '[[' . $line ;
1738 continue;
1739 }
1740
1741 # Make subpage if necessary
1742 if ($useSubpages) {
1743 $link = $this->maybeDoSubpageLink($m[1], $text);
1744 } else {
1745 $link = $m[1];
1746 }
1747
1748 $noforce = (substr($m[1], 0, 1) != ':');
1749 if (!$noforce) {
1750 # Strip off leading ':'
1751 $link = substr($link, 1);
1752 }
1753
1754 wfProfileOut("$fname-misc");
1755 wfProfileIn("$fname-title");
1756 $nt = Title::newFromText($this->mStripState->unstripNoWiki($link));
1757 if (!$nt) {
1758 $s .= $prefix . '[[' . $line;
1759 wfProfileOut("$fname-title");
1760 continue;
1761 }
1762
1763 $ns = $nt->getNamespace();
1764 $iw = $nt->getInterWiki();
1765 wfProfileOut("$fname-title");
1766
1767 if ($might_be_img) { # if this is actually an invalid link
1768 wfProfileIn("$fname-might_be_img");
1769 if ($ns == NS_IMAGE && $noforce) { #but might be an image
1770 $found = false;
1771 while (isset($a[$k + 1])) {
1772 #look at the next 'line' to see if we can close it there
1773 $spliced = array_splice($a, $k + 1, 1);
1774 $next_line = array_shift($spliced);
1775 $m = explode(']]', $next_line, 3);
1776 if (count($m) == 3) {
1777 # the first ]] closes the inner link, the second the image
1778 $found = true;
1779 $text .= "[[{$m[0]}]]{$m[1]}";
1780 $trail = $m[2];
1781 break;
1782 } elseif (count($m) == 2) {
1783 #if there's exactly one ]] that's fine, we'll keep looking
1784 $text .= "[[{$m[0]}]]{$m[1]}";
1785 } else {
1786 #if $next_line is invalid too, we need look no further
1787 $text .= '[[' . $next_line;
1788 break;
1789 }
1790 }
1791 if (!$found) {
1792 # we couldn't find the end of this imageLink, so output it raw
1793 #but don't ignore what might be perfectly normal links in the text we've examined
1794 $text = $this->replaceInternalLinks($text);
1795 $s .= "{$prefix}[[$link|$text";
1796 # note: no $trail, because without an end, there *is* no trail
1797 wfProfileOut("$fname-might_be_img");
1798 continue;
1799 }
1800 } else { #it's not an image, so output it raw
1801 $s .= "{$prefix}[[$link|$text";
1802 # note: no $trail, because without an end, there *is* no trail
1803 wfProfileOut("$fname-might_be_img");
1804 continue;
1805 }
1806 wfProfileOut("$fname-might_be_img");
1807 }
1808
1809 $wasblank = ('' == $text);
1810 if ($wasblank) {
1811 $text = $link;
1812 }
1813
1814 # Link not escaped by : , create the various objects
1815 if ($noforce) {
1816
1817 # Interwikis
1818 wfProfileIn("$fname-interwiki");
1819 if ($iw && $this->mOptions->getInterwikiMagic() && $nottalk && $wgContLang->getLanguageName($iw)) {
1820 $this->mOutput->addLanguageLink($nt->getFullText());
1821 $s = rtrim($s . $prefix);
1822 $s .= trim($trail, "\n") == '' ? '': $prefix . $trail;
1823 wfProfileOut("$fname-interwiki");
1824 continue;
1825 }
1826 wfProfileOut("$fname-interwiki");
1827
1828 if ($ns == NS_IMAGE) {
1829 wfProfileIn("$fname-image");
1830 if (!wfIsBadImage($nt->getDBkey(), $this->mTitle)) {
1831 # recursively parse links inside the image caption
1832 # actually, this will parse them in any other parameters, too,
1833 # but it might be hard to fix that, and it doesn't matter ATM
1834 $text = $this->replaceExternalLinks($text);
1835 $text = $this->replaceInternalLinks($text);
1836
1837 # cloak any absolute URLs inside the image markup, so replaceExternalLinks() won't touch them
1838 $s .= $prefix . $this->armorLinks($this->makeImage($nt, $text)) . $trail;
1839 $this->mOutput->addImage($nt->getDBkey());
1840
1841 wfProfileOut("$fname-image");
1842 continue;
1843 } else {
1844 # We still need to record the image's presence on the page
1845 $this->mOutput->addImage($nt->getDBkey());
1846 }
1847 wfProfileOut("$fname-image");
1848 }
1849
1850 if ($ns == NS_CATEGORY) {
1851 wfProfileIn("$fname-category");
1852 $s = rtrim($s . "\n"); # bug 87
1853
1854 if ($wasblank) {
1855 $sortkey = $this->getDefaultSort();
1856 } else {
1857 $sortkey = $text;
1858 }
1859 $sortkey = Sanitizer::decodeCharReferences($sortkey);
1860 $sortkey = str_replace("\n", '', $sortkey);
1861 $sortkey = $wgContLang->convertCategoryKey($sortkey);
1862 $this->mOutput->addCategory($nt->getDBkey(), $sortkey);
1863
1868 $s .= trim($prefix . $trail, "\n") == '' ? '': $prefix . $trail;
1869
1870 wfProfileOut("$fname-category");
1871 continue;
1872 }
1873 }
1874
1875 # Self-link checking
1876 if ($nt->getFragment() === '') {
1877 if (in_array($nt->getPrefixedText(), $selflink, true)) {
1878 $s .= $prefix . $sk->makeSelfLinkObj($nt, $text, '', $trail);
1879 continue;
1880 }
1881 }
1882
1883 # Special and Media are pseudo-namespaces; no pages actually exist in them
1884 if ($ns == NS_MEDIA) {
1885 $link = $sk->makeMediaLinkObj($nt, $text);
1886 # Cloak with NOPARSE to avoid replacement in replaceExternalLinks
1887 $s .= $prefix . $this->armorLinks($link) . $trail;
1888 $this->mOutput->addImage($nt->getDBkey());
1889 continue;
1890 } elseif ($ns == NS_SPECIAL) {
1891 $s .= $this->makeKnownLinkHolder($nt, $text, '', $trail, $prefix);
1892 continue;
1893 } elseif ($ns == NS_IMAGE) {
1894 $img = new Image($nt);
1895 if ($img->exists()) {
1896 // Force a blue link if the file exists; may be a remote
1897 // upload on the shared repository, and we want to see its
1898 // auto-generated page.
1899 $s .= $this->makeKnownLinkHolder($nt, $text, '', $trail, $prefix);
1900 $this->mOutput->addLink($nt);
1901 continue;
1902 }
1903 }
1904 $s .= $this->makeLinkHolder($nt, $text, '', $trail, $prefix);
1905 }
1906 wfProfileOut($fname);
makeImage($nt, $options)
Parse image options text and use it to make an image.
Definition: Parser.php:4598
makeKnownLinkHolder($nt, $text='', $query='', $trail='', $prefix='')
Render a forced-blue link inline; protect against double expansion of URLs if we're in a mode that pr...
Definition: Parser.php:1957
armorLinks($text)
Insert a NOPARSE hacky thing into any inline links in a chunk that's going to go through further pars...
Definition: Parser.php:1977
getDefaultSort()
Accessor for $mDefaultSort Will use the title/prefixed title if none is set.
Definition: Parser.php:4947
makeLinkHolder(&$nt, $text='', $query='', $trail='', $prefix='')
Make a link placeholder.
Definition: Parser.php:1915
static decodeCharReferences($text)
Decode any character references, numeric or named entities, in the text and return a UTF-8 string.
Definition: Sanitizer.php:1018
static legalChars()
Get a regex character class describing the legal characters in a link.
Definition: Title.php:355
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples

◆ replaceLinkHolders()

Parser::replaceLinkHolders ( $text,
  $options = 0 
)

Replace link placeholders with actual links, in the buffer Placeholders created in Skin::makeLinkObj() Returns an array of links found, indexed by PDBK: 0 - broken 1 - normal link 2 - stub $options is a bit field, RLH_FOR_UPDATE to select for update.

Definition at line 4164 of file Parser.php.

4167 {
4168 global $wgUser;
4169 global $wgContLang;
4170
4171 $fname = 'Parser::replaceLinkHolders';
4172 wfProfileIn($fname);
4173
4174 $pdbks = array();
4175 $colours = array();
4176 $sk = $this->mOptions->getSkin();
4177 $linkCache = &LinkCache::singleton();
4178
4179 if (!empty($this->mLinkHolders['namespaces'])) {
4180 wfProfileIn($fname . '-check');
4181 $dbr = wfGetDB(DB_SLAVE);
4182 $page = $dbr->tableName('page');
4183 $threshold = $wgUser->getOption('stubthreshold');
4184
4185 # Sort by namespace
4186 asort($this->mLinkHolders['namespaces']);
4187
4188 # Generate query
4189 $query = false;
4190 $current = null;
4191 foreach ($this->mLinkHolders['namespaces'] as $key => $ns) {
4192 # Make title object
4193 $title = $this->mLinkHolders['titles'][$key];
4194
4195 # Skip invalid entries.
4196 # Result will be ugly, but prevents crash.
4197 if (is_null($title)) {
4198 continue;
4199 }
4200 $pdbk = $pdbks[$key] = $title->getPrefixedDBkey();
4201
4202 # Check if it's a static known link, e.g. interwiki
4203 if ($title->isAlwaysKnown()) {
4204 $colours[$pdbk] = 1;
4205 } elseif (($id = $linkCache->getGoodLinkID($pdbk)) != 0) {
4206 $colours[$pdbk] = 1;
4207 $this->mOutput->addLink($title, $id);
4208 } elseif ($linkCache->isBadLink($pdbk)) {
4209 $colours[$pdbk] = 0;
4210 } else {
4211 # Not in the link cache, add it to the query
4212 if (!isset($current)) {
4213 $current = $ns;
4214 $query = "SELECT page_id, page_namespace, page_title";
4215 if ($threshold > 0) {
4216 $query .= ', page_len, page_is_redirect';
4217 }
4218 $query .= " FROM $page WHERE (page_namespace=$ns AND page_title IN(";
4219 } elseif ($current != $ns) {
4220 $current = $ns;
4221 $query .= ")) OR (page_namespace=$ns AND page_title IN(";
4222 } else {
4223 $query .= ', ';
4224 }
4225
4226 $query .= $dbr->addQuotes($this->mLinkHolders['dbkeys'][$key]);
4227 }
4228 }
4229 if ($query) {
4230 $query .= '))';
4231 if ($options & RLH_FOR_UPDATE) {
4232 $query .= ' FOR UPDATE';
4233 }
4234
4235 $res = $dbr->query($query, $fname);
4236
4237 # Fetch data and form into an associative array
4238 # non-existent = broken
4239 # 1 = known
4240 # 2 = stub
4241 while ($s = $dbr->fetchObject($res)) {
4242 $title = Title::makeTitle($s->page_namespace, $s->page_title);
4243 $pdbk = $title->getPrefixedDBkey();
4244 $linkCache->addGoodLinkObj($s->page_id, $title);
4245 $this->mOutput->addLink($title, $s->page_id);
4246
4247 if ($threshold > 0) {
4248 $size = $s->page_len;
4249 if ($s->page_is_redirect || $s->page_namespace != 0 || $size >= $threshold) {
4250 $colours[$pdbk] = 1;
4251 } else {
4252 $colours[$pdbk] = 2;
4253 }
4254 } else {
4255 $colours[$pdbk] = 1;
4256 }
4257 }
4258 }
4259 wfProfileOut($fname . '-check');
4260
4261 # Do a second query for different language variants of links and categories
4262 if ($wgContLang->hasVariants()) {
4263 $linkBatch = new LinkBatch();
4264 $variantMap = array(); // maps $pdbkey_Variant => $keys (of link holders)
4265 $categoryMap = array(); // maps $category_variant => $category (dbkeys)
4266 $varCategories = array(); // category replacements oldDBkey => newDBkey
4267
4268 $categories = $this->mOutput->getCategoryLinks();
4269
4270 // Add variants of links to link batch
4271 foreach ($this->mLinkHolders['namespaces'] as $key => $ns) {
4272 $title = $this->mLinkHolders['titles'][$key];
4273 if (is_null($title)) {
4274 continue;
4275 }
4276
4277 $pdbk = $title->getPrefixedDBkey();
4278 $titleText = $title->getText();
4279
4280 // generate all variants of the link title text
4281 $allTextVariants = $wgContLang->convertLinkToAllVariants($titleText);
4282
4283 // if link was not found (in first query), add all variants to query
4284 if (!isset($colours[$pdbk])) {
4285 foreach ($allTextVariants as $textVariant) {
4286 if ($textVariant != $titleText) {
4287 $variantTitle = Title::makeTitle($ns, $textVariant);
4288 if (is_null($variantTitle)) {
4289 continue;
4290 }
4291 $linkBatch->addObj($variantTitle);
4292 $variantMap[$variantTitle->getPrefixedDBkey()][] = $key;
4293 }
4294 }
4295 }
4296 }
4297
4298 // process categories, check if a category exists in some variant
4299 foreach ($categories as $category) {
4300 $variants = $wgContLang->convertLinkToAllVariants($category);
4301 foreach ($variants as $variant) {
4302 if ($variant != $category) {
4303 $variantTitle = Title::newFromDBkey(Title::makeName(NS_CATEGORY, $variant));
4304 if (is_null($variantTitle)) {
4305 continue;
4306 }
4307 $linkBatch->addObj($variantTitle);
4308 $categoryMap[$variant] = $category;
4309 }
4310 }
4311 }
4312
4313
4314 if (!$linkBatch->isEmpty()) {
4315 // construct query
4316 $titleClause = $linkBatch->constructSet('page', $dbr);
4317
4318 $variantQuery = "SELECT page_id, page_namespace, page_title";
4319 if ($threshold > 0) {
4320 $variantQuery .= ', page_len, page_is_redirect';
4321 }
4322
4323 $variantQuery .= " FROM $page WHERE $titleClause";
4324 if ($options & RLH_FOR_UPDATE) {
4325 $variantQuery .= ' FOR UPDATE';
4326 }
4327
4328 $varRes = $dbr->query($variantQuery, $fname);
4329
4330 // for each found variants, figure out link holders and replace
4331 while ($s = $dbr->fetchObject($varRes)) {
4332 $variantTitle = Title::makeTitle($s->page_namespace, $s->page_title);
4333 $varPdbk = $variantTitle->getPrefixedDBkey();
4334 $vardbk = $variantTitle->getDBkey();
4335
4336 $holderKeys = array();
4337 if (isset($variantMap[$varPdbk])) {
4338 $holderKeys = $variantMap[$varPdbk];
4339 $linkCache->addGoodLinkObj($s->page_id, $variantTitle);
4340 $this->mOutput->addLink($variantTitle, $s->page_id);
4341 }
4342
4343 // loop over link holders
4344 foreach ($holderKeys as $key) {
4345 $title = $this->mLinkHolders['titles'][$key];
4346 if (is_null($title)) {
4347 continue;
4348 }
4349
4350 $pdbk = $title->getPrefixedDBkey();
4351
4352 if (!isset($colours[$pdbk])) {
4353 // found link in some of the variants, replace the link holder data
4354 $this->mLinkHolders['titles'][$key] = $variantTitle;
4355 $this->mLinkHolders['dbkeys'][$key] = $variantTitle->getDBkey();
4356
4357 // set pdbk and colour
4358 $pdbks[$key] = $varPdbk;
4359 if ($threshold > 0) {
4360 $size = $s->page_len;
4361 if ($s->page_is_redirect || $s->page_namespace != 0 || $size >= $threshold) {
4362 $colours[$varPdbk] = 1;
4363 } else {
4364 $colours[$varPdbk] = 2;
4365 }
4366 } else {
4367 $colours[$varPdbk] = 1;
4368 }
4369 }
4370 }
4371
4372 // check if the object is a variant of a category
4373 if (isset($categoryMap[$vardbk])) {
4374 $oldkey = $categoryMap[$vardbk];
4375 if ($oldkey != $vardbk) {
4376 $varCategories[$oldkey] = $vardbk;
4377 }
4378 }
4379 }
4380
4381 // rebuild the categories in original order (if there are replacements)
4382 if (count($varCategories) > 0) {
4383 $newCats = array();
4384 $originalCats = $this->mOutput->getCategories();
4385 foreach ($originalCats as $cat => $sortkey) {
4386 // make the replacement
4387 if (array_key_exists($cat, $varCategories)) {
4388 $newCats[$varCategories[$cat]] = $sortkey;
4389 } else {
4390 $newCats[$cat] = $sortkey;
4391 }
4392 }
4393 $this->mOutput->setCategoryLinks($newCats);
4394 }
4395 }
4396 }
4397
4398 # Construct search and replace arrays
4399 wfProfileIn($fname . '-construct');
4400 $replacePairs = array();
4401 foreach ($this->mLinkHolders['namespaces'] as $key => $ns) {
4402 $pdbk = $pdbks[$key];
4403 $searchkey = "<!--LINK $key-->";
4404 $title = $this->mLinkHolders['titles'][$key];
4405 if (empty($colours[$pdbk])) {
4406 $linkCache->addBadLinkObj($title);
4407 $colours[$pdbk] = 0;
4408 $this->mOutput->addLink($title, 0);
4409 $replacePairs[$searchkey] = $sk->makeBrokenLinkObj(
4410 $title,
4411 $this->mLinkHolders['texts'][$key],
4412 $this->mLinkHolders['queries'][$key]
4413 );
4414 } elseif ($colours[$pdbk] == 1) {
4415 $replacePairs[$searchkey] = $sk->makeKnownLinkObj(
4416 $title,
4417 $this->mLinkHolders['texts'][$key],
4418 $this->mLinkHolders['queries'][$key]
4419 );
4420 } elseif ($colours[$pdbk] == 2) {
4421 $replacePairs[$searchkey] = $sk->makeStubLinkObj(
4422 $title,
4423 $this->mLinkHolders['texts'][$key],
4424 $this->mLinkHolders['queries'][$key]
4425 );
4426 }
4427 }
4428 $replacer = new HashtableReplacer($replacePairs, 1);
4429 wfProfileOut($fname . '-construct');
4430
4431 # Do the thing
4432 wfProfileIn($fname . '-replace');
4433 $text = preg_replace_callback(
4434 '/(<!--LINK .*?-->)/',
4435 $replacer->cb(),
4436 $text
4437 );
4438
4439 wfProfileOut($fname . '-replace');
4440 }
4441
4442 # Now process interwiki link holders
4443 # This is quite a bit simpler than internal links
4444 if (!empty($this->mInterwikiLinkHolders['texts'])) {
4445 wfProfileIn($fname . '-interwiki');
4446 # Make interwiki link HTML
4447 $replacePairs = array();
4448 foreach ($this->mInterwikiLinkHolders['texts'] as $key => $link) {
4449 $title = $this->mInterwikiLinkHolders['titles'][$key];
4450 $replacePairs[$key] = $sk->makeLinkObj($title, $link);
4451 }
4452 $replacer = new HashtableReplacer($replacePairs, 1);
4453
4454 $text = preg_replace_callback(
4455 '/<!--IWLINK (.*?)-->/',
4456 $replacer->cb(),
4457 $text
4458 );
4459 wfProfileOut($fname . '-interwiki');
4460 }
4461
4462 wfProfileOut($fname);
const RLH_FOR_UPDATE
Definition: Parser.php:15
static makeName($ns, $title)
Definition: Title.php:400
static & makeTitle($ns, $title)
Create a new Title from a namespace index and a DB key.
Definition: Title.php:253
static newFromDBkey($key)
Create a new Title from a prefixed DB key.
Definition: Title.php:102
foreach($_POST as $key=> $value) $res

◆ replaceLinkHoldersText()

Parser::replaceLinkHoldersText (   $text)

Replace link placeholders with plain text of links (not HTML-formatted).

Parameters
string$text
Returns
string

Definition at line 4470 of file Parser.php.

4473 {
4474 $fname = 'Parser::replaceLinkHoldersText';
4475 wfProfileIn($fname);
4476
4477 $text = preg_replace_callback(
4478 '/<!--(LINK|IWLINK) (.*?)-->/',
4479 array( &$this, 'replaceLinkHoldersTextCallback' ),
4480 $text
4481 );
4482
4483 wfProfileOut($fname);

◆ replaceLinkHoldersTextCallback()

Parser::replaceLinkHoldersTextCallback (   $matches)
Parameters
array$matches
Returns
string

Definition at line 4490 of file Parser.php.

4493 {
4494 $type = $matches[1];
4495 $key = $matches[2];
4496 if ($type == 'LINK') {
4497 if (isset($this->mLinkHolders['texts'][$key])) {
4498 return $this->mLinkHolders['texts'][$key];
4499 }
4500 } elseif ($type == 'IWLINK') {
4501 if (isset($this->mInterwikiLinkHolders['texts'][$key])) {
4502 return $this->mInterwikiLinkHolders['texts'][$key];
4503 }
4504 }

◆ replaceSection()

Parser::replaceSection (   $oldtext,
  $section,
  $text 
)

Definition at line 4890 of file Parser.php.

4893 {

◆ replaceUnusualEscapes()

static Parser::replaceUnusualEscapes (   $url)
static

Replace unusual URL escape codes with their equivalent characters.

Parameters
string
Returns
string
Todo:
This can merge genuinely required bits in the path or query string, breaking legit URLs. A proper fix would treat the various parts of the URL differently; as a workaround, just use the output for statistical records, not for actual linking/output.

Definition at line 1554 of file Parser.php.

1557 {
1558 return preg_replace_callback(
1559 '/%[0-9A-Fa-f]{2}/',
1560 array( 'Parser', 'replaceUnusualEscapesCallback' ),
1561 $url

◆ replaceUnusualEscapesCallback()

static Parser::replaceUnusualEscapesCallback (   $matches)
staticprivate

Callback function used in replaceUnusualEscapes().

Replaces unusual URL escape codes with their equivalent character

Definition at line 1569 of file Parser.php.

1572 {
1573 $char = urldecode($matches[0]);
1574 $ord = ord($char);
1575
1576 // Is it an unsafe or HTTP reserved character according to RFC 1738?
1577 if ($ord > 32 && $ord < 127 && strpos('<>"#{}|\^~[]`;/?', $char) === false) {
1578 // No, shouldn't be escaped
1579 return $char;
1580 } else {
1581 // Yes, leave it escaped
1582 return $matches[0];

◆ replaceVariables()

Parser::replaceVariables (   $text,
  $args = array(),
  $argsOnly = false 
)

Replace magic variables, templates, and template arguments with the appropriate text.

Templates are substituted recursively, taking care to avoid infinite loops.

Note that the substitution depends on value of $mOutputType: OT_WIKI: only {{subst:}} templates OT_MSG: only magic variables OT_HTML: all templates and magic variables

Parameters
string$texThe text to transform
array$argsKey-value pairs representing template parameters to substitute
bool$argsOnlyOnly do argument (triple-brace) expansion, not double-brace expansion

Definition at line 2921 of file Parser.php.

2924 {
2925 # Prevent too big inclusions
2926 if (strlen($text) > $this->mOptions->getMaxIncludeSize()) {
2927 return $text;
2928 }
2929
2930 $fname = __METHOD__ /*. '-L' . count( $this->mArgStack )*/;
2931 wfProfileIn($fname);
2932
2933 # This function is called recursively. To keep track of arguments we need a stack:
2934 array_push($this->mArgStack, $args);
2935
2936 $braceCallbacks = array();
2937 if (!$argsOnly) {
2938 $braceCallbacks[2] = array( &$this, 'braceSubstitution' );
2939 }
2940 if ($this->mOutputType != OT_MSG) {
2941 $braceCallbacks[3] = array( &$this, 'argSubstitution' );
2942 }
2943 if ($braceCallbacks) {
2944 $callbacks = array(
2945 '{' => array(
2946 'end' => '}',
2947 'cb' => $braceCallbacks,
2948 'min' => $argsOnly ? 3 : 2,
2949 'max' => isset($braceCallbacks[3]) ? 3 : 2,
2950 ),
2951 '[' => array(
2952 'end' => ']',
2953 'cb' => array(2 => null),
2954 'min' => 2,
2955 'max' => 2,
2956 )
2957 );
2958 $text = $this->replace_callback($text, $callbacks);
2959
2960 array_pop($this->mArgStack);
2961 }
2962 wfProfileOut($fname);
replace_callback($text, $callbacks)
parse any parentheses in format ((title|part|part)) and call callbacks to get a replacement text for ...
Definition: Parser.php:2734

◆ setDefaultSort()

Parser::setDefaultSort (   $sort)

Mutator for $mDefaultSort.

Parameters
$sortNew value

Definition at line 4936 of file Parser.php.

4939 {

◆ setFunctionHook()

Parser::setFunctionHook (   $id,
  $callback,
  $flags = 0 
)

Create a function, e.g.

{{sum:1|2|3}} The callback function should have the form: function myParserFunction( &$parser, $arg1, $arg2, $arg3 ) { ... }

The callback may either return the text result of the function, or an array with the text in element 0, and a number of flags in the other elements. The names of the flags are specified in the keys. Valid flags are: found The text returned is valid, stop processing the template. This is on by default. nowiki Wiki markup in the return value should be escaped noparse Unsafe HTML tags should not be stripped, etc. noargs Don't replace triple-brace arguments in the return value isHTML The returned text is HTML, armour it against wikitext transformation

Parameters
string$idThe magic word ID
mixed$callbackThe callback function (and object) to use
integer$flagsa combination of the following flags: SFH_NO_HASH No leading hash, i.e. {{plural:...}} instead of {{if:...}}
Returns
The old callback function for this name, if any

Definition at line 4113 of file Parser.php.

4116 {
4117 $oldVal = isset($this->mFunctionHooks[$id]) ? $this->mFunctionHooks[$id] : null;
4118 $this->mFunctionHooks[$id] = $callback;
4119
4120 # Add to function cache
4121 $mw = MagicWord::get($id);
4122 if (!$mw) {
4123 throw new MWException('Parser::setFunctionHook() expecting a magic word identifier.');
4124 }
4125
4126 $synonyms = $mw->getSynonyms();
4127 $sensitive = intval($mw->isCaseSensitive());
4128
4129 foreach ($synonyms as $syn) {
4130 # Case
4131 if (!$sensitive) {
4132 $syn = strtolower($syn);
4133 }
4134 # Add leading hash
4135 if (!($flags & SFH_NO_HASH)) {
4136 $syn = '#' . $syn;
4137 }
4138 # Remove trailing colon
4139 if (substr($syn, -1, 1) == ':') {
4140 $syn = substr($syn, 0, -1);
4141 }
4142 $this->mFunctionSynonyms[$sensitive][$syn] = $id;
4143 }

◆ setHook()

Parser::setHook (   $tag,
  $callback 
)

Create an HTML-style tag, e.g.

<yourtag>special text</yourtag> The callback should have the following form: function myParserHook( $text, $params, &$parser ) { ... }

Transform and return $text. Use $parser for any required context, e.g. use $parser->getTitle() and $parser->getOptions() not $wgTitle or $wgOut->mParserOptions

Parameters
mixed$tagThe tag to use, e.g. 'hook' for <hook>
mixed$callbackThe callback function (and object) to use for the tag
Returns
The old value of the mTagHooks array associated with the hook

Definition at line 4080 of file Parser.php.

4083 {
4084 $tag = strtolower($tag);
4085 $oldVal = isset($this->mTagHooks[$tag]) ? $this->mTagHooks[$tag] : null;
4086 $this->mTagHooks[$tag] = $callback;
4087

◆ setOutputType()

Parser::setOutputType (   $ot)

Definition at line 264 of file Parser.php.

267 {
268 $this->mOutputType = $ot;
269 // Shortcut alias
270 $this->ot = array(
271 'html' => $ot == OT_HTML,
272 'wiki' => $ot == OT_WIKI,
273 'msg' => $ot == OT_MSG,
274 'pre' => $ot == OT_PREPROCESS,

◆ startExternalParse()

Parser::startExternalParse ( $title,
  $options,
  $outputType,
  $clearState = true 
)

Set up some variables which are usually set up in parse() so that an external function can call some class members with confidence.

Definition at line 4017 of file Parser.php.

4020 {
4021 $this->mTitle = &$title;
4022 $this->mOptions = $options;
4023 $this->setOutputType($outputType);
4024 if ($clearState) {
4025 $this->clearState();

◆ strip()

Parser::strip (   $text,
  $state,
  $stripcomments = false,
  $dontstrip = array() 
)

Strips and renders nowiki, pre, math, hiero If $render is set, performs necessary rendering operations on plugins Returns the text, and fills an array with data needed in unstrip()

Parameters
StripState$state
bool$stripcommentswhen set, HTML comments will be stripped in addition to other tags. This is important for section editing, where these comments cause confusion when counting the sections in the wikisource
arraydontstrip contains tags which should not be stripped; used to prevent stipping of <gallery> when saving (fixes bug 2700)

Definition at line 570 of file Parser.php.

573 {
574 global $wgContLang;
575 wfProfileIn(__METHOD__);
576 $render = ($this->mOutputType == OT_HTML);
577
578 $uniq_prefix = $this->mUniqPrefix;
579 $commentState = new ReplacementArray;
580 $nowikiItems = array();
581 $generalItems = array();
582
583 $elements = array_merge(
584 array( 'nowiki', 'gallery' ),
585 array_keys($this->mTagHooks)
586 );
587 global $wgRawHtml;
588 if ($wgRawHtml) {
589 $elements[] = 'html';
590 }
591 if ($this->mOptions->getUseTeX()) {
592 $elements[] = 'math';
593 }
594
595 # Removing $dontstrip tags from $elements list (currently only 'gallery', fixing bug 2700)
596 foreach ($elements as $k => $v) {
597 if (!in_array($v, $dontstrip)) {
598 continue;
599 }
600 unset($elements[$k]);
601 }
602
603 $matches = array();
604 $text = Parser::extractTagsAndParams($elements, $text, $matches, $uniq_prefix);
605
606 foreach ($matches as $marker => $data) {
607 list($element, $content, $params, $tag) = $data;
608 if ($render) {
609 $tagName = strtolower($element);
610 wfProfileIn(__METHOD__ . "-render-$tagName");
611 switch ($tagName) {
612 case '!--':
613 // Comment
614 if (substr($tag, -3) == '-->') {
615 $output = $tag;
616 } else {
617 // Unclosed comment in input.
618 // Close it so later stripping can remove it
619 $output = "$tag-->";
620 }
621 break;
622 case 'html':
623 if ($wgRawHtml) {
624 $output = $content;
625 break;
626 }
627 // Shouldn't happen otherwise. :)
628 // no break
629 case 'nowiki':
630 $output = Xml::escapeTagsOnly($content);
631 break;
632 case 'math':
633 $output = $wgContLang->armourMath(MathRenderer::renderMath($content));
634 break;
635 case 'gallery':
636 $output = $this->renderImageGallery($content, $params);
637 break;
638 default:
639 if (isset($this->mTagHooks[$tagName])) {
640 $output = call_user_func_array(
641 $this->mTagHooks[$tagName],
642 array( $content, $params, $this )
643 );
644 } else {
645 throw new MWException("Invalid call hook $element");
646 }
647 }
648 wfProfileOut(__METHOD__ . "-render-$tagName");
649 } else {
650 // Just stripping tags; keep the source
651 $output = $tag;
652 }
653
654 // Unstrip the output, to support recursive strip() calls
655 $output = $state->unstripBoth($output);
656
657 if (!$stripcomments && $element == '!--') {
658 $commentState->setPair($marker, $output);
659 } elseif ($element == 'html' || $element == 'nowiki') {
660 $nowikiItems[$marker] = $output;
661 } else {
662 $generalItems[$marker] = $output;
663 }
664 }
665 # Add the new items to the state
666 # We do this after the loop instead of during it to avoid slowing
667 # down the recursive unstrip
668 $state->nowiki->mergeArray($nowikiItems);
669 $state->general->mergeArray($generalItems);
670
671 # Unstrip comments unless explicitly told otherwise.
672 # (The comments are always stripped prior to this point, so as to
673 # not invoke any extension tags / parser hooks contained within
674 # a comment.)
675 if (!$stripcomments) {
676 // Put them all back and forget them
677 $text = $commentState->replace($text);
678 }
679
680 wfProfileOut(__METHOD__);
extractTagsAndParams($elements, $text, &$matches, $uniq_prefix='')
Replaces all occurrences of HTML-style comments and the given tags in the text with a random marker a...
Definition: Parser.php:490
$mUniqPrefix
Definition: Parser.php:113
renderImageGallery($text, $params)
Renders an image gallery from a text with one line per image.
Definition: Parser.php:4529
$data
Definition: storeScorm.php:23

◆ stripNoGallery()

Parser::stripNoGallery ( $text)

Detect NOGALLERY magic word and set a placeholder.

Definition at line 3534 of file Parser.php.

3537 {
3538 # if the string __NOGALLERY__ (not case-sensitive) occurs in the HTML,
3539 # do not add TOC
3540 $mw = MagicWord::get('nogallery');

◆ stripToc()

Parser::stripToc (   $text)

Detect TOC magic word and set a placeholder.

Definition at line 3545 of file Parser.php.

3548 {
3549 # if the string __NOTOC__ (not case-sensitive) occurs in the HTML,
3550 # do not add TOC
3551 $mw = MagicWord::get('notoc');
3552 if ($mw->matchAndRemove($text)) {
3553 $this->mShowToc = false;
3554 }
3555
3556 $mw = MagicWord::get('toc');
3557 if ($mw->match($text)) {
3558 $this->mShowToc = true;
3559 $this->mForceTocPosition = true;
3560
3561 // Set a placeholder. At the end we'll fill it in with the TOC.
3562 $text = $mw->replace('<!--MWTOC-->', $text, 1);
3563
3564 // Only keep the first one.
3565 $text = $mw->replace('', $text);
3566 }

◆ tidy()

Parser::tidy (   $text)
static

Interface with html tidy, used if $wgUseTidy = true.

If tidy isn't able to correct the markup, the original will be returned in all its glory with a warning comment appended.

Either the external tidy program or the in-process tidy extension will be used depending on availability. Override the default $wgTidyInternal setting to disable the internal if it's not working.

Parameters
string$textHideous HTML input
Returns
string Corrected HTML output

Definition at line 741 of file Parser.php.

744 {
745 global $wgTidyInternal;
746 $wrappedtext = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' .
747' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html>' .
748'<head><title>test</title></head><body>' . $text . '</body></html>';
749 if ($wgTidyInternal) {
750 $correctedtext = Parser::internalTidy($wrappedtext);
751 } else {
752 $correctedtext = Parser::externalTidy($wrappedtext);
753 }
754 if (is_null($correctedtext)) {
755 wfDebug("Tidy error detected!\n");
756 return $text . "\n<!-- Tidy found serious XHTML errors -->\n";
757 }
externalTidy($text)
Spawn an external HTML tidy process and get corrected markup back from it.
Definition: Parser.php:765
internalTidy($text)
Use the HTML tidy PECL extension to use the tidy library in-process, saving the overhead of spawning ...
Definition: Parser.php:817

◆ Title()

Parser::Title (   $x = null)

#-

#+ Accessor/mutator

Definition at line 4724 of file Parser.php.

4727 {

◆ transformMsg()

Parser::transformMsg (   $text,
  $options 
)

Transform a MediaWiki message by replacing magic variables.

Parameters
string$textthe text to transform
ParserOptions$optionsoptions
Returns
string the text with variables substituted

Definition at line 4035 of file Parser.php.

4038 {
4039 global $wgTitle;
4040 static $executing = false;
4041
4042 $fname = "Parser::transformMsg";
4043
4044 # Guard against infinite recursion
4045 if ($executing) {
4046 return $text;
4047 }
4048 $executing = true;
4049
4050 wfProfileIn($fname);
4051
4052 if ($wgTitle && !($wgTitle instanceof FakeTitle)) {
4053 $this->mTitle = $wgTitle;
4054 } else {
4055 $this->mTitle = Title::newFromText('msg');
4056 }
4057 $this->mOptions = $options;
4058 $this->setOutputType(OT_MSG);
4059 $this->clearState();
4060 $text = $this->replaceVariables($text);
4061
4062 $executing = false;
4063 wfProfileOut($fname);

◆ uniqPrefix()

Parser::uniqPrefix ( )

Accessor for mUniqPrefix.

Definition at line 281 of file Parser.php.

284 {

◆ unstrip()

Parser::unstrip (   $text,
  $state 
)

Restores pre, math, and other extensions removed by strip()

always call unstripNoWiki() after this one

Deprecated:
use $this->mStripState->unstrip()

Definition at line 689 of file Parser.php.

692 {

◆ unstripForHTML()

Parser::unstripForHTML (   $text)
Deprecated:
use $this->mStripState->unstripBoth()

Definition at line 708 of file Parser.php.

711 {

◆ unstripNoWiki()

Parser::unstripNoWiki (   $text,
  $state 
)

Always call this after unstrip() to preserve the order.

Deprecated:
use $this->mStripState->unstrip()

Definition at line 700 of file Parser.php.

703 {

◆ validateSig()

Parser::validateSig (   $text)

Check that the user's signature contains no bad XML.

Parameters
string$text
Returns
mixed An expanded string, or false if invalid.

Definition at line 3969 of file Parser.php.

3972 {

◆ variableSubstitution()

Parser::variableSubstitution (   $matches)

Replace magic variables.

Definition at line 2968 of file Parser.php.

2971 {
2972 global $wgContLang;
2973 $fname = 'Parser::variableSubstitution';
2974 $varname = $wgContLang->lc($matches[1]);
2975 wfProfileIn($fname);
2976 $skip = false;
2977 if ($this->mOutputType == OT_WIKI) {
2978 # Do only magic variables prefixed by SUBST
2979 $mwSubst = &MagicWord::get('subst');
2980 if (!$mwSubst->matchStartAndRemove($varname)) {
2981 $skip = true;
2982 }
2983 # Note that if we don't substitute the variable below,
2984 # we don't remove the {{subst:}} magic word, in case
2985 # it is a template rather than a magic variable.
2986 }
2987 if (!$skip && array_key_exists($varname, $this->mVariables)) {
2988 $id = $this->mVariables[$varname];
2989 # Now check if we did really match, case sensitive or not
2990 $mw = &MagicWord::get($id);
2991 if ($mw->match($matches[1])) {
2992 $text = $this->getVariableValue($id);
2993 $this->mOutput->mContainsOldMagic = true;
2994 } else {
2995 $text = $matches[0];
2996 }
2997 } else {
2998 $text = $matches[0];
2999 }
3000 wfProfileOut($fname);
getVariableValue($index)
Return value of a magic variable (like PAGENAME)
Definition: Parser.php:2506

Field Documentation

◆ $mArgStack

Parser::$mArgStack

Definition at line 108 of file Parser.php.

◆ $mAutonumber

Parser::$mAutonumber

Definition at line 104 of file Parser.php.

◆ $mDefaultSort

Parser::$mDefaultSort

Definition at line 115 of file Parser.php.

◆ $mDTopen

Parser::$mDTopen

Definition at line 105 of file Parser.php.

◆ $mFunctionHooks

Parser::$mFunctionHooks

Definition at line 98 of file Parser.php.

◆ $mFunctionSynonyms

Parser::$mFunctionSynonyms

Definition at line 99 of file Parser.php.

◆ $mIncludeCount

Parser::$mIncludeCount

Definition at line 107 of file Parser.php.

◆ $mIncludeSizes

Parser::$mIncludeSizes

Definition at line 114 of file Parser.php.

◆ $mInPre

Parser::$mInPre

Definition at line 110 of file Parser.php.

◆ $mInterwikiLinkHolders

Parser::$mInterwikiLinkHolders

Definition at line 111 of file Parser.php.

◆ $mLastSection

Parser::$mLastSection

Definition at line 109 of file Parser.php.

◆ $mLinkHolders

Parser::$mLinkHolders

Definition at line 112 of file Parser.php.

◆ $mOptions

Parser::$mOptions

Definition at line 124 of file Parser.php.

◆ $mOutput

Parser::$mOutput

Definition at line 103 of file Parser.php.

◆ $mOutputType

Parser::$mOutputType

Definition at line 128 of file Parser.php.

◆ $mRevIdForTs

Parser::$mRevIdForTs

Definition at line 136 of file Parser.php.

◆ $mRevisionId

Parser::$mRevisionId

Definition at line 132 of file Parser.php.

◆ $mRevisionTimestamp

Parser::$mRevisionTimestamp

Definition at line 134 of file Parser.php.

◆ $mStripState

Parser::$mStripState

Definition at line 106 of file Parser.php.

◆ $mTagHooks

Parser::$mTagHooks

#+

Definition at line 97 of file Parser.php.

◆ $mTemplatePath

Parser::$mTemplatePath

Definition at line 119 of file Parser.php.

◆ $mTemplates

Parser::$mTemplates

Definition at line 116 of file Parser.php.

◆ $mTitle

Parser::$mTitle

Definition at line 126 of file Parser.php.

◆ $mUniqPrefix

Parser::$mUniqPrefix

Definition at line 113 of file Parser.php.

◆ $mVariables

Parser::$mVariables

Definition at line 100 of file Parser.php.

◆ $ot

Parser::$ot

Definition at line 130 of file Parser.php.

◆ VERSION

const Parser::VERSION = MW_PARSER_VERSION

Definition at line 92 of file Parser.php.


The documentation for this class was generated from the following file: