/** * Check, if the user solved the captcha. * * Based on reference implementation: * https://github.com/google/recaptcha#php * * @return boolean */ function passCaptcha() { global $wgRequest, $wgReCaptchaSecretKey, $wgReCaptchaSendRemoteIP; $url = 'https://www.google.com/recaptcha/api/siteverify'; // Build data to append to request $data = array('secret' => $wgReCaptchaSecretKey, 'response' => $wgRequest->getVal('g-recaptcha-response')); if ($wgReCaptchaSendRemoteIP) { $data['remoteip'] = $wgRequest->getIP(); } $url = wfAppendQuery($url, $data); $request = MWHttpRequest::factory($url, array('method' => 'GET')); $status = $request->execute(); if (!$status->isOK()) { $this->error = 'http'; $this->logStatusError($status); return false; } $response = FormatJson::decode($request->getContent(), true); if (!$response) { $this->error = 'json'; $this->logStatusError($this->error); return false; } if (isset($response['error-codes'])) { $this->error = 'recaptcha-api'; $this->logCheckError($response['error-codes']); return false; } return $response['success']; }
protected function fetchScriptList() { $data = array('action' => 'query', 'format' => 'php', 'list' => 'allpages', 'apnamespace' => '8', 'aplimit' => '500'); $baseUrl = $this->getArg(0); $pages = array(); do { $url = wfAppendQuery($baseUrl, $data); $strResult = Http::get($url); //$result = FormatJson::decode( $strResult ); // Still broken $result = unserialize($strResult); if (!empty($result['query']['allpages'])) { foreach ($result['query']['allpages'] as $page) { if (substr($page['title'], -3) === '.js') { strtok($page['title'], ':'); $pages[] = strtok(''); } } } if (!empty($result['query-continue'])) { $data['apfrom'] = $result['query-continue']['allpages']['apfrom']; $this->output("Fetching new batch from {$data['apfrom']}\n"); } } while (isset($result['query-continue'])); return $pages; }
public function stage(GatewayType $adapter, $normalized, &$stagedData) { if ($adapter->isBatchProcessor()) { // Only makes sense for real users. return; } if (!empty($normalized['returnto'])) { $returnto = $normalized['returnto']; } else { $returnto = ''; } if (isset($normalized['payment_method']) && $normalized['payment_method'] === 'cc') { // Add order ID to the returnto URL, only if it's not already there. //TODO: This needs to be more robust (like actually pulling the //qstring keys, resetting the values, and putting it all back) //but for now it'll keep us alive. if ($adapter->getOrderIDMeta('generate') && !empty($returnto) && !strpos($returnto, 'order_id')) { $queryArray = array('order_id' => $normalized['order_id']); $stagedData['returnto'] = wfAppendQuery($returnto, $queryArray); } } else { // FIXME: An empty returnto should be handled by the result switcher instead. $stagedData['returnto'] = ResultPages::getThankYouPage($adapter); } }
/** * @param bool $rapidFail if true, render a form as a fail page rather than redirect * @param string $failPage either a wiki page title, or a URL to an external wiki * page title. * @param array $data information about the current request. * language, gateway, payment_method, and payment_submethod must be set * @param Psr\Log\LoggerInterface $logger * @return string full URL of the fail page, or just form name in case of rapidFail */ private static function getFailPageFromParams($rapidFail, $failPage, $data, LoggerInterface $logger) { if (isset($data['language'])) { $language = $data['language']; } else { $language = WmfFramework::getLanguageCode(); } // Prefer RapidFail. if ($rapidFail) { // choose which fail page to go for. try { $fail_ffname = GatewayFormChooser::getBestErrorForm($data['gateway'], $data['payment_method'], $data['payment_submethod']); return $fail_ffname; } catch (Exception $e) { $logger->error('Cannot determine best error form. ' . $e->getMessage()); } } if (filter_var($failPage, FILTER_VALIDATE_URL)) { return self::appendLanguageAndMakeURL($failPage, $language); } // FIXME: either add Special:FailPage to avoid depending on wiki content, // or update the content on payments to be consistent with the /lang // format of ThankYou pages so we can use appendLanguageAndMakeURL here. $failTitle = Title::newFromText($failPage); $url = wfAppendQuery($failTitle->getFullURL(), array('uselang' => $language)); return $url; }
/** * Target URL for a link provided by a support button/aid. * * @param $title Title Title object for the translation message. * @since 2015.09 */ public static function getSupportUrl(Title $title) { global $wgTranslateSupportUrl, $wgTranslateSupportUrlNamespace; $namespace = $title->getNamespace(); // Fetch the configuration for this namespace if possible, or the default. if (isset($wgTranslateSupportUrlNamespace[$namespace])) { $config = $wgTranslateSupportUrlNamespace[$namespace]; } elseif ($wgTranslateSupportUrl) { $config = $wgTranslateSupportUrl; } else { throw new TranslationHelperException("Support page not configured"); } // Preprocess params $params = array(); if (isset($config['params'])) { foreach ($config['params'] as $key => $value) { $params[$key] = str_replace('%MESSAGE%', $title->getPrefixedText(), $value); } } // Return the URL or make one from the page if (isset($config['url'])) { return wfAppendQuery($config['url'], $params); } elseif (isset($config['page'])) { $page = Title::newFromText($config['page']); if (!$page) { throw new TranslationHelperException("Support page not configured properly"); } return $page->getFullUrl($params); } else { throw new TranslationHelperException("Support page not configured properly"); } }
protected function fetchScriptList() { $data = ['action' => 'query', 'format' => 'json', 'list' => 'allpages', 'apnamespace' => '8', 'aplimit' => '500', 'continue' => '']; $baseUrl = $this->getArg(0); $pages = []; while (true) { $url = wfAppendQuery($baseUrl, $data); $strResult = Http::get($url, [], __METHOD__); $result = FormatJson::decode($strResult, true); $page = null; foreach ($result['query']['allpages'] as $page) { if (substr($page['title'], -3) === '.js') { strtok($page['title'], ':'); $pages[] = strtok(''); } } if ($page !== null) { $this->output("Fetched list up to {$page['title']}\n"); } if (isset($result['continue'])) { // >= 1.21 $data = array_replace($data, $result['continue']); } elseif (isset($result['query-continue']['allpages'])) { // <= 1.20 $data = array_replace($data, $result['query-continue']['allpages']); } else { break; } } return $pages; }
public function execute( $par ) { global $wgOut, $wgRequest; global $wgVariablePagePossibilities; $lang = ( preg_match( '/^[A-Za-z-]+$/', $wgRequest->getVal( 'lang' ) ) ) ? $wgRequest->getVal( 'lang' ) : 'en' ; $utm_source = $wgRequest->getVal( 'utm_source' ); $utm_medium = $wgRequest->getVal( 'utm_medium' ); $utm_campaign = $wgRequest->getVal( 'utm_campaign' ); $referrer = ( $wgRequest->getVal( 'referrer' )) ? $wgRequest->getVal( 'referrer' ) : $wgRequest->getHeader( 'referer' ); $query = array(); if ( strlen( $lang ) ) $query[ 'language' ] = $lang; if ( strlen( $utm_source ) ) $query[ 'utm_source' ] = $utm_source; if ( strlen( $utm_medium ) ) $query[ 'utm_medium' ] = $utm_medium; if ( strlen( $utm_campaign ) ) $query[ 'utm_campaign' ] = $utm_campaign; if ( strlen( $referrer ) ) $query[ 'referrer' ] = $referrer; // determine the URL to which we will redirect the user $url = $this->determinePage( $wgVariablePagePossibilities ); $wgOut->redirect( wfAppendQuery( $url, $query ) ); }
public function execute() { global $wgUser, $wgArticleFeedbackRatingTypes, $wgArticleFeedbackSMaxage, $wgArticleFeedbackNamespaces; $params = $this->extractRequestParams(); // Anon token check if ($wgUser->isAnon()) { if (!isset($params['anontoken'])) { $this->dieUsageMsg(array('missingparam', 'anontoken')); } elseif (strlen($params['anontoken']) != 32) { $this->dieUsage('The anontoken is not 32 characters', 'invalidtoken'); } $token = $params['anontoken']; } else { $token = ''; } // Load check, is this page ArticleFeedback-enabled ? // Keep in sync with ext.articleFeedback.startup.js $title = Title::newFromID($params['pageid']); if (is_null($title) || !in_array($title->getNamespace(), $wgArticleFeedbackNamespaces) || $title->isRedirect()) { // ...then error out $this->dieUsage('ArticleFeedback is not enabled on this page', 'invalidpage'); } $dbw = wfGetDB(DB_MASTER); // Query the latest ratings by this user for this page, // possibly for an older revision // Select from the master to prevent replag-induced bugs $res = $dbw->select('article_feedback', array('aa_rating_id', 'aa_rating_value', 'aa_revision'), array('aa_user_text' => $wgUser->getName(), 'aa_page_id' => $params['pageid'], 'aa_rating_id' => array_keys($wgArticleFeedbackRatingTypes), 'aa_user_anon_token' => $token), __METHOD__, array('ORDER BY' => 'aa_revision DESC', 'LIMIT' => count($wgArticleFeedbackRatingTypes))); $lastRatings = array(); foreach ($res as $row) { $lastRatings[$row->aa_rating_id]['value'] = $row->aa_rating_value; $lastRatings[$row->aa_rating_id]['revision'] = $row->aa_revision; } $pageId = $params['pageid']; $revisionId = $params['revid']; foreach ($wgArticleFeedbackRatingTypes as $ratingID => $unused) { $lastPageRating = false; $lastRevRating = false; if (isset($lastRatings[$ratingID])) { $lastPageRating = intval($lastRatings[$ratingID]['value']); if (intval($lastRatings[$ratingID]['revision']) == $revisionId) { $lastRevRating = $lastPageRating; } } $thisRating = false; if (isset($params["r{$ratingID}"])) { $thisRating = intval($params["r{$ratingID}"]); } $this->insertRevisionRating($pageId, $revisionId, $ratingID, $thisRating - $lastRevRating, $thisRating, $lastRevRating); $this->insertPageRating($pageId, $ratingID, $thisRating - $lastPageRating, $thisRating, $lastPageRating); $this->insertUserRatings($pageId, $revisionId, $wgUser, $token, $ratingID, $thisRating, $params['bucket']); } $this->insertProperties($revisionId, $wgUser, $token, $params); $squidUpdate = new SquidUpdate(array(wfAppendQuery(wfScript('api'), array('action' => 'query', 'format' => 'json', 'list' => 'articlefeedback', 'afpageid' => $pageId, 'afanontoken' => '', 'afuserrating' => 0, 'maxage' => 0, 'smaxage' => $wgArticleFeedbackSMaxage)))); $squidUpdate->doUpdate(); wfRunHooks('ArticleFeedbackChangeRating', array($params)); $r = array('result' => 'Success'); $this->getResult()->addValue(null, $this->getModuleName(), $r); }
/** * Get the API URL constructed from the domain template of sites */ public static function getApiURL($language, $params = null) { global $wgContentTranslationSiteTemplates; $domain = self::getDomainCode($language); // $wgContentTranslationSiteTemplates['api'] is protocol relative path $url = 'https:' . str_replace('$1', $domain, $wgContentTranslationSiteTemplates['api']); $url = wfAppendQuery($url, $params); return $url; }
private function doRequest($apiUrl) { $params = array('action' => 'query', 'list' => 'allpages', 'apnamespace' => 120, 'aplimit' => 300, 'format' => 'json', 'rawcontinue' => 1); if (isset($this->continuation) && $this->continuation !== null) { $params['apfrom'] = $this->continuation; } $json = Http::get(wfAppendQuery($apiUrl, $params), array(), __METHOD__); return json_decode($json, true); }
private function doRequest(array $ids) { $params = array('action' => 'wbgetentities', 'ids' => implode('|', $ids), 'format' => 'json'); $json = Http::get(wfAppendQuery($this->apiUrl, $params), array(), __METHOD__); $data = json_decode($json, true); if ($data) { return $data; } $this->logger->error('Failed to decode json api response'); }
/** @brief Fetch the edit form and return the text in #wpTextbox1. @param title The page to be opened for editing. */ public function getPreloadedText($title) { $url = wfAppendQuery(wfScript('index'), array('title' => $title, 'action' => 'edit')); $this->loadFromURL($url); $elem = $this->getElementById('wpTextbox1'); if (!$elem) { return null; } return trim($elem->textContent); }
function wfCSSRender(&$parser, $css) { global $wgCSSPath, $wgStylePath, $wgCSSIdentifier; $css = trim($css); $title = Title::newFromText($css); $rawProtection = "{$wgCSSIdentifier}=1"; $headItem = '<!-- Begin Extension:CSS -->'; if (is_object($title) && $title->exists()) { # Article actually in the db $params = "action=raw&ctype=text/css&{$rawProtection}"; $url = $title->getLocalURL($params); $headItem .= HTML::linkedStyle($url); } elseif ($css[0] == '/') { # Regular file $base = $wgCSSPath === false ? $wgStylePath : $wgCSSPath; $url = wfAppendQuery($base . $css, $rawProtection); # Verify the expanded URL is still using the base URL if (strpos(wfExpandUrl($url), wfExpandUrl($base)) === 0) { $headItem .= HTML::linkedStyle($url); } else { $headItem .= '<!-- Invalid/malicious path -->'; } } else { # Inline CSS; use data URI to prevent injection. JavaScript # will use a canary to verify load and will safely convert to # style tag if load fails. # Generate random CSS color that isn't black or white. $color = dechex(mt_rand(1, hexdec('fffffe'))); $color = str_pad($color, 6, '0', STR_PAD_LEFT); # Prepend canary CSS to sanitized user CSS $canaryId = "{$wgCSSIdentifier}-canary-{$color}"; $canaryCSS = "#{$canaryId}{background:#{$color} !important}"; $css = $canaryCSS . Sanitizer::checkCss($css); # Encode data URI and append link tag $dataPrefix = 'data:text/css;charset=UTF-8;base64,'; $url = $dataPrefix . base64_encode($css); $headItem .= HTML::linkedStyle($url); # Calculate URI prefix to match link tag $hrefPrefix = $dataPrefix . base64_encode('#' . $canaryId); $hrefPrefix = substr($url, 0, strlen($hrefPrefix)); # Add JS to verify the link tag loaded and fallback if needed $parser->getOutput()->addModules('ext.CSS'); $headItem .= HTML::inlineScript(<<<INLINESCRIPT jQuery( function( \$ ) { \t\$( 'link[href^="{$hrefPrefix}"]' ) \t\t.cssExtensionDataURIFallback( '{$canaryId}', '{$color}' ); } ); INLINESCRIPT ); } $headItem .= '<!-- End Extension:CSS -->'; $parser->getOutput()->addHeadItem($headItem); return ''; }
/** * Hook function called with &match=lang * Transform $text into a bilingual version * @param $out OutputPage * @param $text */ function addMatchedText(&$out, &$text) { global $wgContLang, $wgContLanguageCode, $wgRequest, $wgLang, $wgMemc, $wgDoubleWikiCacheTime; $match_request = $wgRequest->getText('match'); if ($match_request === '') { return true; } $this->addMatchingTags($text, $match_request); $langLinks = $out->getLanguageLinks(); foreach ($langLinks as $l) { $nt = Title::newFromText($l); $iw = $nt->getInterwiki(); if ($iw !== $match_request) { continue; } $key = wfMemcKey('doublewiki', $wgLang->getCode(), $nt->getPrefixedDbKey()); $cachedText = $wgMemc->get($key); if ($cachedText) { $text = $cachedText; } else { $url = $nt->getCanonicalURL(); $myURL = $out->getTitle()->getLocalURL(); $languageName = $wgContLang->getLanguageName($iw); $myLanguage = $wgLang->getLanguageName($wgContLang->getCode()); $translation = Http::get(wfAppendQuery($url, array('action' => 'render'))); if ($translation !== null) { break; } /** * first find all links that have no 'class' parameter. * these links are local so we add '?match=xx' to their url, * unless it already contains a '?' */ $translation = preg_replace("/<a href=\"http:\\/\\/([^\"\\?]*)\"(([\\s]+)(c(?!lass=)|[^c\\>\\s])([^\\>\\s]*))*\\>/i", "<a href=\"http://\\1?match={$wgContLanguageCode}\"\\2>", $translation); // now add class='extiw' to these links $translation = preg_replace("/<a href=\"http:\\/\\/([^\"]*)\"(([\\s]+)(c(?!lass=)|[^c\\>\\s])([^\\>\\s]*))*\\>/i", "<a href=\"http://\\1\" class=\"extiw\"\\3>", $translation); // use class='extiw' for images too $translation = preg_replace("/<a href=\"http:\\/\\/([^\"]*)\"([^\\>]*)class=\"image\"([^\\>]*)\\>/i", "<a href=\"http://\\1\"\\2class=\"extiw\"\\3>", $translation); // add prefixes to internal links, in order to prevent duplicates $translation = preg_replace("/<a href=\"#(.*?)\"/i", "<a href=\"#l_\\1\"", $translation); $translation = preg_replace("/<li id=\"(.*?)\"/i", "<li id=\"l_\\1\"", $translation); $text = preg_replace("/<a href=\"#(.*?)\"/i", "<a href=\"#r_\\1\"", $text); $text = preg_replace("/<li id=\"(.*?)\"/i", "<li id=\"r_\\1\"", $text); // add ?match= to local links of the local wiki $text = preg_replace("/<a href=\"\\/([^\"\\?]*)\"/i", "<a href=\"/\\1?match={$match_request}\"", $text); // do the job $text = $this->matchColumns($text, $myLanguage, $myURL, $wgContLanguageCode, $translation, $languageName, $url, $match_request); $wgMemc->set($key, $text, $wgDoubleWikiCacheTime); } break; } return true; }
/** * Purpose: Add custom tabs * * When editing in read-only data-set, if you have the copy permission, you can * make a copy into the designated community dataset and edit the data there. * This is accessible through an 'edit copy' tab which is added below. * * @param $skin Skin as passed by MW * @param $tabs as passed by MW */ public static function onSkinTemplateTabs( $skin, $content_actions ) { global $wgUser, $wgCommunity_dc, $wdShowEditCopy, $wdHandlerClasses; $title = $skin->getTitle(); if ( !self::isWikidataNs( $title ) ) { return true; } $ns = $title->getNamespace(); $editChanged = false; $dc = wdGetDataSetContext(); if ( $wdHandlerClasses[ $ns ] == 'DefinedMeaning' ) { # Hackishly determine which DMID we're on by looking at the page title component $tt = $title->getText(); $rpos1 = strrpos( $tt, '(' ); $rpos2 = strrpos( $tt, ')' ); $dmid = ( $rpos1 && $rpos2 ) ? substr( $tt, $rpos1 + 1, $rpos2 - $rpos1 - 1 ) : 0; if ( $dmid ) { $copyTitle = SpecialPage::getTitleFor( 'Copy' ); if ( $dc != $wgCommunity_dc && $wdShowEditCopy ) { $editChanged = true; $content_actions['edit'] = array( 'class' => false, 'text' => wfMsg( 'ow_nstab_edit_copy' ), 'href' => $copyTitle->getLocalUrl( "action=copy&dmid=$dmid&dc1=$dc&dc2=$wgCommunity_dc" ) ); } $content_actions['nstab-definedmeaning'] = array( 'class' => 'selected', 'text' => wfMsg( 'ow_nstab_definedmeaning' ), 'href' => $title->getLocalUrl( "dataset=$dc" ) ); } } // Prevent move tab being shown. unset( $content_actions['move'] ); // Add context dataset (old hooks 'GetEditLinkTrail' and 'GetHistoryLinkTrail') if ( !$editChanged && $content_actions['edit'] != null ) { $content_actions['edit']['href'] = wfAppendQuery( $content_actions['edit']['href'], "dataset=$dc" ); } $content_actions['history']['href'] = wfAppendQuery( $content_actions['history']['href'], "dataset=$dc" ); return true; }
protected function requestParsoid($method, $title, $params) { global $wgVisualEditorParsoidURL, $wgVisualEditorParsoidTimeout, $wgVisualEditorParsoidForwardCookies; $url = $wgVisualEditorParsoidURL . '/' . urlencode($this->getApiSource()) . '/' . urlencode($title->getPrefixedDBkey()); $data = array_merge($this->getProxyConf(), array('method' => $method, 'timeout' => $wgVisualEditorParsoidTimeout)); if ($method === 'POST') { $data['postData'] = $params; } else { $url = wfAppendQuery($url, $params); } $req = MWHttpRequest::factory($url, $data); // Forward cookies, but only if configured to do so and if there are read restrictions if ($wgVisualEditorParsoidForwardCookies && !User::isEveryoneAllowed('read')) { $req->setHeader('Cookie', $this->getRequest()->getHeader('Cookie')); } $status = $req->execute(); if ($status->isOK()) { // Pass thru performance data from Parsoid to the client, unless the response was // served directly from Varnish, in which case discard the value of the XPP header // and use it to declare the cache hit instead. $xCache = $req->getResponseHeader('X-Cache'); if (is_string($xCache) && strpos(strtolower($xCache), 'hit') !== false) { $xpp = 'cached-response=true'; $hit = true; } else { $xpp = $req->getResponseHeader('X-Parsoid-Performance'); $hit = false; } WikiaLogger::instance()->debug('ApiVisualEditor', array('hit' => $hit, 'method' => $method, 'url' => $url)); if ($xpp !== null) { $resp = $this->getRequest()->response(); $resp->header('X-Parsoid-Performance: ' . $xpp); } } elseif ($status->isGood()) { $this->dieUsage($req->getContent(), 'parsoidserver-http-' . $req->getStatus()); } elseif ($errors = $status->getErrorsByType('error')) { $error = $errors[0]; $code = $error['message']; if (count($error['params'])) { $message = $error['params'][0]; } else { $message = 'MWHttpRequest error'; } $this->dieUsage($message, 'parsoidserver-' . $code); } // TODO pass through X-Parsoid-Performance header, merge with getHTML above return $req->getContent(); }
/** * Main execution point * * @param string $subpage */ public function execute($subpage) { // Backwards-compatibility: redirect to new feed URLs $feedFormat = $this->getRequest()->getVal('feed'); if (!$this->including() && $feedFormat) { $query = $this->getFeedQuery(); $query['feedformat'] = $feedFormat === 'atom' ? 'atom' : 'rss'; $this->getOutput()->redirect(wfAppendQuery(wfScript('api'), $query)); return; } // 10 seconds server-side caching max $this->getOutput()->setSquidMaxage(10); // Check if the client has a cached version $lastmod = $this->checkLastModified(); if ($lastmod === false) { return; } parent::execute($subpage); }
public function execute($par) { $redirect = $this->getRedirect($par); $query = $this->getRedirectQuery(); // Redirect to a page title with possible query parameters if ($redirect instanceof Title) { $url = $redirect->getFullURL($query); $this->getOutput()->redirect($url); return $redirect; } elseif ($redirect === true) { // Redirect to index.php with query parameters $url = wfAppendQuery(wfScript('index'), $query); $this->getOutput()->redirect($url); return $redirect; } else { $class = get_class($this); throw new MWException("RedirectSpecialPage {$class} doesn't redirect!"); } }
/** * Main execution point * * @param string $subpage */ public function execute($subpage) { // Backwards-compatibility: redirect to new feed URLs $feedFormat = $this->getRequest()->getVal('feed'); if (!$this->including() && $feedFormat) { $query = $this->getFeedQuery(); $query['feedformat'] = $feedFormat === 'atom' ? 'atom' : 'rss'; $this->getOutput()->redirect(wfAppendQuery(wfScript('api'), $query)); return; } // 10 seconds server-side caching max $this->getOutput()->setCdnMaxage(10); // Check if the client has a cached version $lastmod = $this->checkLastModified(); if ($lastmod === false) { return; } $this->addHelpLink('//meta.wikimedia.org/wiki/Special:MyLanguage/Help:Recent_changes', true); parent::execute($subpage); }
/** * Returns the normalized form of the given page title, using the * normalization rules of the given site. If the given title is a redirect, * the redirect weill be resolved and the redirect target is returned. * * @note This actually makes an API request to the remote site, so beware * that this function is slow and depends on an external service. * * @see Site::normalizePageName * * @since 1.27 * * @param string $pageName * @param string $apiUrl * * @return string * @throws \MWException */ public function normalizePageName($pageName, $apiUrl) { // Check if we have strings as arguments. if (!is_string($pageName)) { throw new \MWException('$pageName must be a string'); } // Go on call the external site // Make sure the string is normalized into NFC (due to T42017) // but do nothing to the whitespaces, that should work appropriately. // @see https://phabricator.wikimedia.org/T42017 $pageName = Validator::cleanUp($pageName); // Build the args for the specific call $args = ['action' => 'query', 'prop' => 'info', 'redirects' => true, 'converttitles' => true, 'format' => 'json', 'titles' => $pageName]; $url = wfAppendQuery($apiUrl, $args); // Go on call the external site // @todo we need a good way to specify a timeout here. $ret = $this->http->get($url, [], __METHOD__); if ($ret === false) { wfDebugLog("MediaWikiSite", "call to external site failed: {$url}"); return false; } $data = FormatJson::decode($ret, true); if (!is_array($data)) { wfDebugLog("MediaWikiSite", "call to <{$url}> returned bad json: " . $ret); return false; } $page = static::extractPageRecord($data, $pageName); if (isset($page['missing'])) { wfDebugLog("MediaWikiSite", "call to <{$url}> returned a marker for a missing page title! " . $ret); return false; } if (isset($page['invalid'])) { wfDebugLog("MediaWikiSite", "call to <{$url}> returned a marker for an invalid page title! " . $ret); return false; } if (!isset($page['title'])) { wfDebugLog("MediaWikiSite", "call to <{$url}> did not return a page title! " . $ret); return false; } return $page['title']; }
/** * Some extra tabs for editing * @param &$sktemplate SkinTemplate * @param &$links array * @return bool */ public static function onSkinTemplateNavigation(&$sktemplate, &$links) { $title = $sktemplate->getTitle(); $request = $sktemplate->getRequest(); if (isset($links['views']['edit'])) { if ($title->hasContentModel('CollaborationListContent') || $title->hasContentModel('CollaborationHubContent')) { // Edit as JSON $active = in_array($request->getVal('action'), ['edit', 'submit']) && $request->getVal('format') === 'application/json'; $links['actions']['editasjson'] = ['class' => $active ? 'selected' : false, 'href' => wfAppendQuery($links['views']['edit']['href'], ['format' => 'application/json']), 'text' => wfMessage('collaborationkit-editjsontab')->text()]; if ($active) { // Make it not be selected when editing json. $links['views']['edit']['class'] = false; } } if ($title->hasContentModel('CollaborationHubContent')) { // Add feature $links['actions']['addnewfeature'] = ['class' => '', 'href' => SpecialPage::getTitleFor('CreateHubFeature')->getFullUrl(['collaborationhub' => $title->getFullText()]), 'text' => wfMessage('collaborationkit-hub-addpage')->text()]; } } return true; }
/** * <inputbox type=create...> sends requests with action=edit, and * possibly a &prefix=Foo. So we pick that up here, munge prefix * and title together, and redirect back out to the real page * @param $output OutputPage * @param $article Article * @param $title Title * @param $user User * @param $request WebRequest * @param $wiki MediaWiki * @return bool */ public static function onMediaWikiPerformAction($output, $article, $title, $user, $request, $wiki) { if ($wiki->getAction($request) !== 'edit') { # not our problem return true; } if ($request->getText('prefix', '') === '') { # Fine return true; } $params = $request->getValues(); $title = $params['prefix']; if (isset($params['title'])) { $title .= $params['title']; } unset($params['prefix']); $params['title'] = $title; global $wgScript; $output->redirect(wfAppendQuery($wgScript, $params), '301'); return false; }
public function execute($par) { if (empty($par)) { $par = 'main'; } // These come from transclusions $request = $this->getRequest(); $options = ['action' => 'help', 'nolead' => true, 'submodules' => $request->getCheck('submodules'), 'recursivesubmodules' => $request->getCheck('recursivesubmodules'), 'title' => $request->getVal('title', $this->getPageTitle('$1')->getPrefixedText())]; // These are for linking from wikitext, since url parameters are a pain // to do. while (true) { if (substr($par, 0, 4) === 'sub/') { $par = substr($par, 4); $options['submodules'] = 1; continue; } if (substr($par, 0, 5) === 'rsub/') { $par = substr($par, 5); $options['recursivesubmodules'] = 1; continue; } $moduleName = $par; break; } if (!$this->including()) { unset($options['nolead'], $options['title']); $options['modules'] = $moduleName; $link = wfAppendQuery(wfExpandUrl(wfScript('api'), PROTO_CURRENT), $options); $this->getOutput()->redirect($link); return; } $main = new ApiMain($this->getContext(), false); try { $module = $main->getModuleFromPath($moduleName); } catch (UsageException $ex) { $this->getOutput()->addHTML(Html::rawElement('span', ['class' => 'error'], $this->msg('apihelp-no-such-module', $moduleName)->inContentLanguage()->parse())); return; } ApiHelp::getHelp($this->getContext(), $module, $options); }
/** * Handle Special:Redirect/logid/xxx * (by redirecting to index.php?title=Special:Log) * * @since 1.27 * @return string|null Url to redirect to, or null if $mValue is invalid. */ function dispatchLog() { $logid = $this->mValue; if (!ctype_digit($logid)) { return null; } $logid = (int) $logid; if ($logid === 0) { return null; } $logparams = ['log_id', 'log_timestamp', 'log_type', 'log_user_text']; $dbr = wfGetDB(DB_REPLICA); // Gets the nested SQL statement which // returns timestamp of the log with the given log ID $inner = $dbr->selectSQLText('logging', ['log_timestamp'], ['log_id' => $logid]); // Returns all fields mentioned in $logparams of the logs // with the same timestamp as the one returned by the statement above $logsSameTimestamps = $dbr->select('logging', $logparams, ["log_timestamp = ({$inner})"]); if ($logsSameTimestamps->numRows() === 0) { return null; } // Stores the row with the same log ID as the one given $rowMain = []; foreach ($logsSameTimestamps as $row) { if ((int) $row->log_id === $logid) { $rowMain = $row; } } array_shift($logparams); // Stores all the rows with the same values in each column // as $rowMain foreach ($logparams as $cond) { $matchedRows = []; foreach ($logsSameTimestamps as $row) { if ($row->{$cond} === $rowMain->{$cond}) { $matchedRows[] = $row; } } if (count($matchedRows) === 1) { break; } $logsSameTimestamps = $matchedRows; } $query = ['title' => 'Special:Log', 'limit' => count($matchedRows)]; // A map of database field names from table 'logging' to the values of $logparams $keys = ['log_timestamp' => 'offset', 'log_type' => 'type', 'log_user_text' => 'user']; foreach ($logparams as $logKey) { $query[$keys[$logKey]] = $matchedRows[0]->{$logKey}; } $query['offset'] = $query['offset'] + 1; $url = $query; return wfAppendQuery(wfScript('index'), $url); }
/** * @return string */ function getTransformScript() { if (!isset($this->transformScript)) { $this->transformScript = false; if ($this->repo) { $script = $this->repo->getThumbScriptUrl(); if ($script) { $this->transformScript = wfAppendQuery($script, array('f' => $this->getName())); } } } return $this->transformScript; }
/** * @return array Array in format "link name or number => 'link html'". */ public function getHeadLinksArray() { global $wgVersion; $tags = array(); $config = $this->getConfig(); $canonicalUrl = $this->mCanonicalUrl; $tags['meta-generator'] = Html::element('meta', array('name' => 'generator', 'content' => "MediaWiki {$wgVersion}")); if ($config->get('ReferrerPolicy') !== false) { $tags['meta-referrer'] = Html::element('meta', array('name' => 'referrer', 'content' => $config->get('ReferrerPolicy'))); } $p = "{$this->mIndexPolicy},{$this->mFollowPolicy}"; if ($p !== 'index,follow') { // http://www.robotstxt.org/wc/meta-user.html // Only show if it's different from the default robots policy $tags['meta-robots'] = Html::element('meta', array('name' => 'robots', 'content' => $p)); } foreach ($this->mMetatags as $tag) { if (0 == strcasecmp('http:', substr($tag[0], 0, 5))) { $a = 'http-equiv'; $tag[0] = substr($tag[0], 5); } else { $a = 'name'; } $tagName = "meta-{$tag[0]}"; if (isset($tags[$tagName])) { $tagName .= $tag[1]; } $tags[$tagName] = Html::element('meta', array($a => $tag[0], 'content' => $tag[1])); } foreach ($this->mLinktags as $tag) { $tags[] = Html::element('link', $tag); } # Universal edit button if ($config->get('UniversalEditButton') && $this->isArticleRelated()) { $user = $this->getUser(); if ($this->getTitle()->quickUserCan('edit', $user) && ($this->getTitle()->exists() || $this->getTitle()->quickUserCan('create', $user))) { // Original UniversalEditButton $msg = $this->msg('edit')->text(); $tags['universal-edit-button'] = Html::element('link', array('rel' => 'alternate', 'type' => 'application/x-wiki', 'title' => $msg, 'href' => $this->getTitle()->getEditURL())); // Alternate edit link $tags['alternative-edit'] = Html::element('link', array('rel' => 'edit', 'title' => $msg, 'href' => $this->getTitle()->getEditURL())); } } # Generally the order of the favicon and apple-touch-icon links # should not matter, but Konqueror (3.5.9 at least) incorrectly # uses whichever one appears later in the HTML source. Make sure # apple-touch-icon is specified first to avoid this. if ($config->get('AppleTouchIcon') !== false) { $tags['apple-touch-icon'] = Html::element('link', array('rel' => 'apple-touch-icon', 'href' => $config->get('AppleTouchIcon'))); } if ($config->get('Favicon') !== false) { $tags['favicon'] = Html::element('link', array('rel' => 'shortcut icon', 'href' => $config->get('Favicon'))); } # OpenSearch description link $tags['opensearch'] = Html::element('link', array('rel' => 'search', 'type' => 'application/opensearchdescription+xml', 'href' => wfScript('opensearch_desc'), 'title' => $this->msg('opensearch-desc')->inContentLanguage()->text())); if ($config->get('EnableAPI')) { # Real Simple Discovery link, provides auto-discovery information # for the MediaWiki API (and potentially additional custom API # support such as WordPress or Twitter-compatible APIs for a # blogging extension, etc) $tags['rsd'] = Html::element('link', array('rel' => 'EditURI', 'type' => 'application/rsd+xml', 'href' => wfExpandUrl(wfAppendQuery(wfScript('api'), array('action' => 'rsd')), PROTO_RELATIVE))); } # Language variants if (!$config->get('DisableLangConversion')) { $lang = $this->getTitle()->getPageLanguage(); if ($lang->hasVariants()) { $variants = $lang->getVariants(); foreach ($variants as $_v) { $tags["variant-{$_v}"] = Html::element('link', array('rel' => 'alternate', 'hreflang' => wfBCP47($_v), 'href' => $this->getTitle()->getLocalURL(array('variant' => $_v)))); } } # x-default link per https://support.google.com/webmasters/answer/189077?hl=en $tags["variant-x-default"] = Html::element('link', array('rel' => 'alternate', 'hreflang' => 'x-default', 'href' => $this->getTitle()->getLocalURL())); } # Copyright if ($this->copyrightUrl !== null) { $copyright = $this->copyrightUrl; } else { $copyright = ''; if ($config->get('RightsPage')) { $copy = Title::newFromText($config->get('RightsPage')); if ($copy) { $copyright = $copy->getLocalURL(); } } if (!$copyright && $config->get('RightsUrl')) { $copyright = $config->get('RightsUrl'); } } if ($copyright) { $tags['copyright'] = Html::element('link', array('rel' => 'copyright', 'href' => $copyright)); } # Feeds if ($config->get('Feed')) { foreach ($this->getSyndicationLinks() as $format => $link) { # Use the page name for the title. In principle, this could # lead to issues with having the same name for different feeds # corresponding to the same page, but we can't avoid that at # this low a level. $tags[] = $this->feedLink($format, $link, $this->msg("page-{$format}-feed", $this->getTitle()->getPrefixedText())->text()); } # Recent changes feed should appear on every page (except recentchanges, # that would be redundant). Put it after the per-page feed to avoid # changing existing behavior. It's still available, probably via a # menu in your browser. Some sites might have a different feed they'd # like to promote instead of the RC feed (maybe like a "Recent New Articles" # or "Breaking news" one). For this, we see if $wgOverrideSiteFeed is defined. # If so, use it instead. $sitename = $config->get('Sitename'); if ($config->get('OverrideSiteFeed')) { foreach ($config->get('OverrideSiteFeed') as $type => $feedUrl) { // Note, this->feedLink escapes the url. $tags[] = $this->feedLink($type, $feedUrl, $this->msg("site-{$type}-feed", $sitename)->text()); } } elseif (!$this->getTitle()->isSpecial('Recentchanges')) { $rctitle = SpecialPage::getTitleFor('Recentchanges'); foreach ($config->get('AdvertisedFeedTypes') as $format) { $tags[] = $this->feedLink($format, $rctitle->getLocalURL(array('feed' => $format)), $this->msg("site-{$format}-feed", $sitename)->text()); } } } # Canonical URL if ($config->get('EnableCanonicalServerLink')) { if ($canonicalUrl !== false) { $canonicalUrl = wfExpandUrl($canonicalUrl, PROTO_CANONICAL); } else { if ($this->isArticleRelated()) { // This affects all requests where "setArticleRelated" is true. This is // typically all requests that show content (query title, curid, oldid, diff), // and all wikipage actions (edit, delete, purge, info, history etc.). // It does not apply to File pages and Special pages. // 'history' and 'info' actions address page metadata rather than the page // content itself, so they may not be canonicalized to the view page url. // TODO: this ought to be better encapsulated in the Action class. $action = Action::getActionName($this->getContext()); if (in_array($action, array('history', 'info'))) { $query = "action={$action}"; } else { $query = ''; } $canonicalUrl = $this->getTitle()->getCanonicalURL($query); } else { $reqUrl = $this->getRequest()->getRequestURL(); $canonicalUrl = wfExpandUrl($reqUrl, PROTO_CANONICAL); } } } if ($canonicalUrl !== false) { $tags[] = Html::element('link', array('rel' => 'canonical', 'href' => $canonicalUrl)); } return $tags; }
/** * Prepares links used in the mobile footer * @param QuickTemplate $tpl */ protected function prepareMobileFooterLinks($tpl) { $req = $this->getRequest(); $url = $this->getOutput()->getProperty('desktopUrl'); if ($url) { $url = wfAppendQuery($url, 'mobileaction=toggle_view_desktop'); } else { $url = $this->getTitle()->getLocalUrl($req->appendQueryValue('mobileaction', 'toggle_view_desktop', true)); } $url = htmlspecialchars($this->mobileContext->getDesktopUrl(wfExpandUrl($url, PROTO_RELATIVE))); $desktop = wfMessage('mobile-frontend-view-desktop')->escaped(); $mobile = wfMessage('mobile-frontend-view-mobile')->escaped(); $switcherHtml = <<<HTML <h2>{$this->getSitename(true)}</h2> <ul> \t<li>{$mobile}</li><li><a id="mw-mf-display-toggle" href="{$url}">{$desktop}</a></li> </ul> HTML; // Generate the licensing text displayed in the footer of each page. // See Skin::getCopyright for desktop equivalent. $license = self::getLicense('footer'); if (isset($license['link']) && $license['link']) { $licenseText = $this->msg('mobile-frontend-copyright')->rawParams($license['link'])->text(); } else { $licenseText = ''; } // Enable extensions to add links to footer in Mobile view, too - bug 66350 Hooks::run('SkinMinervaOutputPageBeforeExec', array(&$this, &$tpl)); $tpl->set('mobile-switcher', $switcherHtml); $tpl->set('mobile-license', $licenseText); $tpl->set('privacy', $this->footerLink('mobile-frontend-privacy-link-text', 'privacypage')); $tpl->set('terms-use', $this->getTermsLink()); }
/** * Recursively-called function to actually construct the help * * @param IContextSource $context * @param ApiBase[] $modules * @param array $options * @param array &$haveModules * @return string */ private static function getHelpInternal(IContextSource $context, array $modules, array $options, &$haveModules) { $out = ''; $level = empty($options['headerlevel']) ? 2 : $options['headerlevel']; if (empty($options['tocnumber'])) { $tocnumber = array(2 => 0); } else { $tocnumber =& $options['tocnumber']; } foreach ($modules as $module) { $tocnumber[$level]++; $path = $module->getModulePath(); $module->setContext($context); $help = array('header' => '', 'flags' => '', 'description' => '', 'help-urls' => '', 'parameters' => '', 'examples' => '', 'submodules' => ''); if (empty($options['noheader']) || !empty($options['toc'])) { $anchor = $path; $i = 1; while (isset($haveModules[$anchor])) { $anchor = $path . '|' . ++$i; } if ($module->isMain()) { $header = $context->msg('api-help-main-header')->parse(); } else { $name = $module->getModuleName(); $header = $module->getParent()->getModuleManager()->getModuleGroup($name) . "={$name}"; if ($module->getModulePrefix() !== '') { $header .= ' ' . $context->msg('parentheses', $module->getModulePrefix())->parse(); } } $haveModules[$anchor] = array('toclevel' => count($tocnumber), 'level' => $level, 'anchor' => $anchor, 'line' => $header, 'number' => join('.', $tocnumber), 'index' => false); if (empty($options['noheader'])) { $help['header'] .= Html::element('h' . min(6, $level), array('id' => $anchor, 'class' => 'apihelp-header'), $header); } } else { $haveModules[$path] = true; } $links = array(); $any = false; for ($m = $module; $m !== null; $m = $m->getParent()) { $name = $m->getModuleName(); if ($name === 'main_int') { $name = 'main'; } if (count($modules) === 1 && $m === $modules[0] && !(!empty($options['submodules']) && $m->getModuleManager())) { $link = Html::element('b', null, $name); } else { $link = SpecialPage::getTitleFor('ApiHelp', $m->getModulePath())->getLocalURL(); $link = Html::element('a', array('href' => $link, 'class' => 'apihelp-linktrail'), $name); $any = true; } array_unshift($links, $link); } if ($any) { $help['header'] .= self::wrap($context->msg('parentheses')->rawParams($context->getLanguage()->pipeList($links)), 'apihelp-linktrail', 'div'); } $flags = $module->getHelpFlags(); $help['flags'] .= Html::openElement('div', array('class' => 'apihelp-block apihelp-flags')); $msg = $context->msg('api-help-flags'); if (!$msg->isDisabled()) { $help['flags'] .= self::wrap($msg->numParams(count($flags)), 'apihelp-block-head', 'div'); } $help['flags'] .= Html::openElement('ul'); foreach ($flags as $flag) { $help['flags'] .= Html::rawElement('li', null, self::wrap($context->msg("api-help-flag-{$flag}"), "apihelp-flag-{$flag}")); } $sourceInfo = $module->getModuleSourceInfo(); if ($sourceInfo) { if (isset($sourceInfo['namemsg'])) { $extname = $context->msg($sourceInfo['namemsg'])->text(); } else { $extname = $sourceInfo['name']; } $help['flags'] .= Html::rawElement('li', null, self::wrap($context->msg('api-help-source', $extname, $sourceInfo['name']), 'apihelp-source')); $link = SpecialPage::getTitleFor('Version', 'License/' . $sourceInfo['name']); if (isset($sourceInfo['license-name'])) { $msg = $context->msg('api-help-license', $link, $sourceInfo['license-name']); } elseif (SpecialVersion::getExtLicenseFileName(dirname($sourceInfo['path']))) { $msg = $context->msg('api-help-license-noname', $link); } else { $msg = $context->msg('api-help-license-unknown'); } $help['flags'] .= Html::rawElement('li', null, self::wrap($msg, 'apihelp-license')); } else { $help['flags'] .= Html::rawElement('li', null, self::wrap($context->msg('api-help-source-unknown'), 'apihelp-source')); $help['flags'] .= Html::rawElement('li', null, self::wrap($context->msg('api-help-license-unknown'), 'apihelp-license')); } $help['flags'] .= Html::closeElement('ul'); $help['flags'] .= Html::closeElement('div'); foreach ($module->getFinalDescription() as $msg) { $msg->setContext($context); $help['description'] .= $msg->parseAsBlock(); } $urls = $module->getHelpUrls(); if ($urls) { $help['help-urls'] .= Html::openElement('div', array('class' => 'apihelp-block apihelp-help-urls')); $msg = $context->msg('api-help-help-urls'); if (!$msg->isDisabled()) { $help['help-urls'] .= self::wrap($msg->numParams(count($urls)), 'apihelp-block-head', 'div'); } if (!is_array($urls)) { $urls = array($urls); } $help['help-urls'] .= Html::openElement('ul'); foreach ($urls as $url) { $help['help-urls'] .= Html::rawElement('li', null, Html::element('a', array('href' => $url), $url)); } $help['help-urls'] .= Html::closeElement('ul'); $help['help-urls'] .= Html::closeElement('div'); } $params = $module->getFinalParams(ApiBase::GET_VALUES_FOR_HELP); $dynamicParams = $module->dynamicParameterDocumentation(); $groups = array(); if ($params || $dynamicParams !== null) { $help['parameters'] .= Html::openElement('div', array('class' => 'apihelp-block apihelp-parameters')); $msg = $context->msg('api-help-parameters'); if (!$msg->isDisabled()) { $help['parameters'] .= self::wrap($msg->numParams(count($params)), 'apihelp-block-head', 'div'); } $help['parameters'] .= Html::openElement('dl'); $descriptions = $module->getFinalParamDescription(); foreach ($params as $name => $settings) { if (!is_array($settings)) { $settings = array(ApiBase::PARAM_DFLT => $settings); } $help['parameters'] .= Html::element('dt', null, $module->encodeParamName($name)); // Add description $description = array(); if (isset($descriptions[$name])) { foreach ($descriptions[$name] as $msg) { $msg->setContext($context); $description[] = $msg->parseAsBlock(); } } // Add usage info $info = array(); // Required? if (!empty($settings[ApiBase::PARAM_REQUIRED])) { $info[] = $context->msg('api-help-param-required')->parse(); } // Custom info? if (!empty($settings[ApiBase::PARAM_HELP_MSG_INFO])) { foreach ($settings[ApiBase::PARAM_HELP_MSG_INFO] as $i) { $tag = array_shift($i); $info[] = $context->msg("apihelp-{$path}-paraminfo-{$tag}")->numParams(count($i))->params($context->getLanguage()->commaList($i))->params($module->getModulePrefix())->parse(); } } // Type documentation if (!isset($settings[ApiBase::PARAM_TYPE])) { $dflt = isset($settings[ApiBase::PARAM_DFLT]) ? $settings[ApiBase::PARAM_DFLT] : null; if (is_bool($dflt)) { $settings[ApiBase::PARAM_TYPE] = 'boolean'; } elseif (is_string($dflt) || is_null($dflt)) { $settings[ApiBase::PARAM_TYPE] = 'string'; } elseif (is_int($dflt)) { $settings[ApiBase::PARAM_TYPE] = 'integer'; } } if (isset($settings[ApiBase::PARAM_TYPE])) { $type = $settings[ApiBase::PARAM_TYPE]; $multi = !empty($settings[ApiBase::PARAM_ISMULTI]); $hintPipeSeparated = true; $count = ApiBase::LIMIT_SML2 + 1; if (is_array($type)) { $count = count($type); $links = isset($settings[ApiBase::PARAM_VALUE_LINKS]) ? $settings[ApiBase::PARAM_VALUE_LINKS] : array(); $type = array_map(function ($v) use($links) { $ret = wfEscapeWikiText($v); if (isset($links[$v])) { $ret = "[[{$links[$v]}|{$ret}]]"; } return $ret; }, $type); $i = array_search('', $type, true); if ($i === false) { $type = $context->getLanguage()->commaList($type); } else { unset($type[$i]); $type = $context->msg('api-help-param-list-can-be-empty')->numParams(count($type))->params($context->getLanguage()->commaList($type))->parse(); } $info[] = $context->msg('api-help-param-list')->params($multi ? 2 : 1)->params($type)->parse(); $hintPipeSeparated = false; } else { switch ($type) { case 'submodule': $groups[] = $name; if (isset($settings[ApiBase::PARAM_SUBMODULE_MAP])) { $map = $settings[ApiBase::PARAM_SUBMODULE_MAP]; ksort($map); $submodules = array(); foreach ($map as $v => $m) { $submodules[] = "[[Special:ApiHelp/{$m}|{$v}]]"; } } else { $submodules = $module->getModuleManager()->getNames($name); sort($submodules); $prefix = $module->isMain() ? '' : $module->getModulePath() . '+'; $submodules = array_map(function ($name) use($prefix) { return "[[Special:ApiHelp/{$prefix}{$name}|{$name}]]"; }, $submodules); } $count = count($submodules); $info[] = $context->msg('api-help-param-list')->params($multi ? 2 : 1)->params($context->getLanguage()->commaList($submodules))->parse(); $hintPipeSeparated = false; // No type message necessary, we have a list of values. $type = null; break; case 'namespace': $namespaces = MWNamespace::getValidNamespaces(); $count = count($namespaces); $info[] = $context->msg('api-help-param-list')->params($multi ? 2 : 1)->params($context->getLanguage()->commaList($namespaces))->parse(); $hintPipeSeparated = false; // No type message necessary, we have a list of values. $type = null; break; case 'limit': if (isset($settings[ApiBase::PARAM_MAX2])) { $info[] = $context->msg('api-help-param-limit2')->numParams($settings[ApiBase::PARAM_MAX])->numParams($settings[ApiBase::PARAM_MAX2])->parse(); } else { $info[] = $context->msg('api-help-param-limit')->numParams($settings[ApiBase::PARAM_MAX])->parse(); } break; case 'integer': // Possible messages: // api-help-param-integer-min, // api-help-param-integer-max, // api-help-param-integer-minmax $suffix = ''; $min = $max = 0; if (isset($settings[ApiBase::PARAM_MIN])) { $suffix .= 'min'; $min = $settings[ApiBase::PARAM_MIN]; } if (isset($settings[ApiBase::PARAM_MAX])) { $suffix .= 'max'; $max = $settings[ApiBase::PARAM_MAX]; } if ($suffix !== '') { $info[] = $context->msg("api-help-param-integer-{$suffix}")->params($multi ? 2 : 1)->numParams($min, $max)->parse(); } break; case 'upload': $info[] = $context->msg('api-help-param-upload')->parse(); // No type message necessary, api-help-param-upload should handle it. $type = null; break; case 'string': case 'text': // Displaying a type message here would be useless. $type = null; break; } } // Add type. Messages for grep: api-help-param-type-limit // api-help-param-type-integer api-help-param-type-boolean // api-help-param-type-timestamp api-help-param-type-user // api-help-param-type-password if (is_string($type)) { $msg = $context->msg("api-help-param-type-{$type}"); if (!$msg->isDisabled()) { $info[] = $msg->params($multi ? 2 : 1)->parse(); } } if ($multi) { $extra = array(); if ($hintPipeSeparated) { $extra[] = $context->msg('api-help-param-multi-separate')->parse(); } if ($count > ApiBase::LIMIT_SML1) { $extra[] = $context->msg('api-help-param-multi-max')->numParams(ApiBase::LIMIT_SML1, ApiBase::LIMIT_SML2)->parse(); } if ($extra) { $info[] = join(' ', $extra); } } } // Add default $default = isset($settings[ApiBase::PARAM_DFLT]) ? $settings[ApiBase::PARAM_DFLT] : null; if ($default === '') { $info[] = $context->msg('api-help-param-default-empty')->parse(); } elseif ($default !== null && $default !== false) { $info[] = $context->msg('api-help-param-default')->params(wfEscapeWikiText($default))->parse(); } if (!array_filter($description)) { $description = array(self::wrap($context->msg('api-help-param-no-description'), 'apihelp-empty')); } // Add "deprecated" flag if (!empty($settings[ApiBase::PARAM_DEPRECATED])) { $help['parameters'] .= Html::openElement('dd', array('class' => 'info')); $help['parameters'] .= self::wrap($context->msg('api-help-param-deprecated'), 'apihelp-deprecated', 'strong'); $help['parameters'] .= Html::closeElement('dd'); } if ($description) { $description = join('', $description); $description = preg_replace('!\\s*</([oud]l)>\\s*<\\1>\\s*!', "\n", $description); $help['parameters'] .= Html::rawElement('dd', array('class' => 'description'), $description); } foreach ($info as $i) { $help['parameters'] .= Html::rawElement('dd', array('class' => 'info'), $i); } } if ($dynamicParams !== null) { $dynamicParams = ApiBase::makeMessage($dynamicParams, $context, array($module->getModulePrefix(), $module->getModuleName(), $module->getModulePath())); $help['parameters'] .= Html::element('dt', null, '*'); $help['parameters'] .= Html::rawElement('dd', array('class' => 'description'), $dynamicParams->parse()); } $help['parameters'] .= Html::closeElement('dl'); $help['parameters'] .= Html::closeElement('div'); } $examples = $module->getExamplesMessages(); if ($examples) { $help['examples'] .= Html::openElement('div', array('class' => 'apihelp-block apihelp-examples')); $msg = $context->msg('api-help-examples'); if (!$msg->isDisabled()) { $help['examples'] .= self::wrap($msg->numParams(count($examples)), 'apihelp-block-head', 'div'); } $help['examples'] .= Html::openElement('dl'); foreach ($examples as $qs => $msg) { $msg = ApiBase::makeMessage($msg, $context, array($module->getModulePrefix(), $module->getModuleName(), $module->getModulePath())); $link = wfAppendQuery(wfScript('api'), $qs); $help['examples'] .= Html::rawElement('dt', null, $msg->parse()); $help['examples'] .= Html::rawElement('dd', null, Html::element('a', array('href' => $link), "api.php?{$qs}")); } $help['examples'] .= Html::closeElement('dl'); $help['examples'] .= Html::closeElement('div'); } $subtocnumber = $tocnumber; $subtocnumber[$level + 1] = 0; $suboptions = array('submodules' => $options['recursivesubmodules'], 'headerlevel' => $level + 1, 'tocnumber' => &$subtocnumber, 'noheader' => false) + $options; if ($options['submodules'] && $module->getModuleManager()) { $manager = $module->getModuleManager(); $submodules = array(); foreach ($groups as $group) { $names = $manager->getNames($group); sort($names); foreach ($names as $name) { $submodules[] = $manager->getModule($name); } } $help['submodules'] .= self::getHelpInternal($context, $submodules, $suboptions, $haveModules); } $module->modifyHelp($help, $suboptions, $haveModules); Hooks::run('APIHelpModifyOutput', array($module, &$help, $suboptions, &$haveModules)); $out .= join("\n", $help); } return $out; }
function fetchImageQuery($query) { global $wgMemc; $query = array_merge($query, array('format' => 'json', 'action' => 'query', 'redirects' => 'true')); if ($this->mApiBase) { $url = wfAppendQuery($this->mApiBase, $query); } else { $url = $this->makeUrl($query, 'api'); } if (!isset($this->mQueryCache[$url])) { $key = $this->getLocalCacheKey('ForeignAPIRepo', 'Metadata', md5($url)); $data = $wgMemc->get($key); if (!$data) { $data = self::httpGet($url); if (!$data) { return null; } $wgMemc->set($key, $data, 3600); } if (count($this->mQueryCache) > 100) { // Keep the cache from growing infinitely $this->mQueryCache = array(); } $this->mQueryCache[$url] = $data; } return FormatJson::decode($this->mQueryCache[$url], true); }
/** * Get a URL with no fragment or server name (relative URL) from a Title object. * If this page is generated with action=render, however, * $wgServer is prepended to make an absolute URL. * * @see self::getFullURL to always get an absolute URL. * @see self::getLinkURL to always get a URL that's the simplest URL that will be * valid to link, locally, to the current Title. * @see self::newFromText to produce a Title object. * * @param string|array $query An optional query string, * not used for interwiki links. Can be specified as an associative array as well, * e.g., array( 'action' => 'edit' ) (keys and values will be URL-escaped). * Some query patterns will trigger various shorturl path replacements. * @param array $query2 An optional secondary query array. This one MUST * be an array. If a string is passed it will be interpreted as a deprecated * variant argument and urlencoded into a variant= argument. * This second query argument will be added to the $query * The second parameter is deprecated since 1.19. Pass it as a key,value * pair in the first parameter array instead. * * @return string String of the URL. */ public function getLocalURL($query = '', $query2 = false) { global $wgArticlePath, $wgScript, $wgServer, $wgRequest; $query = self::fixUrlQueryArgs($query, $query2); $interwiki = Interwiki::fetch($this->mInterwiki); if ($interwiki) { $namespace = $this->getNsText(); if ($namespace != '') { # Can this actually happen? Interwikis shouldn't be parsed. # Yes! It can in interwiki transclusion. But... it probably shouldn't. $namespace .= ':'; } $url = $interwiki->getURL($namespace . $this->getDBkey()); $url = wfAppendQuery($url, $query); } else { $dbkey = wfUrlencode($this->getPrefixedDBkey()); if ($query == '') { $url = str_replace('$1', $dbkey, $wgArticlePath); Hooks::run('GetLocalURL::Article', array(&$this, &$url)); } else { global $wgVariantArticlePath, $wgActionPaths, $wgContLang; $url = false; $matches = array(); if (!empty($wgActionPaths) && preg_match('/^(.*&|)action=([^&]*)(&(.*)|)$/', $query, $matches)) { $action = urldecode($matches[2]); if (isset($wgActionPaths[$action])) { $query = $matches[1]; if (isset($matches[4])) { $query .= $matches[4]; } $url = str_replace('$1', $dbkey, $wgActionPaths[$action]); if ($query != '') { $url = wfAppendQuery($url, $query); } } } if ($url === false && $wgVariantArticlePath && $wgContLang->getCode() === $this->getPageLanguage()->getCode() && $this->getPageLanguage()->hasVariants() && preg_match('/^variant=([^&]*)$/', $query, $matches)) { $variant = urldecode($matches[1]); if ($this->getPageLanguage()->hasVariant($variant)) { // Only do the variant replacement if the given variant is a valid // variant for the page's language. $url = str_replace('$2', urlencode($variant), $wgVariantArticlePath); $url = str_replace('$1', $dbkey, $url); } } if ($url === false) { if ($query == '-') { $query = ''; } $url = "{$wgScript}?title={$dbkey}&{$query}"; } } Hooks::run('GetLocalURL::Internal', array(&$this, &$url, $query)); // @todo FIXME: This causes breakage in various places when we // actually expected a local URL and end up with dupe prefixes. if ($wgRequest->getVal('action') == 'render') { $url = $wgServer . $url; } } Hooks::run('GetLocalURL', array(&$this, &$url, $query)); return $url; }