function register() { global $wgContLang, $wgNamespaceAliases, $wgDisableCounters; $lib = array('getNsIndex' => array($this, 'getNsIndex'), 'pagesInCategory' => array($this, 'pagesInCategory'), 'pagesInNamespace' => array($this, 'pagesInNamespace'), 'usersInGroup' => array($this, 'usersInGroup'), 'interwikiMap' => array($this, 'interwikiMap')); $info = array('siteName' => $GLOBALS['wgSitename'], 'server' => $GLOBALS['wgServer'], 'scriptPath' => $GLOBALS['wgScriptPath'], 'stylePath' => $GLOBALS['wgStylePath'], 'currentVersion' => SpecialVersion::getVersion()); if (!self::$namespacesCache || self::$namespacesCacheLang !== $wgContLang->getCode()) { $namespaces = array(); $namespacesByName = array(); foreach ($wgContLang->getFormattedNamespaces() as $ns => $title) { $canonical = MWNamespace::getCanonicalName($ns); $namespaces[$ns] = array('id' => $ns, 'name' => $title, 'canonicalName' => strtr($canonical, '_', ' '), 'hasSubpages' => MWNamespace::hasSubpages($ns), 'hasGenderDistinction' => MWNamespace::hasGenderDistinction($ns), 'isCapitalized' => MWNamespace::isCapitalized($ns), 'isContent' => MWNamespace::isContent($ns), 'isIncludable' => !MWNamespace::isNonincludable($ns), 'isMovable' => MWNamespace::isMovable($ns), 'isSubject' => MWNamespace::isSubject($ns), 'isTalk' => MWNamespace::isTalk($ns), 'defaultContentModel' => MWNamespace::getNamespaceContentModel($ns), 'aliases' => array()); if ($ns >= NS_MAIN) { $namespaces[$ns]['subject'] = MWNamespace::getSubject($ns); $namespaces[$ns]['talk'] = MWNamespace::getTalk($ns); $namespaces[$ns]['associated'] = MWNamespace::getAssociated($ns); } else { $namespaces[$ns]['subject'] = $ns; } $namespacesByName[strtr($title, ' ', '_')] = $ns; if ($canonical) { $namespacesByName[$canonical] = $ns; } } $aliases = array_merge($wgNamespaceAliases, $wgContLang->getNamespaceAliases()); foreach ($aliases as $title => $ns) { if (!isset($namespacesByName[$title]) && isset($namespaces[$ns])) { $ct = count($namespaces[$ns]['aliases']); $namespaces[$ns]['aliases'][$ct + 1] = $title; $namespacesByName[$title] = $ns; } } $namespaces[NS_MAIN]['displayName'] = wfMessage('blanknamespace')->inContentLanguage()->text(); self::$namespacesCache = $namespaces; self::$namespacesCacheLang = $wgContLang->getCode(); } $info['namespaces'] = self::$namespacesCache; $info['stats'] = array('pages' => (int) SiteStats::pages(), 'articles' => (int) SiteStats::articles(), 'files' => (int) SiteStats::images(), 'edits' => (int) SiteStats::edits(), 'views' => $wgDisableCounters ? null : (int) SiteStats::views(), 'users' => (int) SiteStats::users(), 'activeUsers' => (int) SiteStats::activeUsers(), 'admins' => (int) SiteStats::numberingroup('sysop')); return $this->getEngine()->registerInterface('mw.site.lua', $lib, $info); }
/** * Return the text of a template, after recursively * replacing any variables or templates within the template. * * @param array $piece The parts of the template * $piece['title']: the title, i.e. the part before the | * $piece['parts']: the parameter array * $piece['lineStart']: whether the brace was at the start of a line * @param PPFrame $frame The current frame, contains template arguments * @throws MWException * @return string The text of the template * @private */ function braceSubstitution($piece, $frame) { wfProfileIn(__METHOD__); wfProfileIn(__METHOD__ . '-setup'); # Flags $found = false; # $text has been filled $nowiki = false; # wiki markup in $text should be escaped $isHTML = false; # $text is HTML, armour it against wikitext transformation $forceRawInterwiki = false; # Force interwiki transclusion to be done in raw mode not rendered $isChildObj = false; # $text is a DOM node needing expansion in a child frame $isLocalObj = false; # $text is a DOM node needing expansion in the current frame # Title object, where $text came from $title = false; # $part1 is the bit before the first |, and must contain only title characters. # Various prefixes will be stripped from it later. $titleWithSpaces = $frame->expand($piece['title']); $part1 = trim($titleWithSpaces); $titleText = false; # Original title text preserved for various purposes $originalTitle = $part1; # $args is a list of argument nodes, starting from index 0, not including $part1 # @todo FIXME: If piece['parts'] is null then the call to getLength() below won't work b/c this $args isn't an object $args = null == $piece['parts'] ? array() : $piece['parts']; wfProfileOut(__METHOD__ . '-setup'); $titleProfileIn = null; // profile templates # SUBST wfProfileIn(__METHOD__ . '-modifiers'); if (!$found) { $substMatch = $this->mSubstWords->matchStartAndRemove($part1); # Possibilities for substMatch: "subst", "safesubst" or FALSE # Decide whether to expand template or keep wikitext as-is. if ($this->ot['wiki']) { if ($substMatch === false) { $literal = true; # literal when in PST with no prefix } else { $literal = false; # expand when in PST with subst: or safesubst: } } else { if ($substMatch == 'subst') { $literal = true; # literal when not in PST with plain subst: } else { $literal = false; # expand when not in PST with safesubst: or no prefix } } if ($literal) { $text = $frame->virtualBracketedImplode('{{', '|', '}}', $titleWithSpaces, $args); $isLocalObj = true; $found = true; } } # Variables if (!$found && $args->getLength() == 0) { $id = $this->mVariables->matchStartToEnd($part1); if ($id !== false) { $text = $this->getVariableValue($id, $frame); if (MagicWord::getCacheTTL($id) > -1) { $this->mOutput->updateCacheExpiry(MagicWord::getCacheTTL($id)); } $found = true; } } # MSG, MSGNW and RAW if (!$found) { # Check for MSGNW: $mwMsgnw = MagicWord::get('msgnw'); if ($mwMsgnw->matchStartAndRemove($part1)) { $nowiki = true; } else { # Remove obsolete MSG: $mwMsg = MagicWord::get('msg'); $mwMsg->matchStartAndRemove($part1); } # Check for RAW: $mwRaw = MagicWord::get('raw'); if ($mwRaw->matchStartAndRemove($part1)) { $forceRawInterwiki = true; } } wfProfileOut(__METHOD__ . '-modifiers'); # Parser functions if (!$found) { wfProfileIn(__METHOD__ . '-pfunc'); $colonPos = strpos($part1, ':'); if ($colonPos !== false) { $func = substr($part1, 0, $colonPos); $funcArgs = array(trim(substr($part1, $colonPos + 1))); for ($i = 0; $i < $args->getLength(); $i++) { $funcArgs[] = $args->item($i); } try { $result = $this->callParserFunction($frame, $func, $funcArgs); } catch (Exception $ex) { wfProfileOut(__METHOD__ . '-pfunc'); wfProfileOut(__METHOD__); throw $ex; } # The interface for parser functions allows for extracting # flags into the local scope. Extract any forwarded flags # here. extract($result); } wfProfileOut(__METHOD__ . '-pfunc'); } # Finish mangling title and then check for loops. # Set $title to a Title object and $titleText to the PDBK if (!$found) { $ns = NS_TEMPLATE; # Split the title into page and subpage $subpage = ''; $relative = $this->maybeDoSubpageLink($part1, $subpage); if ($part1 !== $relative) { $part1 = $relative; $ns = $this->mTitle->getNamespace(); } $title = Title::newFromText($part1, $ns); if ($title) { $titleText = $title->getPrefixedText(); # Check for language variants if the template is not found if ($this->getConverterLanguage()->hasVariants() && $title->getArticleID() == 0) { $this->getConverterLanguage()->findVariantLink($part1, $title, true); } # Do recursion depth check $limit = $this->mOptions->getMaxTemplateDepth(); if ($frame->depth >= $limit) { $found = true; $text = '<span class="error">' . wfMessage('parser-template-recursion-depth-warning')->numParams($limit)->inContentLanguage()->text() . '</span>'; } } } # Load from database if (!$found && $title) { if (!Profiler::instance()->isPersistent()) { # Too many unique items can kill profiling DBs/collectors $titleProfileIn = __METHOD__ . "-title-" . $title->getPrefixedDBkey(); wfProfileIn($titleProfileIn); // template in } wfProfileIn(__METHOD__ . '-loadtpl'); if (!$title->isExternal()) { if ($title->isSpecialPage() && $this->mOptions->getAllowSpecialInclusion() && $this->ot['html']) { // Pass the template arguments as URL parameters. // "uselang" will have no effect since the Language object // is forced to the one defined in ParserOptions. $pageArgs = array(); for ($i = 0; $i < $args->getLength(); $i++) { $bits = $args->item($i)->splitArg(); if (strval($bits['index']) === '') { $name = trim($frame->expand($bits['name'], PPFrame::STRIP_COMMENTS)); $value = trim($frame->expand($bits['value'])); $pageArgs[$name] = $value; } } // Create a new context to execute the special page $context = new RequestContext(); $context->setTitle($title); $context->setRequest(new FauxRequest($pageArgs)); $context->setUser($this->getUser()); $context->setLanguage($this->mOptions->getUserLangObj()); $ret = SpecialPageFactory::capturePath($title, $context); if ($ret) { $text = $context->getOutput()->getHTML(); $this->mOutput->addOutputPageMetadata($context->getOutput()); $found = true; $isHTML = true; $this->disableCache(); } } elseif (MWNamespace::isNonincludable($title->getNamespace())) { $found = false; # access denied wfDebug(__METHOD__ . ": template inclusion denied for " . $title->getPrefixedDBkey() . "\n"); } else { list($text, $title) = $this->getTemplateDom($title); if ($text !== false) { $found = true; $isChildObj = true; } } # If the title is valid but undisplayable, make a link to it if (!$found && ($this->ot['html'] || $this->ot['pre'])) { $text = "[[:{$titleText}]]"; $found = true; } } elseif ($title->isTrans()) { # Interwiki transclusion if ($this->ot['html'] && !$forceRawInterwiki) { $text = $this->interwikiTransclude($title, 'render'); $isHTML = true; } else { $text = $this->interwikiTransclude($title, 'raw'); # Preprocess it like a template $text = $this->preprocessToDom($text, self::PTD_FOR_INCLUSION); $isChildObj = true; } $found = true; } # Do infinite loop check # This has to be done after redirect resolution to avoid infinite loops via redirects if (!$frame->loopCheck($title)) { $found = true; $text = '<span class="error">' . wfMessage('parser-template-loop-warning', $titleText)->inContentLanguage()->text() . '</span>'; wfDebug(__METHOD__ . ": template loop broken at '{$titleText}'\n"); } wfProfileOut(__METHOD__ . '-loadtpl'); } # If we haven't found text to substitute by now, we're done # Recover the source wikitext and return it if (!$found) { $text = $frame->virtualBracketedImplode('{{', '|', '}}', $titleWithSpaces, $args); if ($titleProfileIn) { wfProfileOut($titleProfileIn); // template out } wfProfileOut(__METHOD__); return array('object' => $text); } # Expand DOM-style return values in a child frame if ($isChildObj) { # Clean up argument array $newFrame = $frame->newChild($args, $title); if ($nowiki) { $text = $newFrame->expand($text, PPFrame::RECOVER_ORIG); } elseif ($titleText !== false && $newFrame->isEmpty()) { # Expansion is eligible for the empty-frame cache if (isset($this->mTplExpandCache[$titleText])) { $text = $this->mTplExpandCache[$titleText]; } else { $text = $newFrame->expand($text); $this->mTplExpandCache[$titleText] = $text; } } else { # Uncached expansion $text = $newFrame->expand($text); } } if ($isLocalObj && $nowiki) { $text = $frame->expand($text, PPFrame::RECOVER_ORIG); $isLocalObj = false; } if ($titleProfileIn) { wfProfileOut($titleProfileIn); // template out } # Replace raw HTML by a placeholder if ($isHTML) { $text = $this->insertStripItem($text); } elseif ($nowiki && ($this->ot['html'] || $this->ot['pre'])) { # Escape nowiki-style return values $text = wfEscapeWikiText($text); } elseif (is_string($text) && !$piece['lineStart'] && preg_match('/^(?:{\\||:|;|#|\\*)/', $text)) { # Bug 529: if the template begins with a table or block-level # element, it should be treated as beginning a new line. # This behavior is somewhat controversial. $text = "\n" . $text; } if (is_string($text) && !$this->incrementIncludeSize('post-expand', strlen($text))) { # Error, oversize inclusion if ($titleText !== false) { # Make a working, properly escaped link if possible (bug 23588) $text = "[[:{$titleText}]]"; } else { # This will probably not be a working link, but at least it may # provide some hint of where the problem is preg_replace('/^:/', '', $originalTitle); $text = "[[:{$originalTitle}]]"; } $text .= $this->insertStripItem('<!-- WARNING: template omitted, post-expand include size too large -->'); $this->limitationWarn('post-expand-template-inclusion'); } if ($isLocalObj) { $ret = array('object' => $text); } else { $ret = array('text' => $text); } wfProfileOut(__METHOD__); return $ret; }
/** * @covers MWNamespace::isNonincludable */ public function testIsNonincludable() { global $wgNonincludableNamespaces; $wgNonincludableNamespaces = array(NS_USER); $this->assertTrue(MWNamespace::isNonincludable(NS_USER)); $this->assertFalse(MWNamespace::isNonincludable(NS_TEMPLATE)); }
protected function appendNamespaces($property) { global $wgContLang; $data = array(); foreach ($wgContLang->getFormattedNamespaces() as $ns => $title) { $data[$ns] = array('id' => intval($ns), 'case' => MWNamespace::isCapitalized($ns) ? 'first-letter' : 'case-sensitive'); ApiResult::setContent($data[$ns], $title); $canonical = MWNamespace::getCanonicalName($ns); if (MWNamespace::hasSubpages($ns)) { $data[$ns]['subpages'] = ''; } if ($canonical) { $data[$ns]['canonical'] = strtr($canonical, '_', ' '); } if (MWNamespace::isContent($ns)) { $data[$ns]['content'] = ''; } if (MWNamespace::isNonincludable($ns)) { $data[$ns]['nonincludable'] = ''; } $contentmodel = MWNamespace::getNamespaceContentModel($ns); if ($contentmodel) { $data[$ns]['defaultcontentmodel'] = $contentmodel; } } $this->getResult()->setIndexedTagName($data, 'ns'); return $this->getResult()->addValue('query', $property, $data); }
/** * Handler for expandTemplate() */ function expandTemplate($frameId, $titleText, $args) { $frame = $this->getFrameById($frameId); $title = Title::newFromText($titleText, NS_TEMPLATE); if (!$title) { throw new Scribunto_LuaError("expandTemplate: invalid title \"{$titleText}\""); } if ($frame->depth >= $this->parser->mOptions->getMaxTemplateDepth()) { throw new Scribunto_LuaError('expandTemplate: template depth limit exceeded'); } if (MWNamespace::isNonincludable($title->getNamespace())) { throw new Scribunto_LuaError('expandTemplate: template inclusion denied'); } list($dom, $finalTitle) = $this->parser->getTemplateDom($title); if ($dom === false) { throw new Scribunto_LuaError("expandTemplate: template \"{$titleText}\" does not exist"); } if (!$frame->loopCheck($finalTitle)) { throw new Scribunto_LuaError('expandTemplate: template loop detected'); } $fargs = $this->getParser()->getPreprocessor()->newPartNodeArray($args); $newFrame = $frame->newChild($fargs, $finalTitle); $text = $this->doCachedExpansion($newFrame, $dom, array('template' => $finalTitle->getPrefixedDBkey(), 'args' => $args)); return array($text); }