/** * Takes care of setting a strip state pair in MW 1.18 as well as in previous versions */ protected function stripStatePair($marker, $value) { global $wgVersion; if (version_compare($wgVersion, '1.17.99', '>')) { // MW 1.18alpha+ $this->mFinalizedVarsStripState->addGeneral($marker, $value); } else { $this->mFinalizedVarsStripState->general->setPair($marker, $value); } }
/** * Return the text to be used for a given extension tag. * This is the ghost of strip(). * * @param array $params Associative array of parameters: * name PPNode for the tag name * attr PPNode for unparsed text where tag attributes are thought to be * attributes Optional associative array of parsed attributes * inner Contents of extension element * noClose Original text did not have a close tag * @param $frame PPFrame * * @throws MWException * @return string */ function extensionSubstitution($params, $frame) { $name = $frame->expand($params['name']); $attrText = !isset($params['attr']) ? null : $frame->expand($params['attr']); $content = !isset($params['inner']) ? null : $frame->expand($params['inner']); $marker = "{$this->mUniqPrefix}-{$name}-" . sprintf('%08X', $this->mMarkerIndex++) . self::MARKER_SUFFIX; $isFunctionTag = isset($this->mFunctionTagHooks[strtolower($name)]) && ($this->ot['html'] || $this->ot['pre']); if ($isFunctionTag) { $markerType = 'none'; } else { $markerType = 'general'; } if ($this->ot['html'] || $isFunctionTag) { $name = strtolower($name); $attributes = Sanitizer::decodeTagAttributes($attrText); if (isset($params['attributes'])) { $attributes = $attributes + $params['attributes']; } if (isset($this->mTagHooks[$name])) { # Workaround for PHP bug 35229 and similar if (!is_callable($this->mTagHooks[$name])) { throw new MWException("Tag hook for {$name} is not callable\n"); } $output = call_user_func_array($this->mTagHooks[$name], array($content, $attributes, $this, $frame)); } elseif (isset($this->mFunctionTagHooks[$name])) { list($callback, ) = $this->mFunctionTagHooks[$name]; if (!is_callable($callback)) { throw new MWException("Tag hook for {$name} is not callable\n"); } $output = call_user_func_array($callback, array(&$this, $frame, $content, $attributes)); } else { $output = '<span class="error">Invalid tag extension name: ' . htmlspecialchars($name) . '</span>'; } if (is_array($output)) { # Extract flags to local scope (to override $markerType) $flags = $output; $output = $flags[0]; unset($flags[0]); extract($flags); } } else { if (is_null($attrText)) { $attrText = ''; } if (isset($params['attributes'])) { foreach ($params['attributes'] as $attrName => $attrValue) { $attrText .= ' ' . htmlspecialchars($attrName) . '="' . htmlspecialchars($attrValue) . '"'; } } if ($content === null) { $output = "<{$name}{$attrText}/>"; } else { $close = is_null($params['close']) ? '' : $frame->expand($params['close']); $output = "<{$name}{$attrText}>{$content}{$close}"; } } if ($markerType === 'none') { return $output; } elseif ($markerType === 'nowiki') { $this->mStripState->addNoWiki($marker, $output); } elseif ($markerType === 'general') { $this->mStripState->addGeneral($marker, $output); } else { throw new MWException(__METHOD__ . ': invalid marker type'); } return $marker; }
/** * Return the text to be used for a given extension tag. * This is the ghost of strip(). * * @param $params Associative array of parameters: * name PPNode for the tag name * attr PPNode for unparsed text where tag attributes are thought to be * attributes Optional associative array of parsed attributes * inner Contents of extension element * noClose Original text did not have a close tag * @param $frame PPFrame * * @return string */ function extensionSubstitution($params, $frame) { $name = $frame->expand($params['name']); $attrText = !isset($params['attr']) ? null : $frame->expand($params['attr']); $content = !isset($params['inner']) ? null : $frame->expand($params['inner']); # RTE (Rich Text Editor) - begin # @author: Inez Korczyński global $wgRTEParserEnabled; if (!empty($wgRTEParserEnabled)) { $wikitextIdx = RTEMarker::getDataIdx(RTEMarker::EXT_WIKITEXT, $content); # Allow parser extensions to generate their own placeholders (instead of default one from RTE) # @author: Macbre if (wfRunHooks('RTEUseDefaultPlaceholder', array($name, $params, $frame, $wikitextIdx))) { if ($wikitextIdx !== null) { $dataIdx = RTEData::put('placeholder', array('type' => 'ext', 'wikitextIdx' => $wikitextIdx)); return RTEMarker::generate(RTEMarker::PLACEHOLDER, $dataIdx); } } else { RTE::log(__METHOD__, "skipped default placeholder for <{$name}>"); // restore value of $content $content = RTEData::get('wikitext', $wikitextIdx); // keep inner content of tag $content = preg_replace('#^<[^>]+>(.*)<[^>]+>$#s', '\\1', $content); } } # RTE - end $marker = "{$this->mUniqPrefix}-{$name}-" . sprintf('%08X', $this->mMarkerIndex++) . self::MARKER_SUFFIX; $isFunctionTag = isset($this->mFunctionTagHooks[strtolower($name)]) && ($this->ot['html'] || $this->ot['pre']); if ($isFunctionTag) { $markerType = 'none'; } else { $markerType = 'general'; } if ($this->ot['html'] || $isFunctionTag) { $name = strtolower($name); # PLB - begin # @author: Tomasz Odrobny $this->mCurrentTagName = $name; # PLB - end $attributes = Sanitizer::decodeTagAttributes($attrText); if (isset($params['attributes'])) { $attributes = $attributes + $params['attributes']; } if (isset($this->mTagHooks[$name])) { # Workaround for PHP bug 35229 and similar if (!is_callable($this->mTagHooks[$name])) { throw new MWException("Tag hook for {$name} is not callable\n"); } wfRunHooks('ParserTagHooksBeforeInvoke', [$name, $marker, $content, $attributes, $this, $frame]); $output = call_user_func_array($this->mTagHooks[$name], array($content, $attributes, $this, $frame)); } elseif (isset($this->mFunctionTagHooks[$name])) { list($callback, $flags) = $this->mFunctionTagHooks[$name]; if (!is_callable($callback)) { throw new MWException("Tag hook for {$name} is not callable\n"); } $output = call_user_func_array($callback, array(&$this, $frame, $content, $attributes)); } else { $output = '<span class="error">Invalid tag extension name: ' . htmlspecialchars($name) . '</span>'; } if (is_array($output)) { # Extract flags to local scope (to override $markerType) $flags = $output; $output = $flags[0]; unset($flags[0]); extract($flags); } } else { if (is_null($attrText)) { $attrText = ''; } if (isset($params['attributes'])) { foreach ($params['attributes'] as $attrName => $attrValue) { $attrText .= ' ' . htmlspecialchars($attrName) . '="' . htmlspecialchars($attrValue) . '"'; } } if ($content === null) { $output = "<{$name}{$attrText}/>"; } else { $close = is_null($params['close']) ? '' : $frame->expand($params['close']); $output = "<{$name}{$attrText}>{$content}{$close}"; } } if ($markerType === 'none') { return $output; } elseif ($markerType === 'nowiki') { $this->mStripState->addNoWiki($marker, $output); } elseif ($markerType === 'general') { $this->mStripState->addGeneral($marker, $output); } else { throw new MWException(__METHOD__ . ': invalid marker type'); } return $marker; }
/** * 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() * * @param StripState $state * * @param bool $stripcomments when set, HTML comments <!-- like this --> * 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 * * @param array dontstrip contains tags which should not be stripped; * used to prevent stipping of <gallery> when saving (fixes bug 2700) * * @private */ function strip($text, $state, $stripcomments = false, $dontstrip = array()) { global $wgContLang, $wgUseTeX, $wgScriptPath, $wgVersion, $wgHooks, $wgExtensionFunctions; wfProfileIn(__METHOD__); $render = $this->mOutputType == OT_HTML; $uniq_prefix = $this->mUniqPrefix; $commentState = new ReplacementArray(); $nowikiItems = array(); $generalItems = array(); $elements = array_merge(array('nowiki', 'gallery', 'math'), array_keys($this->mTagHooks)); if (isset($wgHooks['ParserFirstCallInit']) && in_array('efSyntaxHighlight_GeSHiSetup', $wgHooks['ParserFirstCallInit']) || isset($wgExtensionFunctions) && in_array('efSyntaxHighlight_GeSHiSetup', $wgExtensionFunctions)) { $elements = array_merge($elements, array('source')); } if (isset($wgHooks['ParserFirstCallInit']) && in_array('wfCite', $wgHooks['ParserFirstCallInit']) || isset($wgExtensionFunctions) && in_array('wfCite', $wgExtensionFunctions)) { $elements = array_merge($elements, array('ref', 'references')); } global $wgRawHtml; if ($wgRawHtml) { $elements[] = 'html'; } # Removing $dontstrip tags from $elements list (currently only 'gallery', fixing bug 2700) foreach ($elements as $k => $v) { if (!in_array($v, $dontstrip)) { continue; } unset($elements[$k]); } $elements = array_unique($elements); $matches = array(); if (version_compare("1.12", $wgVersion, ">")) { $text = Parser::extractTagsAndParams($elements, $text, $matches, $uniq_prefix); } else { $text = self::extractTagsAndParams($elements, $text, $matches, $uniq_prefix); } foreach ($matches as $marker => $data) { list($element, $content, $params, $tag) = $data; if ($render) { $tagName = strtolower($element); wfProfileIn(__METHOD__ . "-render-{$tagName}"); switch ($tagName) { case '!--': // Comment if (substr($tag, -3) == '-->') { $output = $tag; } else { // Unclosed comment in input. // Close it so later stripping can remove it $output = "{$tag}-->"; } break; case 'references': $output = $this->fck_wikiTag('references', $content, $params); break; case 'ref': $output = $this->fck_wikiTag('ref', $content, $params); break; case 'source': $output = $this->fck_wikiTag('source', $content, $params); break; case 'html': if ($wgRawHtml) { $output = $this->fck_wikiTag('html', $content, $params); } break; case 'nowiki': $output = $this->fck_wikiTag('nowiki', $content, $params); // required by FCKeditor break; case 'math': if ($wgUseTeX) { //normal render $output = $wgContLang->armourMath(MathRenderer::renderMath($content)); } else { // show fakeimage $output = '<img _fckfakelement="true" class="FCK__MWMath" _fck_mw_math="' . $content . '" src="' . $wgScriptPath . '/skins/common/images/button_math.png" />'; } break; case 'gallery': $output = $this->fck_wikiTag('gallery', $content, $params); // required by FCKeditor //$output = $this->renderImageGallery( $content, $params ); break; default: if (isset($this->mTagHooks[$tagName])) { $this->fck_mw_taghook = $tagName; // required by FCKeditor $output = call_user_func_array($this->mTagHooks[$tagName], array($content, $params, $this)); } else { throw new MWException("Invalid call hook {$element}"); } } wfProfileOut(__METHOD__ . "-render-{$tagName}"); } else { // Just stripping tags; keep the source $output = $tag; } // Unstrip the output, to support recursive strip() calls $output = $state->unstripBoth($output); if (!$stripcomments && $element == '!--') { $commentState->setPair($marker, $output); } elseif ($element == 'html' || $element == 'nowiki') { # $nowikiItems[$marker] = $output; $state->addNoWiki($marker, $output); } else { # $generalItems[$marker] = $output; $state->addGeneral($marker, $output); } } # Unstrip comments unless explicitly told otherwise. # (The comments are always stripped prior to this point, so as to # not invoke any extension tags / parser hooks contained within # a comment.) if (!$stripcomments) { // Put them all back and forget them $text = $commentState->replace($text); } $this->fck_matches = $matches; wfProfileOut(__METHOD__); return $text; }
/** * Parse the form definition and return it */ public static function getFormDefinition(Parser $parser, $form_def = null, $form_id = null) { if ($form_id !== null) { $cachedDef = self::getFormDefinitionFromCache($form_id, $parser); if ($cachedDef !== null) { return $cachedDef; } } if ($form_id !== null) { $form_title = Title::newFromID($form_id); $form_def = SFUtils::getPageText($form_title); } elseif ($form_def == null) { // No id, no text -> nothing to do return ''; } // Remove <noinclude> sections and <includeonly> tags from form definition $form_def = StringUtils::delimiterReplace('<noinclude>', '</noinclude>', '', $form_def); $form_def = strtr($form_def, array('<includeonly>' => '', '</includeonly>' => '')); // We need to replace all SF tags in the form definition by strip items. But we can not just use // the Parser strip state because the Parser would during parsing replace all strip items and then // mangle them into HTML code. So we have to use our own. Which means we also can not just use // Parser::insertStripItem() (see below). $prefix = "UNIQ" . Parser::getRandomString(); $stripState = new StripState($prefix); // This regexp will find any SF triple braced tags (including correct handling of contained braces), i.e. // {{{field|foo|default={{Bar}}}}} is not a problem. When used with preg_match and friends, $matches[0] will // contain the whole SF tag, $matches[1] will contain the tag without the enclosing triple braces. $regexp = '#\\{\\{\\{((?>[^\\{\\}]+)|(\\{((?>[^\\{\\}]+)|(?-2))*\\}))*\\}\\}\\}#'; // replace all SF tags by strip markers $form_def = preg_replace_callback($regexp, function (array $matches) use($stripState, $prefix) { static $markerIndex = 0; $rnd = "{$prefix}-item-{$markerIndex}-" . Parser::MARKER_SUFFIX; $markerIndex++; $stripState->addGeneral($rnd, $matches[0]); return $rnd; }, $form_def); $title = is_object($parser->getTitle()) ? $parser->getTitle() : new Title(); // parse wiki-text $output = $parser->parse($form_def, $title, $parser->getOptions()); $form_def = $stripState->unstripGeneral($output->getText()); if ($output->getCacheTime() == -1) { $form_article = Article::newFromID($form_id); self::purgeCache($form_article); wfDebug("Caching disabled for form definition {$form_id}\n"); } elseif ($form_id !== null) { self::cacheFormDefinition($form_id, $form_def, $parser); } return $form_def; }