static function AJAXPollRender($input, $args = array(), Parser $parser) { global $wgUser, $wgOut, $wgTitle, $wgScriptPath, $wgUseAjax; $parser->disableCache(); $parser->addTrackingCategory('ajaxpoll-tracking-category'); if ($wgUser->getName() == '') { $userName = wfGetIP(); } else { $userName = $wgUser->getName(); } // ID of the poll $id = strtoupper(md5($input)); $par = new Parser(); $input = $par->parse($input, $wgTitle, $wgOut->parserOptions()); $input = trim(strip_tags($input->getText())); $lines = explode("\n", trim($input)); // compatibility for non-ajax requests - just in case if (!$wgUseAjax) { $responseId = "ajaxpoll-post-id"; $responseAnswer = "ajaxpoll-post-answer-{$id}"; $responseToken = "ajaxPollToken"; if (isset($_POST[$responseId]) && isset($_POST[$responseAnswer]) && $_POST[$responseId] == $id && isset($_POST[$responseToken])) { self::submitVote($id, intval($_POST[$responseAnswer]), $_POST[$responseToken]); } } $dbw = wfGetDB(DB_MASTER); $dbw->begin(__METHOD__); /** * Register poll in the database */ $row = $dbw->selectRow(array('ajaxpoll_info'), array('COUNT(poll_id) AS count'), array('poll_id' => $id), __METHOD__); $showResultsBeforeVoting = null; if (array_key_exists('show-results-before-voting', $args)) { if (strval($args['show-results-before-voting']) !== '0') { $showResultsBeforeVoting = '1'; } else { $showResultsBeforeVoting = '0'; } } if (empty($row->count)) { $dbw->insert('ajaxpoll_info', array('poll_id' => $id, 'poll_show_results_before_voting' => $showResultsBeforeVoting, 'poll_txt' => $input, 'poll_date' => wfTimestampNow()), __METHOD__); } else { $dbw->update('ajaxpoll_info', array('poll_show_results_before_voting' => $showResultsBeforeVoting), array('poll_id' => $id), __METHOD__); } $dbw->commit(__METHOD__); switch ($lines[0]) { case 'STATS': $ret = self::buildStats($id, $userName); break; default: $ret = Html::rawElement('div', array('id' => 'ajaxpoll-container-' . $id), self::buildHTML($id, $userName, $lines)); break; } return $ret; }
private function applyTagArgs(Coord $coord) { global $wgContLang, $wgTypeToDim, $wgDefaultDim, $wgGeoDataWarningLevel, $wgGlobes; $args = $this->named; $coord->primary = isset($args['primary']); $coord->globe = isset($args['globe']) ? $wgContLang->lc($args['globe']) : $wgDefaultGlobe; if (!isset($wgGlobes[$coord->globe])) { if ($wgGeoDataWarningLevel['unknown globe'] == 'fail') { return Status::newFatal('geodata-bad-globe', $coord->globe); } elseif ($wgGeoDataWarningLevel['unknown globe'] == 'warn') { $this->parser->addTrackingCategory('geodata-unknown-globe-category'); } } $coord->dim = $wgDefaultDim; if (isset($args['type'])) { $coord->type = preg_replace('/\\(.*?\\).*$/', '', $args['type']); if (isset($wgTypeToDim[$coord->type])) { $coord->dim = $wgTypeToDim[$coord->type]; } else { if ($wgGeoDataWarningLevel['unknown type'] == 'fail') { return Status::newFatal('geodata-bad-type', $coord->type); } elseif ($wgGeoDataWarningLevel['unknown type'] == 'warn') { $this->parser->addTrackingCategory('geodata-unknown-type-category'); } } } if (isset($args['scale'])) { $coord->dim = $args['scale'] / 10; } if (isset($args['dim'])) { $dim = $this->parseDim($args['dim']); if ($dim !== false) { $coord->dim = $dim; } } $coord->name = isset($args['name']) ? $args['name'] : null; if (isset($args['region'])) { $code = strtoupper($args['region']); if (preg_match('/^([A-Z]{2})(?:-([A-Z0-9]{1,3}))?$/', $code, $m)) { $coord->country = $m[1]; $coord->region = isset($m[2]) ? $m[2] : null; } else { if ($wgGeoDataWarningLevel['invalid region'] == 'fail') { return Status::newFatal('geodata-bad-region', $args['region']); } elseif ($wgGeoDataWarningLevel['invalid region'] == 'warn') { $this->parser->addTrackingCategory('geodata-unknown-region-category'); } } } return Status::newGood(); }
/** * #coordinates parser function callback * * @param Parser $parser * @param PPFrame $frame * @param Array $args * @return Mixed */ public function coordinates($parser, $frame, $args) { if ($parser != $this->parser) { throw new MWException(__METHOD__ . '() called by wrong parser'); } $this->output = $parser->getOutput(); if (!isset($this->output->geoData)) { $this->output->geoData = new CoordinatesOutput(); } $this->unnamed = array(); $this->named = array(); $first = trim($frame->expand(array_shift($args))); $this->addArg($first); foreach ($args as $arg) { $bits = $arg->splitArg(); $value = trim($frame->expand($bits['value'])); if ($bits['index'] === '') { $this->named[trim($frame->expand($bits['name']))] = $value; } else { $this->addArg($value); } } $this->parseTagArgs(); $status = GeoData::parseCoordinates($this->unnamed, $this->named['globe']); if ($status->isGood()) { $coord = $status->value; $status = $this->applyTagArgs($coord); if ($status->isGood()) { $status = $this->applyCoord($coord); if ($status->isGood()) { return ''; } } } $parser->addTrackingCategory('geodata-broken-tags-category'); $errorText = $this->errorText($status); if ($errorText == '<>') { // Error that doesn't require a message, // can't think of a better way to pass this condition return ''; } return array("<span class=\"error\">{$errorText}</span>", 'noparse' => false); }
/** * Create a new child frame * $args is optionally a multi-root PPNode or array containing the template arguments * * @param bool|array $args * @param Title|bool $title * @param int $indexOffset * @return PPTemplateFrame_DOM */ public function newChild($args = false, $title = false, $indexOffset = 0) { $namedArgs = array(); $numberedArgs = array(); if ($title === false) { $title = $this->title; } if ($args !== false) { $xpath = false; if ($args instanceof PPNode) { $args = $args->node; } foreach ($args as $arg) { if ($arg instanceof PPNode) { $arg = $arg->node; } if (!$xpath || $xpath->document !== $arg->ownerDocument) { $xpath = new DOMXPath($arg->ownerDocument); } $nameNodes = $xpath->query('name', $arg); $value = $xpath->query('value', $arg); if ($nameNodes->item(0)->hasAttributes()) { // Numbered parameter $index = $nameNodes->item(0)->attributes->getNamedItem('index')->textContent; $index = $index - $indexOffset; if (isset($namedArgs[$index]) || isset($numberedArgs[$index])) { $this->parser->getOutput()->addWarning(wfMessage('duplicate-args-warning', wfEscapeWikiText($this->title), wfEscapeWikiText($title), wfEscapeWikiText($index))->text()); $this->parser->addTrackingCategory('duplicate-args-category'); } $numberedArgs[$index] = $value->item(0); unset($namedArgs[$index]); } else { // Named parameter $name = trim($this->expand($nameNodes->item(0), PPFrame::STRIP_COMMENTS)); if (isset($namedArgs[$name]) || isset($numberedArgs[$name])) { $this->parser->getOutput()->addWarning(wfMessage('duplicate-args-warning', wfEscapeWikiText($this->title), wfEscapeWikiText($title), wfEscapeWikiText($name))->text()); $this->parser->addTrackingCategory('duplicate-args-category'); } $namedArgs[$name] = $value->item(0); unset($numberedArgs[$name]); } } } return new PPTemplateFrame_DOM($this->preprocessor, $this, $numberedArgs, $namedArgs, $title); }
/** * Override the title of the page when viewed, provided we've been given a * title which will normalise to the canonical title * * @param Parser $parser Parent parser * @param string $text Desired title text * @param string $uarg * @return string */ public static function displaytitle($parser, $text = '', $uarg = '') { global $wgRestrictDisplayTitle; static $magicWords = null; if (is_null($magicWords)) { $magicWords = new MagicWordArray(['displaytitle_noerror', 'displaytitle_noreplace']); } $arg = $magicWords->matchStartToEnd($uarg); // parse a limited subset of wiki markup (just the single quote items) $text = $parser->doQuotes($text); // remove stripped text (e.g. the UNIQ-QINU stuff) that was generated by tag extensions/whatever $text = $parser->killMarkers($text); // list of disallowed tags for DISPLAYTITLE // these will be escaped even though they are allowed in normal wiki text $bad = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'blockquote', 'ol', 'ul', 'li', 'hr', 'table', 'tr', 'th', 'td', 'dl', 'dd', 'caption', 'p', 'ruby', 'rb', 'rt', 'rtc', 'rp', 'br']; // disallow some styles that could be used to bypass $wgRestrictDisplayTitle if ($wgRestrictDisplayTitle) { $htmlTagsCallback = function (&$params) { $decoded = Sanitizer::decodeTagAttributes($params); if (isset($decoded['style'])) { // this is called later anyway, but we need it right now for the regexes below to be safe // calling it twice doesn't hurt $decoded['style'] = Sanitizer::checkCss($decoded['style']); if (preg_match('/(display|user-select|visibility)\\s*:/i', $decoded['style'])) { $decoded['style'] = '/* attempt to bypass $wgRestrictDisplayTitle */'; } } $params = Sanitizer::safeEncodeTagAttributes($decoded); }; } else { $htmlTagsCallback = null; } // only requested titles that normalize to the actual title are allowed through // if $wgRestrictDisplayTitle is true (it is by default) // mimic the escaping process that occurs in OutputPage::setPageTitle $text = Sanitizer::normalizeCharReferences(Sanitizer::removeHTMLtags($text, $htmlTagsCallback, [], [], $bad)); $title = Title::newFromText(Sanitizer::stripAllTags($text)); if (!$wgRestrictDisplayTitle || $title instanceof Title && !$title->hasFragment() && $title->equals($parser->mTitle)) { $old = $parser->mOutput->getProperty('displaytitle'); if ($old === false || $arg !== 'displaytitle_noreplace') { $parser->mOutput->setDisplayTitle($text); } if ($old !== false && $old !== $text && !$arg) { $converter = $parser->getConverterLanguage()->getConverter(); return '<span class="error">' . wfMessage('duplicate-displaytitle', $converter->markNoConversion(wfEscapeWikiText($old)), $converter->markNoConversion(wfEscapeWikiText($text)))->inContentLanguage()->text() . '</span>'; } else { return ''; } } else { $parser->addTrackingCategory('restricted-displaytitle-ignored'); $converter = $parser->getConverterLanguage()->getConverter(); return '<span class="error">' . wfMessage('restricted-displaytitle', $converter->markNoConversion(wfEscapeWikiText($text)))->inContentLanguage()->text() . '</span>'; } }
/** * Create a new child frame * $args is optionally a multi-root PPNode or array containing the template arguments * * @param array|bool|PPNode_Hash_Array $args * @param Title|bool $title * @param int $indexOffset * @throws MWException * @return PPTemplateFrame_Hash */ public function newChild($args = false, $title = false, $indexOffset = 0) { $namedArgs = array(); $numberedArgs = array(); if ($title === false) { $title = $this->title; } if ($args !== false) { if ($args instanceof PPNode_Hash_Array) { $args = $args->value; } elseif (!is_array($args)) { throw new MWException(__METHOD__ . ': $args must be array or PPNode_Hash_Array'); } foreach ($args as $arg) { $bits = $arg->splitArg(); if ($bits['index'] !== '') { // Numbered parameter $index = $bits['index'] - $indexOffset; if (isset($namedArgs[$index]) || isset($numberedArgs[$index])) { $this->parser->getOutput()->addWarning(wfMessage('duplicate-args-warning', wfEscapeWikiText($this->title), wfEscapeWikiText($title), wfEscapeWikiText($index))->text()); $this->parser->addTrackingCategory('duplicate-args-category'); } $numberedArgs[$index] = $bits['value']; unset($namedArgs[$index]); } else { // Named parameter $name = trim($this->expand($bits['name'], PPFrame::STRIP_COMMENTS)); if (isset($namedArgs[$name]) || isset($numberedArgs[$name])) { $this->parser->getOutput()->addWarning(wfMessage('duplicate-args-warning', wfEscapeWikiText($this->title), wfEscapeWikiText($title), wfEscapeWikiText($name))->text()); $this->parser->addTrackingCategory('duplicate-args-category'); } $namedArgs[$name] = $bits['value']; unset($numberedArgs[$name]); } } } return new PPTemplateFrame_Hash($this->preprocessor, $this, $numberedArgs, $namedArgs, $title); }
/** * Parser hook * * @param string $text * @param array $args * @param Parser $parser * @return string */ public static function parserHook($text, $args = array(), $parser) { global $wgUseTidy; // Don't trim leading spaces away, just the linefeeds $out = preg_replace('/^\\n+/', '', rtrim($text)); // Convert deprecated attributes if (isset($args['enclose'])) { if ($args['enclose'] === 'none') { $args['inline'] = true; } unset($args['enclose']); } $lexer = isset($args['lang']) ? $args['lang'] : ''; $result = self::highlight($out, $lexer, $args); if (!$result->isGood()) { $parser->addTrackingCategory('syntaxhighlight-error-category'); } $out = $result->getValue(); // HTML Tidy will convert tabs to spaces incorrectly (bug 30930). // But the conversion from tab to space occurs while reading the input, // before the conversion from 	 to tab, so we can armor it that way. if ($wgUseTidy) { $out = str_replace("\t", '	', $out); } // Allow certain HTML attributes $htmlAttribs = Sanitizer::validateAttributes($args, array('style', 'class', 'id', 'dir')); if (!isset($htmlAttribs['class'])) { $htmlAttribs['class'] = self::HIGHLIGHT_CSS_CLASS; } else { $htmlAttribs['class'] .= ' ' . self::HIGHLIGHT_CSS_CLASS; } if (!(isset($htmlAttribs['dir']) && $htmlAttribs['dir'] === 'rtl')) { $htmlAttribs['dir'] = 'ltr'; } if (isset($args['inline'])) { // Enforce inlineness. Stray newlines may result in unexpected list and paragraph processing // (also known as doBlockLevels()). $out = str_replace("\n", ' ', $out); $out = Html::rawElement('code', $htmlAttribs, $out); } else { // Not entirely sure what benefit this provides, but it was here already $htmlAttribs['class'] .= ' ' . 'mw-content-' . $htmlAttribs['dir']; // Unwrap Pygments output to provide our own wrapper. We can't just always use the 'nowrap' // option (pass 'inline'), since it disables other useful things like line highlighting. // Tolerate absence of quotes for Html::element() and wgWellFormedXml=false. $m = array(); if (preg_match('/^<div class="?mw-highlight"?>(.*)<\\/div>$/s', trim($out), $m)) { $out = trim($m[1]); } else { throw new MWException('Unexpected output from Pygments encountered'); } // Use 'nowiki' strip marker to prevent list processing (also known as doBlockLevels()). // However, leave the wrapping <div/> outside to prevent <p/>-wrapping. $marker = $parser->mUniqPrefix . '-syntaxhighlightinner-' . sprintf('%08X', $parser->mMarkerIndex++) . $parser::MARKER_SUFFIX; $parser->mStripState->addNoWiki($marker, $out); $out = Html::openElement('div', $htmlAttribs) . $marker . Html::closeElement('div'); } // Register CSS $parser->getOutput()->addModuleStyles('ext.pygments'); return $out; }