示例#1
0
 /**
  * Convert wikitext to HTML
  * Do not call this function recursively.
  *
  * @param string $text text we want to parse
  * @param $title Title object
  * @param $options ParserOptions
  * @param $linestart boolean
  * @param $clearState boolean
  * @param int $revid number to pass in {{REVISIONID}}
  * @return ParserOutput a ParserOutput
  */
 public function parse($text, Title $title, ParserOptions $options, $linestart = true, $clearState = true, $revid = null)
 {
     /**
      * First pass--just handle <nowiki> sections, pass the rest off
      * to internalParse() which does all the real work.
      */
     global $wgUseTidy, $wgAlwaysUseTidy, $wgShowHostnames;
     $fname = __METHOD__ . '-' . wfGetCaller();
     wfProfileIn(__METHOD__);
     wfProfileIn($fname);
     $this->startParse($title, $options, self::OT_HTML, $clearState);
     $this->mInputSize = strlen($text);
     if ($this->mOptions->getEnableLimitReport()) {
         $this->mOutput->resetParseStartTime();
     }
     # Remove the strip marker tag prefix from the input, if present.
     if ($clearState) {
         $text = str_replace($this->mUniqPrefix, '', $text);
     }
     $oldRevisionId = $this->mRevisionId;
     $oldRevisionObject = $this->mRevisionObject;
     $oldRevisionTimestamp = $this->mRevisionTimestamp;
     $oldRevisionUser = $this->mRevisionUser;
     $oldRevisionSize = $this->mRevisionSize;
     if ($revid !== null) {
         $this->mRevisionId = $revid;
         $this->mRevisionObject = null;
         $this->mRevisionTimestamp = null;
         $this->mRevisionUser = null;
         $this->mRevisionSize = null;
     }
     wfRunHooks('ParserBeforeStrip', array(&$this, &$text, &$this->mStripState));
     # No more strip!
     wfRunHooks('ParserAfterStrip', array(&$this, &$text, &$this->mStripState));
     $text = $this->internalParse($text);
     wfRunHooks('ParserAfterParse', array(&$this, &$text, &$this->mStripState));
     $text = $this->mStripState->unstripGeneral($text);
     # Clean up special characters, only run once, next-to-last before doBlockLevels
     $fixtags = array('/(.) (?=\\?|:|;|!|%|\\302\\273)/' => '\\1&#160;', '/(\\302\\253) /' => '\\1&#160;', '/&#160;(!\\s*important)/' => ' \\1');
     $text = preg_replace(array_keys($fixtags), array_values($fixtags), $text);
     $text = $this->doBlockLevels($text, $linestart);
     $this->replaceLinkHolders($text);
     /**
      * The input doesn't get language converted if
      * a) It's disabled
      * b) Content isn't converted
      * c) It's a conversion table
      * d) it is an interface message (which is in the user language)
      */
     if (!($options->getDisableContentConversion() || isset($this->mDoubleUnderscores['nocontentconvert']))) {
         if (!$this->mOptions->getInterfaceMessage()) {
             # The position of the convert() call should not be changed. it
             # assumes that the links are all replaced and the only thing left
             # is the <nowiki> mark.
             $text = $this->getConverterLanguage()->convert($text);
         }
     }
     /**
      * A converted title will be provided in the output object if title and
      * content conversion are enabled, the article text does not contain
      * a conversion-suppressing double-underscore tag, and no
      * {{DISPLAYTITLE:...}} is present. DISPLAYTITLE takes precedence over
      * automatic link conversion.
      */
     if (!($options->getDisableTitleConversion() || isset($this->mDoubleUnderscores['nocontentconvert']) || isset($this->mDoubleUnderscores['notitleconvert']) || $this->mOutput->getDisplayTitle() !== false)) {
         $convruletitle = $this->getConverterLanguage()->getConvRuleTitle();
         if ($convruletitle) {
             $this->mOutput->setTitleText($convruletitle);
         } else {
             $titleText = $this->getConverterLanguage()->convertTitle($title);
             $this->mOutput->setTitleText($titleText);
         }
     }
     $text = $this->mStripState->unstripNoWiki($text);
     wfRunHooks('ParserBeforeTidy', array(&$this, &$text));
     $text = $this->replaceTransparentTags($text);
     $text = $this->mStripState->unstripGeneral($text);
     $text = Sanitizer::normalizeCharReferences($text);
     if ($wgUseTidy && $this->mOptions->getTidy() || $wgAlwaysUseTidy) {
         $text = MWTidy::tidy($text);
     } else {
         # attempt to sanitize at least some nesting problems
         # (bug #2702 and quite a few others)
         $tidyregs = array('/(<([bi])>)(<([bi])>)?([^<]*)(<\\/?a[^<]*>)([^<]*)(<\\/\\4>)?(<\\/\\2>)/' => '\\1\\3\\5\\8\\9\\6\\1\\3\\7\\8\\9', '/(<a[^>]+>)([^<]*)(<a[^>]+>[^<]*)<\\/a>(.*)<\\/a>/' => '\\1\\2</a>\\3</a>\\1\\4</a>', '/(<([aib]) [^>]+>)([^<]*)(<div([^>]*)>)(.*)(<\\/div>)([^<]*)(<\\/\\2>)/' => '\\1\\3&lt;div\\5&gt;\\6&lt;/div&gt;\\8\\9', '/<([bi])><\\/\\1>/' => '');
         $text = preg_replace(array_keys($tidyregs), array_values($tidyregs), $text);
     }
     if ($this->mExpensiveFunctionCount > $this->mOptions->getExpensiveParserFunctionLimit()) {
         $this->limitationWarn('expensive-parserfunction', $this->mExpensiveFunctionCount, $this->mOptions->getExpensiveParserFunctionLimit());
     }
     wfRunHooks('ParserAfterTidy', array(&$this, &$text));
     # Information on include size limits, for the benefit of users who try to skirt them
     if ($this->mOptions->getEnableLimitReport()) {
         $max = $this->mOptions->getMaxIncludeSize();
         $cpuTime = $this->mOutput->getTimeSinceStart('cpu');
         if ($cpuTime !== null) {
             $this->mOutput->setLimitReportData('limitreport-cputime', sprintf("%.3f", $cpuTime));
         }
         $wallTime = $this->mOutput->getTimeSinceStart('wall');
         $this->mOutput->setLimitReportData('limitreport-walltime', sprintf("%.3f", $wallTime));
         $this->mOutput->setLimitReportData('limitreport-ppvisitednodes', array($this->mPPNodeCount, $this->mOptions->getMaxPPNodeCount()));
         $this->mOutput->setLimitReportData('limitreport-ppgeneratednodes', array($this->mGeneratedPPNodeCount, $this->mOptions->getMaxGeneratedPPNodeCount()));
         $this->mOutput->setLimitReportData('limitreport-postexpandincludesize', array($this->mIncludeSizes['post-expand'], $max));
         $this->mOutput->setLimitReportData('limitreport-templateargumentsize', array($this->mIncludeSizes['arg'], $max));
         $this->mOutput->setLimitReportData('limitreport-expansiondepth', array($this->mHighestExpansionDepth, $this->mOptions->getMaxPPExpandDepth()));
         $this->mOutput->setLimitReportData('limitreport-expensivefunctioncount', array($this->mExpensiveFunctionCount, $this->mOptions->getExpensiveParserFunctionLimit()));
         wfRunHooks('ParserLimitReportPrepare', array($this, $this->mOutput));
         $limitReport = "NewPP limit report\n";
         if ($wgShowHostnames) {
             $limitReport .= 'Parsed by ' . wfHostname() . "\n";
         }
         foreach ($this->mOutput->getLimitReportData() as $key => $value) {
             if (wfRunHooks('ParserLimitReportFormat', array($key, &$value, &$limitReport, false, false))) {
                 $keyMsg = wfMessage($key)->inLanguage('en')->useDatabase(false);
                 $valueMsg = wfMessage(array("{$key}-value-text", "{$key}-value"))->inLanguage('en')->useDatabase(false);
                 if (!$valueMsg->exists()) {
                     $valueMsg = new RawMessage('$1');
                 }
                 if (!$keyMsg->isDisabled() && !$valueMsg->isDisabled()) {
                     $valueMsg->params($value);
                     $limitReport .= "{$keyMsg->text()}: {$valueMsg->text()}\n";
                 }
             }
         }
         // Since we're not really outputting HTML, decode the entities and
         // then re-encode the things that need hiding inside HTML comments.
         $limitReport = htmlspecialchars_decode($limitReport);
         wfRunHooks('ParserLimitReport', array($this, &$limitReport));
         // Sanitize for comment. Note '‐' in the replacement is U+2010,
         // which looks much like the problematic '-'.
         $limitReport = str_replace(array('-', '&'), array('‐', '&amp;'), $limitReport);
         $text .= "\n<!-- \n{$limitReport}-->\n";
         if ($this->mGeneratedPPNodeCount > $this->mOptions->getMaxGeneratedPPNodeCount() / 10) {
             wfDebugLog('generated-pp-node-count', $this->mGeneratedPPNodeCount . ' ' . $this->mTitle->getPrefixedDBkey());
         }
     }
     $this->mOutput->setText($text);
     $this->mRevisionId = $oldRevisionId;
     $this->mRevisionObject = $oldRevisionObject;
     $this->mRevisionTimestamp = $oldRevisionTimestamp;
     $this->mRevisionUser = $oldRevisionUser;
     $this->mRevisionSize = $oldRevisionSize;
     $this->mInputSize = false;
     wfProfileOut($fname);
     wfProfileOut(__METHOD__);
     return $this->mOutput;
 }
示例#2
0
 /**
  * Convert wikitext to HTML
  * Do not call this function recursively.
  *
  * @param string $text Text we want to parse
  * @param Title $title
  * @param ParserOptions $options
  * @param bool $linestart
  * @param bool $clearState
  * @param int $revid Number to pass in {{REVISIONID}}
  * @return ParserOutput A ParserOutput
  */
 public function parse($text, Title $title, ParserOptions $options, $linestart = true, $clearState = true, $revid = null)
 {
     /**
      * First pass--just handle <nowiki> sections, pass the rest off
      * to internalParse() which does all the real work.
      */
     global $wgShowHostnames;
     if ($clearState) {
         // We use U+007F DELETE to construct strip markers, so we have to make
         // sure that this character does not occur in the input text.
         $text = strtr($text, "", "?");
         $magicScopeVariable = $this->lock();
     }
     $this->startParse($title, $options, self::OT_HTML, $clearState);
     $this->currentRevisionCache = null;
     $this->mInputSize = strlen($text);
     if ($this->mOptions->getEnableLimitReport()) {
         $this->mOutput->resetParseStartTime();
     }
     $oldRevisionId = $this->mRevisionId;
     $oldRevisionObject = $this->mRevisionObject;
     $oldRevisionTimestamp = $this->mRevisionTimestamp;
     $oldRevisionUser = $this->mRevisionUser;
     $oldRevisionSize = $this->mRevisionSize;
     if ($revid !== null) {
         $this->mRevisionId = $revid;
         $this->mRevisionObject = null;
         $this->mRevisionTimestamp = null;
         $this->mRevisionUser = null;
         $this->mRevisionSize = null;
     }
     Hooks::run('ParserBeforeStrip', array(&$this, &$text, &$this->mStripState));
     # No more strip!
     Hooks::run('ParserAfterStrip', array(&$this, &$text, &$this->mStripState));
     $text = $this->internalParse($text);
     Hooks::run('ParserAfterParse', array(&$this, &$text, &$this->mStripState));
     $text = $this->internalParseHalfParsed($text, true, $linestart);
     /**
      * A converted title will be provided in the output object if title and
      * content conversion are enabled, the article text does not contain
      * a conversion-suppressing double-underscore tag, and no
      * {{DISPLAYTITLE:...}} is present. DISPLAYTITLE takes precedence over
      * automatic link conversion.
      */
     if (!($options->getDisableTitleConversion() || isset($this->mDoubleUnderscores['nocontentconvert']) || isset($this->mDoubleUnderscores['notitleconvert']) || $this->mOutput->getDisplayTitle() !== false)) {
         $convruletitle = $this->getConverterLanguage()->getConvRuleTitle();
         if ($convruletitle) {
             $this->mOutput->setTitleText($convruletitle);
         } else {
             $titleText = $this->getConverterLanguage()->convertTitle($title);
             $this->mOutput->setTitleText($titleText);
         }
     }
     if ($this->mExpensiveFunctionCount > $this->mOptions->getExpensiveParserFunctionLimit()) {
         $this->limitationWarn('expensive-parserfunction', $this->mExpensiveFunctionCount, $this->mOptions->getExpensiveParserFunctionLimit());
     }
     # Information on include size limits, for the benefit of users who try to skirt them
     if ($this->mOptions->getEnableLimitReport()) {
         $max = $this->mOptions->getMaxIncludeSize();
         $cpuTime = $this->mOutput->getTimeSinceStart('cpu');
         if ($cpuTime !== null) {
             $this->mOutput->setLimitReportData('limitreport-cputime', sprintf("%.3f", $cpuTime));
         }
         $wallTime = $this->mOutput->getTimeSinceStart('wall');
         $this->mOutput->setLimitReportData('limitreport-walltime', sprintf("%.3f", $wallTime));
         $this->mOutput->setLimitReportData('limitreport-ppvisitednodes', array($this->mPPNodeCount, $this->mOptions->getMaxPPNodeCount()));
         $this->mOutput->setLimitReportData('limitreport-ppgeneratednodes', array($this->mGeneratedPPNodeCount, $this->mOptions->getMaxGeneratedPPNodeCount()));
         $this->mOutput->setLimitReportData('limitreport-postexpandincludesize', array($this->mIncludeSizes['post-expand'], $max));
         $this->mOutput->setLimitReportData('limitreport-templateargumentsize', array($this->mIncludeSizes['arg'], $max));
         $this->mOutput->setLimitReportData('limitreport-expansiondepth', array($this->mHighestExpansionDepth, $this->mOptions->getMaxPPExpandDepth()));
         $this->mOutput->setLimitReportData('limitreport-expensivefunctioncount', array($this->mExpensiveFunctionCount, $this->mOptions->getExpensiveParserFunctionLimit()));
         Hooks::run('ParserLimitReportPrepare', array($this, $this->mOutput));
         $limitReport = "NewPP limit report\n";
         if ($wgShowHostnames) {
             $limitReport .= 'Parsed by ' . wfHostname() . "\n";
         }
         $limitReport .= 'Cached time: ' . $this->mOutput->getCacheTime() . "\n";
         $limitReport .= 'Cache expiry: ' . $this->mOutput->getCacheExpiry() . "\n";
         $limitReport .= 'Dynamic content: ' . ($this->mOutput->hasDynamicContent() ? 'true' : 'false') . "\n";
         foreach ($this->mOutput->getLimitReportData() as $key => $value) {
             if (Hooks::run('ParserLimitReportFormat', array($key, &$value, &$limitReport, false, false))) {
                 $keyMsg = wfMessage($key)->inLanguage('en')->useDatabase(false);
                 $valueMsg = wfMessage(array("{$key}-value-text", "{$key}-value"))->inLanguage('en')->useDatabase(false);
                 if (!$valueMsg->exists()) {
                     $valueMsg = new RawMessage('$1');
                 }
                 if (!$keyMsg->isDisabled() && !$valueMsg->isDisabled()) {
                     $valueMsg->params($value);
                     $limitReport .= "{$keyMsg->text()}: {$valueMsg->text()}\n";
                 }
             }
         }
         // Since we're not really outputting HTML, decode the entities and
         // then re-encode the things that need hiding inside HTML comments.
         $limitReport = htmlspecialchars_decode($limitReport);
         Hooks::run('ParserLimitReport', array($this, &$limitReport));
         // Sanitize for comment. Note '‐' in the replacement is U+2010,
         // which looks much like the problematic '-'.
         $limitReport = str_replace(array('-', '&'), array('‐', '&amp;'), $limitReport);
         $text .= "\n<!-- \n{$limitReport}-->\n";
         // Add on template profiling data
         $dataByFunc = $this->mProfiler->getFunctionStats();
         uasort($dataByFunc, function ($a, $b) {
             return $a['real'] < $b['real'];
             // descending order
         });
         $profileReport = "Transclusion expansion time report (%,ms,calls,template)\n";
         foreach (array_slice($dataByFunc, 0, 10) as $item) {
             $profileReport .= sprintf("%6.2f%% %8.3f %6d - %s\n", $item['%real'], $item['real'], $item['calls'], htmlspecialchars($item['name']));
         }
         $text .= "\n<!-- \n{$profileReport}-->\n";
         if ($this->mGeneratedPPNodeCount > $this->mOptions->getMaxGeneratedPPNodeCount() / 10) {
             wfDebugLog('generated-pp-node-count', $this->mGeneratedPPNodeCount . ' ' . $this->mTitle->getPrefixedDBkey());
         }
     }
     $this->mOutput->setText($text);
     $this->mRevisionId = $oldRevisionId;
     $this->mRevisionObject = $oldRevisionObject;
     $this->mRevisionTimestamp = $oldRevisionTimestamp;
     $this->mRevisionUser = $oldRevisionUser;
     $this->mRevisionSize = $oldRevisionSize;
     $this->mInputSize = false;
     $this->currentRevisionCache = null;
     return $this->mOutput;
 }
示例#3
0
 /**
  * Get the Limit report for page previews
  *
  * @since 1.22
  * @param ParserOutput $output ParserOutput object from the parse
  * @return string HTML
  */
 public static function getPreviewLimitReport($output)
 {
     if (!$output || !$output->getLimitReportData()) {
         return '';
     }
     wfProfileIn(__METHOD__);
     $limitReport = Html::rawElement('div', array('class' => 'mw-limitReportExplanation'), wfMessage('limitreport-title')->parseAsBlock());
     // Show/hide animation doesn't work correctly on a table, so wrap it in a div.
     $limitReport .= Html::openElement('div', array('class' => 'preview-limit-report-wrapper'));
     $limitReport .= Html::openElement('table', array('class' => 'preview-limit-report wikitable')) . Html::openElement('tbody');
     foreach ($output->getLimitReportData() as $key => $value) {
         if (wfRunHooks('ParserLimitReportFormat', array($key, &$value, &$limitReport, true, true))) {
             $keyMsg = wfMessage($key);
             $valueMsg = wfMessage(array("{$key}-value-html", "{$key}-value"));
             if (!$valueMsg->exists()) {
                 $valueMsg = new RawMessage('$1');
             }
             if (!$keyMsg->isDisabled() && !$valueMsg->isDisabled()) {
                 $limitReport .= Html::openElement('tr') . Html::rawElement('th', null, $keyMsg->parse()) . Html::rawElement('td', null, $valueMsg->params($value)->parse()) . Html::closeElement('tr');
             }
         }
     }
     $limitReport .= Html::closeElement('tbody') . Html::closeElement('table') . Html::closeElement('div');
     wfProfileOut(__METHOD__);
     return $limitReport;
 }
 /**
  * Propogate if we should create a ToC from ParserOutput -> OutputPage.
  *
  * Its assumed we should create a ToC on the following conditions:
  *  * __NOCOLLABORATIONHUBTOC__ is not on page
  *  * Somebody added parser metadata to the OutputPage (More likely to be a real page)
  *  * The limit report was enabled (More likely to be a real page)
  * These conditions are hacky. Ideally we'd come up with a more
  * robust way of determining if this is really a wikipage.
  *
  * Eventually, the TOC will be output by onOutputPageBeforeHTML hook if this
  * hook signals it is ok.
  *
  * @param $out OutputPage
  * @param $pout ParserOutput
  */
 public static function onOutputPageParserOutput(OutputPage $out, ParserOutput $pout)
 {
     if ($out->getProperty('CollaborationHubSubpage')) {
         // We've already been here, so we can't abort
         // outputting the TOC at this stage.
         wfDebug(__METHOD__ . ' TOC already outputted, possibly incorrectly.');
         return;
     }
     if ($pout->getProperty('nocollaborationhubtoc') !== false) {
         // TOC disabled, mark as done.
         $out->setProperty('CollaborationHubSubpage', true);
     } elseif ($pout->getLimitReportData()) {
         $out->setProperty('CollaborationHubSubpage', "in-progress");
     }
 }
示例#5
0
 /**
  * Get the Limit report for page previews
  *
  * @since 1.22
  * @param ParserOutput $output ParserOutput object from the parse
  * @return string HTML
  */
 public static function getPreviewLimitReport($output)
 {
     if (!$output || !$output->getLimitReportData()) {
         return '';
     }
     $limitReport = Html::rawElement('div', ['class' => 'mw-limitReportExplanation'], wfMessage('limitreport-title')->parseAsBlock());
     // Show/hide animation doesn't work correctly on a table, so wrap it in a div.
     $limitReport .= Html::openElement('div', ['class' => 'preview-limit-report-wrapper']);
     $limitReport .= Html::openElement('table', ['class' => 'preview-limit-report wikitable']) . Html::openElement('tbody');
     foreach ($output->getLimitReportData()['limitreport'] as $key => $value) {
         if (Hooks::run('ParserLimitReportFormat', [$key, &$value, &$limitReport, true, true])) {
             $keyMsg = wfMessage("limitreport-{$key}");
             $valueMsg = wfMessage(["limitreport-{$key}-value-html", "limitreport-{$key}-value"]);
             if (!$valueMsg->exists()) {
                 $valueMsg = new RawMessage('$1');
             }
             if (!$keyMsg->isDisabled() && !$valueMsg->isDisabled()) {
                 // If it's a value/limit array, convert it for $1/$2
                 if (is_array($value) && isset($value['value'])) {
                     $value = [$value['value'], $value['limit']];
                 }
                 $limitReport .= Html::openElement('tr') . Html::rawElement('th', null, $keyMsg->parse()) . Html::rawElement('td', null, $valueMsg->params($value)->parse()) . Html::closeElement('tr');
             }
         }
     }
     $limitReport .= Html::closeElement('tbody') . Html::closeElement('table') . Html::closeElement('div');
     return $limitReport;
 }