function intermediateFunction($level = 2, $n = 0) { if ($n > 0) { return self::intermediateFunction($level, $n - 1); } return wfGetCaller($level); }
/** * Stop profiling of a processor * * @since 1.9 * * @param string $name name of the function we will profile * @param boolean $caller if the caller should be profiled as well */ public static function Out($name = false, $caller = false) { $instance = self::getInstance(); if ($instance instanceof \Profiler) { $processor = $name ? $name : wfGetCaller(2); if ($caller) { $instance->profileOut($processor . '-' . wfGetCaller(3)); } $instance->profileOut($processor); } return $instance; }
/** * This is public, for the convenience of external callers wishing to access * properties, e.g. eval.php */ function _unstub($name = '_unstub', $level = 2) { static $recursionLevel = 0; if (get_class($GLOBALS[$this->mGlobal]) != $this->mClass) { $fname = __METHOD__ . '-' . $this->mGlobal; wfProfileIn($fname); $caller = wfGetCaller($level); if (++$recursionLevel > 2) { throw new MWException("Unstub loop detected on call of \${$this->mGlobal}->{$name} from {$caller}\n"); } wfDebug("Unstubbing \${$this->mGlobal} on call of \${$this->mGlobal}->{$name} from {$caller}\n"); $GLOBALS[$this->mGlobal] = $this->_newObject(); --$recursionLevel; wfProfileOut($fname); } }
function decho($name, $value = "", $html = true) { $lineEnd = "<br>\n"; if (!$html) { $lineEnd = "\n"; } $prefix = wfGetCaller(2); if (is_string($value)) { echo "{$prefix}: {$name}: {$value}"; } else { if ((!is_array($value) || !is_object($value)) && method_exists($value, '__toString')) { print_r("{$prefix}: {$name}: {$value}"); } else { echo "{$prefix}: {$name}: "; print_r($value); echo $lineEnd; } } echo $lineEnd; }
/** * Write $msg under log group 'tests-parser' * @param string $msg Message to log */ protected static function debug($msg) { return wfDebugLog('tests-parser', wfGetCaller() . ' ' . $msg); }
/** * Run an anonymous function before the current transaction commits or now if there is none. * If there is a transaction and it is rolled back, then the callback is cancelled. * Callbacks must not start nor commit any transactions. * * This is useful for updates that easily cause deadlocks if locks are held too long * but where atomicity is strongly desired for these updates and some related updates. * * @param callable $callback * @since 1.22 */ final public function onTransactionPreCommitOrIdle( $callback ) { if ( $this->mTrxLevel ) { $this->mTrxPreCommitCallbacks[] = array( $callback, wfGetCaller() ); } else { $this->onTransactionIdle( $callback ); // this will trigger immediately } }
/** * Adds a line to the log * * @todo Add support for passing objects * * @since 1.19 * @param $str string */ public static function log($str) { if (!self::$enabled) { return; } self::$log[] = array('msg' => htmlspecialchars($str), 'type' => 'log', 'caller' => wfGetCaller()); }
/** * This function creates a new object of the real class and replace it in * the global variable. * This is public, for the convenience of external callers wishing to access * properties, e.g. eval.php * * @param string $name Name of the method called in this object. * @param int $level Level to go in the stack trace to get the function * who called this function. * @return object The unstubbed version of itself * @throws MWException */ public function _unstub($name = '_unstub', $level = 2) { static $recursionLevel = 0; if (!$GLOBALS[$this->global] instanceof StubObject) { return $GLOBALS[$this->global]; // already unstubbed. } if (get_class($GLOBALS[$this->global]) != $this->class) { $caller = wfGetCaller($level); if (++$recursionLevel > 2) { throw new MWException("Unstub loop detected on call of " . "\${$this->global}->{$name} from {$caller}\n"); } wfDebug("Unstubbing \${$this->global} on call of " . "\${$this->global}::{$name} from {$caller}\n"); $GLOBALS[$this->global] = $this->_newObject(); --$recursionLevel; return $GLOBALS[$this->global]; } }
/** Unless you know what you're doing, you want commitRevision */ function save($fname = null) { $this->dieIfHistorical(); $dbr = wfGetDB(DB_MASTER); if (!$fname) { $fname = __METHOD__ . "/" . wfGetCaller(); } else { $fname = __METHOD__ . "/" . $fname; } $dbr->update('thread', $this->getRow(), array('thread_id' => $this->id), $fname); // Touch the root if ($this->root()) { $this->root()->getTitle()->invalidateCache(); } // Touch the talk page, too. $this->getTitle()->invalidateCache(); $this->dbVersion = clone $this; unset($this->dbVersion->dbVersion); }
/** * Convert wikitext to HTML * Do not call this function recursively. * * @param $text String: text we want to parse * @param $title A title object * @param $options ParserOptions * @param $linestart boolean * @param $clearState boolean * @param $revid Int: 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, $wgContLang; $fname = __METHOD__ . '-' . wfGetCaller(); wfProfileIn(__METHOD__); wfProfileIn($fname); if ($clearState) { $this->clearState(); } $this->mOptions = $options; $this->setTitle($title); $oldRevisionId = $this->mRevisionId; $oldRevisionTimestamp = $this->mRevisionTimestamp; if ($revid !== null) { $this->mRevisionId = $revid; $this->mRevisionTimestamp = null; } $this->setOutputType(self::OT_HTML); wfRunHooks('ParserBeforeStrip', array(&$this, &$text, &$this->mStripState)); # No more strip! wfRunHooks('ParserAfterStrip', array(&$this, &$text, &$this->mStripState)); $text = $this->internalParse($text); $text = $this->mStripState->unstripGeneral($text); # Clean up special characters, only run once, next-to-last before doBlockLevels $fixtags = array('/(.) (?=\\?|:|;|!|%|\\302\\273)/' => '\\1 \\2', '/(\\302\\253) /' => '\\1 ', '/ (!\\s*important)/' => ' \\1'); $text = preg_replace(array_keys($fixtags), array_values($fixtags), $text); $text = $this->doBlockLevels($text, $linestart); $this->replaceLinkHolders($text); # the position of the parserConvert() call should not be changed. it # assumes that the links are all replaced and the only thing left # is the <nowiki> mark. # Side-effects: this calls $this->mOutput->setTitleText() $text = $wgContLang->parserConvert($text, $this); $text = $this->mStripState->unstripNoWiki($text); wfRunHooks('ParserBeforeTidy', array(&$this, &$text)); //!JF Move to its own function $uniq_prefix = $this->mUniqPrefix; $matches = array(); $elements = array_keys($this->mTransparentTagHooks); $text = self::extractTagsAndParams($elements, $text, $matches, $uniq_prefix); foreach ($matches as $marker => $data) { list($element, $content, $params, $tag) = $data; $tagName = strtolower($element); if (isset($this->mTransparentTagHooks[$tagName])) { $output = call_user_func_array($this->mTransparentTagHooks[$tagName], array($content, $params, $this)); } else { $output = $tag; } $this->mStripState->general->setPair($marker, $output); } $text = $this->mStripState->unstripGeneral($text); $text = Sanitizer::normalizeCharReferences($text); if ($wgUseTidy && $this->mOptions->mTidy || $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<div\\5>\\6</div>\\8\\9', '/<([bi])><\\/\\1>/' => ''); $text = preg_replace(array_keys($tidyregs), array_values($tidyregs), $text); } global $wgExpensiveParserFunctionLimit; if ($this->mExpensiveFunctionCount > $wgExpensiveParserFunctionLimit) { $this->limitationWarn('expensive-parserfunction', $this->mExpensiveFunctionCount, $wgExpensiveParserFunctionLimit); } wfRunHooks('ParserAfterTidy', array(&$this, &$text)); # Information on include size limits, for the benefit of users who try to skirt them if ($this->mOptions->getEnableLimitReport()) { global $wgExpensiveParserFunctionLimit; $max = $this->mOptions->getMaxIncludeSize(); $PFreport = "Expensive parser function count: {$this->mExpensiveFunctionCount}/{$wgExpensiveParserFunctionLimit}\n"; $limitReport = "NewPP limit report\n" . "Preprocessor node count: {$this->mPPNodeCount}/{$this->mOptions->mMaxPPNodeCount}\n" . "Post-expand include size: {$this->mIncludeSizes['post-expand']}/{$max} bytes\n" . "Template argument size: {$this->mIncludeSizes['arg']}/{$max} bytes\n" . $PFreport; wfRunHooks('ParserLimitReport', array($this, &$limitReport)); $text .= "\n<!-- \n{$limitReport}-->\n"; } $this->mOutput->setText($text); $this->mRevisionId = $oldRevisionId; $this->mRevisionTimestamp = $oldRevisionTimestamp; wfProfileOut($fname); wfProfileOut(__METHOD__); return $this->mOutput; }
/** Poor man debugging */ protected function debug($msg = '') { wfDebug(wfGetCaller() . "{$msg}\n"); }
/** * Convert wikitext to HTML * Do not call this function recursively. * * @private * @param string $text Text we want to parse * @param Title &$title A title object * @param array $options * @param boolean $linestart * @param boolean $clearState * @param int $revid number to pass in {{REVISIONID}} * @return ParserOutput a ParserOutput */ function parse($text, &$title, $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, $wgContLang; $fname = 'Parser::parse-' . wfGetCaller(); wfProfileIn($fname); if ($clearState) { $this->clearState(); } $this->mOptions = $options; $this->mTitle =& $title; $oldRevisionId = $this->mRevisionId; if ($revid !== null) { $this->mRevisionId = $revid; } $this->setOutputType(OT_HTML); //$text = $this->strip( $text, $this->mStripState ); // VOODOO MAGIC FIX! Sometimes the above segfaults in PHP5. $x =& $this->mStripState; wfRunHooks('ParserBeforeStrip', array(&$this, &$text, &$x)); $text = $this->strip($text, $x); wfRunHooks('ParserAfterStrip', array(&$this, &$text, &$x)); $text = $this->internalParse($text); $text = $this->unstrip($text, $this->mStripState); # Clean up special characters, only run once, next-to-last before doBlockLevels $fixtags = array('/(.) (?=\\?|:|;|!|\\302\\273)/' => '\\1 \\2', '/(\\302\\253) /' => '\\1 '); $text = preg_replace(array_keys($fixtags), array_values($fixtags), $text); # only once and last $text = $this->doBlockLevels($text, $linestart); $this->replaceLinkHolders($text); # the position of the parserConvert() call should not be changed. it # assumes that the links are all replaced and the only thing left # is the <nowiki> mark. # Side-effects: this calls $this->mOutput->setTitleText() $text = $wgContLang->parserConvert($text, $this); $text = $this->unstripNoWiki($text, $this->mStripState); wfRunHooks('ParserBeforeTidy', array(&$this, &$text)); $text = Sanitizer::normalizeCharReferences($text); if ($wgUseTidy and $this->mOptions->mTidy or $wgAlwaysUseTidy) { $text = Parser::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<div\\5>\\6</div>\\8\\9', '/<([bi])><\\/\\1>/' => ''); $text = preg_replace(array_keys($tidyregs), array_values($tidyregs), $text); } wfRunHooks('ParserAfterTidy', array(&$this, &$text)); # Information on include size limits, for the benefit of users who try to skirt them if (max($this->mIncludeSizes) > 1000) { $max = $this->mOptions->getMaxIncludeSize(); $text .= "<!-- \n" . "Pre-expand include size: {$this->mIncludeSizes['pre-expand']} bytes\n" . "Post-expand include size: {$this->mIncludeSizes['post-expand']} bytes\n" . "Template argument size: {$this->mIncludeSizes['arg']} bytes\n" . "Maximum: {$max} bytes\n" . "-->\n"; } $this->mOutput->setText($text); $this->mRevisionId = $oldRevisionId; wfProfileOut($fname); return $this->mOutput; }
/** * Adds a depreciation entry to the log, along with a backtrace * * @param $function * @param $version * @param $component * @return mixed */ public static function deprecated($function, $version, $component) { if (!self::$enabled) { return; } // Chain: This function -> wfDeprecated -> deprecatedFunction -> caller $caller = wfGetCaller(4); // Check to see if there already was a warning about this function $functionString = "{$function}-{$caller}"; if (in_array($functionString, self::$deprecationWarnings)) { return; } $version = $version === false ? '(unknown version)' : $version; $component = $component === false ? 'MediaWiki' : $component; $msg = htmlspecialchars("Use of function {$function} was deprecated in {$component} {$version}"); $msg .= Html::rawElement('div', array('class' => 'mw-debug-backtrace'), Html::element('span', array(), 'Backtrace:') . wfBacktrace()); self::$deprecationWarnings[] = $functionString; self::$log[] = array('msg' => $msg, 'type' => 'deprecated', 'caller' => $caller); }
/** * Adds a line to the log * * @since 1.19 * @param mixed $str */ public static function log($str) { if (!self::$enabled) { return; } if (!is_string($str)) { $str = print_r($str, true); } self::$log[] = ['msg' => htmlspecialchars($str), 'type' => 'log', 'caller' => wfGetCaller()]; }
/** * Asserts that the given database query yields the rows given by $expectedRows. * The expected rows should be given as indexed (not associative) arrays, with * the values given in the order of the columns in the $fields parameter. * Note that the rows are sorted by the columns given in $fields. * * @since 1.20 * * @param string|array $table The table(s) to query * @param string|array $fields The columns to include in the result (and to sort by) * @param string|array $condition "where" condition(s) * @param array $expectedRows An array of arrays giving the expected rows. * * @throws MWException If this test cases's needsDB() method doesn't return true. * Test cases can use "@group Database" to enable database test support, * or list the tables under testing in $this->tablesUsed, or override the * needsDB() method. */ protected function assertSelect($table, $fields, $condition, array $expectedRows) { if (!$this->needsDB()) { throw new MWException('When testing database state, the test cases\'s needDB()' . ' method should return true. Use @group Database or $this->tablesUsed.'); } $db = wfGetDB(DB_SLAVE); $res = $db->select($table, $fields, $condition, wfGetCaller(), array('ORDER BY' => $fields)); $this->assertNotEmpty($res, "query failed: " . $db->lastError()); $i = 0; foreach ($expectedRows as $expected) { $r = $res->fetchRow(); self::stripStringKeys($r); $i += 1; $this->assertNotEmpty($r, "row #{$i} missing"); $this->assertEquals($expected, $r, "row #{$i} mismatches"); } $r = $res->fetchRow(); self::stripStringKeys($r); $this->assertFalse($r, "found extra row (after #{$i})"); }
/** * Convenience method to count on a single table for a given type * * @since 1.9 * * @param string $type * * @return number */ protected function count($type) { $caller = wfGetCaller(); $count = 0; $res = $this->dbConnection->select($this->findPropertyTableByType($type)->getName(), 'COUNT(s_id) AS count', array(), __METHOD__); $row = $this->dbConnection->fetchObject($res); return (int) $row->count; }
/** * Convert wikitext to HTML * Do not call this function recursively. * * @param $text String: text we want to parse * @param $title Title object * @param $options ParserOptions * @param $linestart boolean * @param $clearState boolean * @param $revid Int: 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; $fname = __METHOD__ . '-' . wfGetCaller(); wfProfileIn(__METHOD__); wfProfileIn($fname); $this->startParse($title, $options, self::OT_HTML, $clearState); # 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; if ($revid !== null) { $this->mRevisionId = $revid; $this->mRevisionObject = null; $this->mRevisionTimestamp = null; $this->mRevisionUser = 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 ', '/(\\302\\253) /' => '\\1 ', '/ (!\\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']))) { # Run convert unconditionally in 1.18-compatible mode global $wgBug34832TransitionalRollback; if ($wgBug34832TransitionalRollback || !$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<div\\5>\\6</div>\\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(); $PFreport = "Expensive parser function count: {$this->mExpensiveFunctionCount}/{$this->mOptions->getExpensiveParserFunctionLimit()}\n"; $limitReport = "NewPP limit report\n" . "Preprocessor visited node count: {$this->mPPNodeCount}/{$this->mOptions->getMaxPPNodeCount()}\n" . "Preprocessor generated node count: " . "{$this->mGeneratedPPNodeCount}/{$this->mOptions->getMaxGeneratedPPNodeCount()}\n" . "Post-expand include size: {$this->mIncludeSizes['post-expand']}/{$max} bytes\n" . "Template argument size: {$this->mIncludeSizes['arg']}/{$max} bytes\n" . "Highest expansion depth: {$this->mHighestExpansionDepth}/{$this->mOptions->getMaxPPExpandDepth()}\n" . $PFreport; wfRunHooks('ParserLimitReport', array($this, &$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; wfProfileOut($fname); wfProfileOut(__METHOD__); return $this->mOutput; }
/** * Add a callable update. In a lot of cases, we just need a callback/closure, * defining a new DeferrableUpdate object is not necessary * * @see MWCallableUpdate::__construct() * * @param callable $callable * @param integer $stage DeferredUpdates constant (PRESEND or POSTSEND) (since 1.27) * @param IDatabase|null $dbw Abort if this DB is rolled back [optional] (since 1.28) */ public static function addCallableUpdate($callable, $stage = self::POSTSEND, IDatabase $dbw = null) { self::addUpdate(new MWCallableUpdate($callable, wfGetCaller(), $dbw), $stage); }
/** * Execute a shell command, returning both stdout and stderr. Convenience * function, as all the arguments to wfShellExec can become unwieldy. * * @note This also includes errors from limit.sh, e.g. if $wgMaxShellFileSize is exceeded. * @param string|string[] $cmd If string, a properly shell-escaped command line, * or an array of unescaped arguments, in which case each value will be escaped * Example: [ 'convert', '-font', 'font name' ] would produce "'convert' '-font' 'font name'" * @param null|mixed &$retval Optional, will receive the program's exit code. * (non-zero is usually failure) * @param array $environ Optional environment variables which should be * added to the executed command environment. * @param array $limits Optional array with limits(filesize, memory, time, walltime) * this overwrites the global wgMaxShell* limits. * @return string Collected stdout and stderr as a string */ function wfShellExecWithStderr($cmd, &$retval = null, $environ = array(), $limits = array()) { return wfShellExec($cmd, $retval, $environ, $limits, array('duplicateStderr' => true, 'profileMethod' => wfGetCaller())); }
/** * Ensure a given setup stage has been done, throw an exception if it has * not. */ protected function checkSetupDone($funcName, $funcName2 = null) { if (!$this->setupDone[$funcName] && ($funcName === null || !$this->setupDone[$funcName2])) { throw new MWException("{$funcName} must be called before calling " . wfGetCaller()); } }
/** * 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 ', '/(\\302\\253) /' => '\\1 ', '/ (!\\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<div\\5>\\6</div>\\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('‐', '&'), $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; }
/** * Convert wikitext to HTML * Do not call this function recursively. * * @param $text String: text we want to parse * @param $title A title object * @param $options ParserOptions * @param $linestart boolean * @param $clearState boolean * @param $revid Int: 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, $wgContLang, $wgDisableLangConversion, $wgDisableTitleConversion; $fname = __METHOD__ . '-' . wfGetCaller(); wfProfileIn(__METHOD__); wfProfileIn($fname); if ($clearState) { $this->clearState(); } $this->mOptions = $options; $this->setTitle($title); // Page title has to be set for the pre-processor $oldRevisionId = $this->mRevisionId; $oldRevisionTimestamp = $this->mRevisionTimestamp; if ($revid !== null) { $this->mRevisionId = $revid; $this->mRevisionTimestamp = null; } $this->setOutputType(self::OT_HTML); wfRunHooks('ParserBeforeStrip', array(&$this, &$text, &$this->mStripState)); # No more strip! wfRunHooks('ParserAfterStrip', array(&$this, &$text, &$this->mStripState)); $text = $this->internalParse($text); $text = $this->mStripState->unstripGeneral($text); # Clean up special characters, only run once, next-to-last before doBlockLevels $fixtags = array('/(.) (?=\\?|:|;|!|%|\\302\\273)/' => '\\1 \\2', '/(\\302\\253) /' => '\\1 ', '/ (!\\s*important)/' => ' \\1'); $text = preg_replace(array_keys($fixtags), array_values($fixtags), $text); $text = $this->doBlockLevels($text, $linestart); $this->replaceLinkHolders($text); /** * The page doesn't get language converted if * a) It's disabled * b) Content isn't converted * c) It's a conversion table */ if (!($wgDisableLangConversion || isset($this->mDoubleUnderscores['nocontentconvert']) || $this->mTitle->isConversionTable())) { # 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 = $wgContLang->convert($text); } /** * A page get its title converted except: * a) Language conversion is globally disabled * b) Title convert is globally disabled * c) The page is a redirect page * d) User request with a "linkconvert" set to "no" * e) A "nocontentconvert" magic word has been set * f) A "notitleconvert" magic word has been set * g) User sets "noconvertlink" in his/her preference * * Note that if a user tries to set a title in a conversion * rule but content conversion was not done, then the parser * won't pick it up. This is probably expected behavior. */ if (!($wgDisableLangConversion || $wgDisableTitleConversion || isset($this->mDoubleUnderscores['nocontentconvert']) || isset($this->mDoubleUnderscores['notitleconvert']) || $this->mOutput->getDisplayTitle() !== false)) { $convruletitle = $wgContLang->getConvRuleTitle(); if ($convruletitle) { $this->mOutput->setTitleText($convruletitle); } else { $titleText = $wgContLang->convertTitle($title); $this->mOutput->setTitleText($titleText); } } $text = $this->mStripState->unstripNoWiki($text); wfRunHooks('ParserBeforeTidy', array(&$this, &$text)); //!JF Move to its own function $uniq_prefix = $this->mUniqPrefix; $matches = array(); $elements = array_keys($this->mTransparentTagHooks); $text = self::extractTagsAndParams($elements, $text, $matches, $uniq_prefix); foreach ($matches as $marker => $data) { list($element, $content, $params, $tag) = $data; $tagName = strtolower($element); if (isset($this->mTransparentTagHooks[$tagName])) { $output = call_user_func_array($this->mTransparentTagHooks[$tagName], array($content, $params, $this)); } else { $output = $tag; } $this->mStripState->general->setPair($marker, $output); } $text = $this->mStripState->unstripGeneral($text); $text = Sanitizer::normalizeCharReferences($text); if ($wgUseTidy && $this->mOptions->mTidy || $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<div\\5>\\6</div>\\8\\9', '/<([bi])><\\/\\1>/' => ''); $text = preg_replace(array_keys($tidyregs), array_values($tidyregs), $text); } global $wgExpensiveParserFunctionLimit; if ($this->mExpensiveFunctionCount > $wgExpensiveParserFunctionLimit) { $this->limitationWarn('expensive-parserfunction', $this->mExpensiveFunctionCount, $wgExpensiveParserFunctionLimit); } 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(); $PFreport = "Expensive parser function count: {$this->mExpensiveFunctionCount}/{$wgExpensiveParserFunctionLimit}\n"; $limitReport = "NewPP limit report\n" . "Preprocessor node count: {$this->mPPNodeCount}/{$this->mOptions->mMaxPPNodeCount}\n" . "Post-expand include size: {$this->mIncludeSizes['post-expand']}/{$max} bytes\n" . "Template argument size: {$this->mIncludeSizes['arg']}/{$max} bytes\n" . $PFreport; wfRunHooks('ParserLimitReport', array($this, &$limitReport)); $text .= "\n<!-- \n{$limitReport}-->\n"; } $this->mOutput->setText($text); $this->mRevisionId = $oldRevisionId; $this->mRevisionTimestamp = $oldRevisionTimestamp; wfProfileOut($fname); wfProfileOut(__METHOD__); return $this->mOutput; }