/**
  * @covers Message::__construct
  * @covers Message::params
  */
 public function testDeliciouslyManyParams()
 {
     $msg = new RawMessage('$1$2$3$4$5$6$7$8$9$10$11$12');
     // One less than above has placeholders
     $params = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k');
     $this->assertEquals('abcdefghijka2', $msg->params($params)->plain(), 'Params > 9 are replaced correctly');
 }
Exemple #2
0
 /**
  * Process the wikitext for the "?preload=" feature. (bug 5210)
  *
  * "<noinclude>", "<includeonly>" etc. are parsed as for template
  * transclusion, comments, templates, arguments, tags hooks and parser
  * functions are untouched.
  *
  * @param $text String
  * @param $title Title
  * @param $options ParserOptions
  * @param $params Array
  * @return String
  */
 public function getPreloadText($text, Title $title, ParserOptions $options, $params = array())
 {
     $msg = new RawMessage($text);
     $text = $msg->params($params)->plain();
     # Parser (re)initialisation
     $this->startParse($title, $options, self::OT_PLAIN, true);
     $flags = PPFrame::NO_ARGS | PPFrame::NO_TEMPLATES;
     $dom = $this->preprocessToDom($text, self::PTD_FOR_INCLUSION);
     $text = $this->getPreprocessor()->newFrame()->expand($dom, $flags);
     $text = $this->mStripState->unstripBoth($text);
     return $text;
 }
Exemple #3
0
 /**
  * Get the error list as a Message object
  *
  * @param string|string[] $shortContext A short enclosing context message name (or an array of
  * message names), to be used when there is a single error.
  * @param string|string[] $longContext A long enclosing context message name (or an array of
  * message names), for a list.
  *
  * @return Message
  */
 public function getMessage($shortContext = false, $longContext = false)
 {
     $rawErrors = $this->sv->getErrors();
     if (count($rawErrors) == 0) {
         if ($this->sv->isOK()) {
             $this->sv->fatal('internalerror_info', __METHOD__ . " called for a good result, this is incorrect\n");
         } else {
             $this->sv->fatal('internalerror_info', __METHOD__ . ": Invalid result object: no error text but not OK\n");
         }
         $rawErrors = $this->sv->getErrors();
         // just added a fatal
     }
     if (count($rawErrors) == 1) {
         $s = $this->getErrorMessage($rawErrors[0]);
         if ($shortContext) {
             $s = wfMessage($shortContext, $s);
         } elseif ($longContext) {
             $wrapper = new RawMessage("* \$1\n");
             $wrapper->params($s)->parse();
             $s = wfMessage($longContext, $wrapper);
         }
     } else {
         $msgs = $this->getErrorMessageArray($rawErrors);
         $msgCount = count($msgs);
         if ($shortContext) {
             $msgCount++;
         }
         $s = new RawMessage('* $' . implode("\n* \$", range(1, $msgCount)));
         $s->params($msgs)->parse();
         if ($longContext) {
             $s = wfMessage($longContext, $s);
         } elseif ($shortContext) {
             $wrapper = new RawMessage("\n\$1\n", $s);
             $wrapper->parse();
             $s = wfMessage($shortContext, $wrapper);
         }
     }
     return $s;
 }
Exemple #4
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;
 }
Exemple #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;
 }
Exemple #6
0
 /**
  * @covers Message::params
  * @covers Message::toString
  * @covers Message::replaceParameters
  */
 public function testReplaceManyParams()
 {
     $msg = new RawMessage('$1$2$3$4$5$6$7$8$9$10$11$12');
     // One less than above has placeholders
     $params = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'];
     $this->assertEquals('abcdefghijka2', $msg->params($params)->plain(), 'Params > 9 are replaced correctly');
     $msg = new RawMessage('Params$*');
     $params = ['ab', 'bc', 'cd'];
     $this->assertEquals('Params: ab, bc, cd', $msg->params($params)->text());
 }
Exemple #7
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(
			# french spaces, last one Guillemet-left
			# only if there is something before the space
			'/(.) (?=\\?|:|;|!|%|\\302\\273)/' => '\\1&#160;',
			# french spaces, Guillemet-right
			'/(\\302\\253) /' => '\\1&#160;',
			'/&#160;(!\s*important)/' => ' \\1', # Beware of CSS magic word !important, bug #11874.
		);
		$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(
				# ''Something [http://www.cool.com cool''] -->
				# <i>Something</i><a href="http://www.cool.com"..><i>cool></i></a>
				'/(<([bi])>)(<([bi])>)?([^<]*)(<\/?a[^<]*>)([^<]*)(<\/\\4>)?(<\/\\2>)/' =>
				'\\1\\3\\5\\8\\9\\6\\1\\3\\7\\8\\9',
				# fix up an anchor inside another anchor, only
				# at least for a single single nested link (bug 3695)
				'/(<a[^>]+>)([^<]*)(<a[^>]+>[^<]*)<\/a>(.*)<\/a>/' =>
				'\\1\\2</a>\\3</a>\\1\\4</a>',
				# fix div inside inline elements- doBlockLevels won't wrap a line which
				# contains a div, so fix it up here; replace
				# div with escaped text
				'/(<([aib]) [^>]+>)([^<]*)(<div([^>]*)>)(.*)(<\/div>)([^<]*)(<\/\\2>)/' =>
				'\\1\\3&lt;div\\5&gt;\\6&lt;/div&gt;\\8\\9',
				# remove empty italic or bold tag pairs, some
				# introduced by rules above
				'/<([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;
	}
Exemple #8
0
 public static function from(RawMessage $message)
 {
     return new static($message->nickname(), $message->username(), $message->hostname(), $message->serverName(), $message->command(), $message->params());
 }