/** * Check if the given local page title is a spam regex source. * @param Title $title * @return bool */ function isLocalSource($title) { global $wgDBname; if ($title->getNamespace() == NS_MEDIAWIKI) { $sources = array("Spam-blacklist", "Spam-whitelist"); if (in_array($title->getDBkey(), $sources)) { return true; } } $thisHttp = wfExpandUrl($title->getFullUrl('action=raw'), PROTO_HTTP); $thisHttpRegex = '/^' . preg_quote($thisHttp, '/') . '(?:&.*)?$/'; foreach ($this->files as $fileName) { $matches = array(); if (preg_match('/^DB: (\\w*) (.*)$/', $fileName, $matches)) { if ($wgDBname == $matches[1]) { if ($matches[2] == $title->getPrefixedDbKey()) { // Local DB fetch of this page... return true; } } } elseif (preg_match($thisHttpRegex, $fileName)) { // Raw view of this page return true; } } return false; }
/** * Forks processes to scan the originating IP for an open proxy server * MemCached can be used to skip IPs that have already been scanned */ function wfProxyCheck() { global $wgBlockOpenProxies, $wgProxyPorts, $wgProxyScriptPath; global $wgMemc, $wgProxyMemcExpiry, $wgRequest; global $wgProxyKey; if (!$wgBlockOpenProxies) { return; } $ip = $wgRequest->getIP(); # Get MemCached key $mcKey = wfMemcKey('proxy', 'ip', $ip); $mcValue = $wgMemc->get($mcKey); $skip = (bool) $mcValue; # Fork the processes if (!$skip) { $title = SpecialPage::getTitleFor('Blockme'); $iphash = md5($ip . $wgProxyKey); $url = wfExpandUrl($title->getFullURL('ip=' . $iphash), PROTO_HTTP); foreach ($wgProxyPorts as $port) { $params = implode(' ', array(escapeshellarg($wgProxyScriptPath), escapeshellarg($ip), escapeshellarg($port), escapeshellarg($url))); exec("php {$params} >" . wfGetNull() . " 2>&1 &"); } # Set MemCached key $wgMemc->set($mcKey, 1, $wgProxyMemcExpiry); } }
function streamAppleTouch() { global $wgAppleTouchIcon; wfResetOutputBuffers(); if ($wgAppleTouchIcon === false) { # That's not very helpful, that's where we are already header('HTTP/1.1 404 Not Found'); faviconShowError('$wgAppleTouchIcon is configured incorrectly, ' . 'it must be set to something other than false \\n'); return; } $req = RequestContext::getMain()->getRequest(); if ($req->getHeader('X-Favicon-Loop') !== false) { header('HTTP/1.1 500 Internal Server Error'); faviconShowError('Proxy forwarding loop detected'); return; } $url = wfExpandUrl($wgAppleTouchIcon, PROTO_CANONICAL); $client = MWHttpRequest::factory($url); $client->setHeader('X-Favicon-Loop', '1'); $status = $client->execute(); if (!$status->isOK()) { header('HTTP/1.1 500 Internal Server Error'); faviconShowError("Failed to fetch URL \"{$url}\""); return; } $content = $client->getContent(); header('Content-Length: ' . strlen($content)); header('Content-Type: ' . $client->getResponseHeader('Content-Type')); header('Cache-Control: public'); header('Expires: ' . gmdate('r', time() + 86400)); echo $content; }
function efOpenGraphMetaPageHook(OutputPage &$out, &$sk) { global $wgLogo, $wgSitename, $wgXhtmlNamespaces, $egFacebookAppId, $egFacebookAdmins; $wgXhtmlNamespaces["og"] = "http://opengraphprotocol.org/schema/"; $title = $out->getTitle(); $isMainpage = $title->isMainPage(); $meta = array(); if ($isMainpage) { $meta["og:type"] = "website"; $meta["og:title"] = $wgSitename; } else { $meta["og:type"] = "article"; $meta["og:site_name"] = $wgSitename; // Try to chose the most appropriate title for showing in news feeds. if (defined('NS_BLOG_ARTICLE') && $title->getNamespace() == NS_BLOG_ARTICLE || defined('NS_BLOG_ARTICLE_TALK') && $title->getNamespace() == NS_BLOG_ARTICLE_TALK) { $meta["og:title"] = $title->getSubpageText(); } else { $meta["og:title"] = $title->getText(); } } if (isset($out->mMainImage) && $out->mMainImage !== false) { if (is_object($out->mMainImage)) { $meta["og:image"] = wfExpandUrl($out->mMainImage->createThumb(100 * 3, 100)); } else { // In some edge-cases we won't have defined an object but rather a full URL. $meta["og:image"] = $out->mMainImage; } } elseif ($isMainpage) { $meta["og:image"] = wfExpandUrl($wgLogo); } if (isset($out->mDescription)) { // set by Description2 extension, install it if you want proper og:description support $meta["og:description"] = $out->mDescription; } $meta["og:url"] = $title->getFullURL(); if ($egFacebookAppId) { /* begin wikia change */ // $meta["fb:app_id"] = $egFacebookAppId; // fb:app_id needs a prefix property declaring the namespace, so just add it directly $out->addHeadItem("meta:property:fb:app_id", "\t" . Html::element('meta', array('property' => 'fb:app_id', 'content' => $egFacebookAppId, 'prefix' => "fb: http://www.facebook.com/2008/fbml")) . "\n"); /* end wikia change */ } if ($egFacebookAdmins) { $meta["fb:admins"] = $egFacebookAdmins; } /* begin wikia change */ wfRunHooks('OpenGraphMetaHeaders', array("meta" => &$meta, "title" => $title)); /* end wikia change */ foreach ($meta as $property => $value) { if ($value) { if (isset(OutputPage::$metaAttrPrefixes) && isset(OutputPage::$metaAttrPrefixes['property'])) { $out->addMeta("property:{$property}", $value); } else { $out->addHeadItem("meta:property:{$property}", "\t" . Html::element('meta', array('property' => $property, 'content' => $value)) . "\n"); } } } return true; }
/** * Main Constructer * * @access public * @return void */ public function __construct() { global $wgServer, $wgScriptPath, $wgUser; $achievementsPage = Title::newFromText('Special:Achievements'); $this->achievementsURL = $achievementsPage->getFullURL(); $this->urlPrefix = wfExpandUrl($wgServer . $wgScriptPath); $this->wgUser = $wgUser; }
/** * If WikiFactory wgEnableNewAuth variable is set to true, then this method sets login url for the New Auth Flow login page. * Also new class is set for the login button. * Otherwise it sets url to the old Special:Login page. */ private function setupLoginLink() { if ($this->app->wg->EnableNewAuth) { $this->loginUrl = '/join?redirect=' . urlencode(wfExpandUrl($this->app->wg->request->getRequestURL())) . $this->getUselangParam(); $this->loginButtonClass = 'new-login'; } else { $this->loginUrl = SpecialPage::getTitleFor('UserLogin')->getLocalURL(); $this->loginButtonClass = ''; } }
public function performUploadDone($user) { $this->mUpload->finalizeFile(); $status = parent::performUpload($this->comment, $this->pageText, $this->watch, $user); if ($status['result'] !== 'Success') { return $status; } $file = $this->mUpload->getLocalFile(); return array('result' => 1, 'done' => 1, 'resultUrl' => wfExpandUrl($file->getDescriptionUrl())); }
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 ''; }
/** * @param integer $size the width of the thumbnail * @return string */ private function getPageImageHtml($size = 750) { if ($this->item->hasImage()) { $thumb = models\Image::getThumbnail($this->item->getFile(), $size); if ($thumb && $thumb->getUrl()) { $data = array('url' => wfExpandUrl($thumb->getUrl(), PROTO_CURRENT), 'wide' => $thumb->getWidth() > $thumb->getHeight()); return Template::render('CardImage', $data); } } return ''; }
/** @dataProvider provideExpandableUrls */ public function testWfExpandUrl($fullUrl, $shortUrl, $defaultProto, $server, $canServer, $httpsMode, $message) { // Fake $wgServer and $wgCanonicalServer $this->setMwGlobals(array('wgServer' => $server, 'wgCanonicalServer' => $canServer)); // Fake $_SERVER['HTTPS'] if needed if ($httpsMode) { $_SERVER['HTTPS'] = 'on'; } else { unset($_SERVER['HTTPS']); } $this->assertEquals($fullUrl, wfExpandUrl($shortUrl, $defaultProto), $message); }
public function execute() { if ($this->getPageSet()->getGoodTitleCount() == 0) { return; } $params = $this->extractRequestParams(); $query = $params['query']; $protocol = ApiQueryExtLinksUsage::getProtocolPrefix($params['protocol']); $this->addFields(array('el_from', 'el_to')); $this->addTables('externallinks'); $this->addWhereFld('el_from', array_keys($this->getPageSet()->getGoodTitles())); $whereQuery = $this->prepareUrlQuerySearchString($query, $protocol); if ($whereQuery !== null) { $this->addWhere($whereQuery); } // Don't order by el_from if it's constant in the WHERE clause if (count($this->getPageSet()->getGoodTitles()) != 1) { $this->addOption('ORDER BY', 'el_from'); } // If we're querying all protocols, use DISTINCT to avoid repeating protocol-relative links twice if ($protocol === null) { $this->addOption('DISTINCT'); } $this->addOption('LIMIT', $params['limit'] + 1); $offset = isset($params['offset']) ? $params['offset'] : 0; if ($offset) { $this->addOption('OFFSET', $params['offset']); } $res = $this->select(__METHOD__); $count = 0; foreach ($res as $row) { if (++$count > $params['limit']) { // We've reached the one extra which shows that // there are additional pages to be had. Stop here... $this->setContinueEnumParameter('offset', $offset + $params['limit']); break; } $entry = array(); $to = $row->el_to; // expand protocol-relative urls if ($params['expandurl']) { $to = wfExpandUrl($to, PROTO_CANONICAL); } ApiResult::setContent($entry, $to); $fit = $this->addPageSubItem($row->el_from, $entry); if (!$fit) { $this->setContinueEnumParameter('offset', $offset + $count - 1); break; } } }
public function testSubPageRedirect() { $ctx = new RequestContext(); SpecialPageFactory::executePath(Title::newFromText('Special:Search/foo_bar'), $ctx); $url = $ctx->getOutput()->getRedirect(); // some older versions of hhvm have a bug that doesn't parse relative // urls with a port, so help it out a little bit. // https://github.com/facebook/hhvm/issues/7136 $url = wfExpandUrl($url, PROTO_CURRENT); $parts = parse_url($url); $this->assertEquals('/w/index.php', $parts['path']); parse_str($parts['query'], $query); $this->assertEquals('Special:Search', $query['title']); $this->assertEquals('foo bar', $query['search']); }
/** * @param string $url Url to use. If protocol-relative, will be expanded to an http:// URL * @param array $options (optional) extra params to pass (see Http::request()) * @param string $caller The method making this request, for profiling * @param Profiler $profiler An instance of the profiler for profiling, or null */ protected function __construct($url, $options = [], $caller = __METHOD__, $profiler = null) { global $wgHTTPTimeout, $wgHTTPConnectTimeout; $this->url = wfExpandUrl($url, PROTO_HTTP); $this->parsedUrl = wfParseUrl($this->url); if (isset($options['logger'])) { $this->logger = $options['logger']; } else { $this->logger = new NullLogger(); } if (!$this->parsedUrl || !Http::isValidURI($this->url)) { $this->status = Status::newFatal('http-invalid-url', $url); } else { $this->status = Status::newGood(100); // continue } if (isset($options['timeout']) && $options['timeout'] != 'default') { $this->timeout = $options['timeout']; } else { $this->timeout = $wgHTTPTimeout; } if (isset($options['connectTimeout']) && $options['connectTimeout'] != 'default') { $this->connectTimeout = $options['connectTimeout']; } else { $this->connectTimeout = $wgHTTPConnectTimeout; } if (isset($options['userAgent'])) { $this->setUserAgent($options['userAgent']); } $members = ["postData", "proxy", "noProxy", "sslVerifyHost", "caInfo", "method", "followRedirects", "maxRedirects", "sslVerifyCert", "callback"]; foreach ($members as $o) { if (isset($options[$o])) { // ensure that MWHttpRequest::method is always // uppercased. Bug 36137 if ($o == 'method') { $options[$o] = strtoupper($options[$o]); } $this->{$o} = $options[$o]; } } if ($this->noProxy) { $this->proxy = ''; // noProxy takes precedence } // Profile based on what's calling us $this->profiler = $profiler; $this->profileName = $caller; }
/** * Perform an HTTP request * * @param $method String: HTTP method. Usually GET/POST * @param $url String: full URL to act on * @param $options Array: options to pass to MWHttpRequest object. * Possible keys for the array: * - timeout Timeout length in seconds * - postData An array of key-value pairs or a url-encoded form data * - proxy The proxy to use. * Will use $wgHTTPProxy (if set) otherwise. * - noProxy Override $wgHTTPProxy (if set) and don't use any proxy at all. * - sslVerifyHost (curl only) Verify hostname against certificate * - sslVerifyCert (curl only) Verify SSL certificate * - caInfo (curl only) Provide CA information * - maxRedirects Maximum number of redirects to follow (defaults to 5) * - followRedirects Whether to follow redirects (defaults to false). * Note: this should only be used when the target URL is trusted, * to avoid attacks on intranet services accessible by HTTP. * @return Mixed: (bool)false on failure or a string on success */ public static function request($method, $url, $options = array()) { $url = wfExpandUrl($url); wfDebug("HTTP: {$method}: {$url}\n"); $options['method'] = strtoupper($method); if (!isset($options['timeout'])) { $options['timeout'] = 'default'; } $req = MWHttpRequest::factory($url, $options); $status = $req->execute(); if ($status->isOK()) { return $req->getContent(); } else { return false; } }
public function load($parser) { if ($this->loaded) { return; } if (!$parser->getTitle()->mUrlform) { return; } $file = $parser->getTitle()->mUrlform; $path = __DIR__ . '/css/' . $file . '.css'; if (!file_exists($path)) { return; } global $wgScriptPath; $url = wfExpandUrl("{$wgScriptPath}/extensions/CSSLoader/css/{$file}.css"); $this->url = $url; $this->loaded = true; }
/** @dataProvider provideExpandableUrls */ public function testWfExpandUrl($fullUrl, $shortUrl, $defaultProto, $server, $canServer, $httpsMode, $message) { // Fake $wgServer and $wgCanonicalServer global $wgServer, $wgCanonicalServer; $oldServer = $wgServer; $oldCanServer = $wgCanonicalServer; $wgServer = $server; $wgCanonicalServer = $canServer; // Fake $_SERVER['HTTPS'] if needed if ($httpsMode) { $_SERVER['HTTPS'] = 'on'; } else { unset($_SERVER['HTTPS']); } $this->assertEquals($fullUrl, wfExpandUrl($shortUrl, $defaultProto), $message); // Restore $wgServer and $wgCanonicalServer $wgServer = $oldServer; $wgCanonicalServer = $oldCanServer; }
/** * @param string $url * @param array $cookies * @return MobileContext */ private function makeContext($url = '/', $cookies = array()) { $query = array(); if ($url) { $params = wfParseUrl(wfExpandUrl($url)); if (isset($params['query'])) { $query = wfCgiToArray($params['query']); } } $request = new FauxRequest($query); $request->setRequestURL($url); $request->setCookies($cookies, ''); $context = new DerivativeContext(RequestContext::getMain()); $context->setRequest($request); $context->setOutput(new OutputPage($context)); $instance = unserialize('O:13:"MobileContext":0:{}'); $instance->setContext($context); return $instance; }
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); }
public function execute() { wfProfileIn(__METHOD__); $params = $this->extractRequestParams(); global $wgFeedClasses; if (!isset($wgFeedClasses[$params['feedformat']])) { wfProfileOut(__METHOD__); $this->dieUsage('Invalid subscription feed type', 'feed-invalid'); } $language = isset($params['language']) ? $params['language'] : false; if ($language !== false && !Language::isValidCode($language)) { $language = false; } $feeds = FeaturedFeeds::getFeeds($language); $ourFeed = $feeds[$params['feed']]; $feedClass = new $wgFeedClasses[$params['feedformat']]($ourFeed->title, $ourFeed->description, wfExpandUrl(Title::newMainPage()->getFullURL())); ApiFormatFeedWrapper::setResult($this->getResult(), $feedClass, $ourFeed->getFeedItems()); // Cache stuff in squids $this->getMain()->setCacheMode('public'); $this->getMain()->setCacheMaxAge(FeaturedFeeds::getMaxAge()); wfProfileOut(__METHOD__); }
/** * Transform a media file * * @param array $params an associative array of handler-specific parameters. * Typical keys are width, height and page. * @param $flags Integer: a bitfield, may contain self::RENDER_NOW to force rendering * @return MediaTransformOutput|bool False on failure */ function transform($params, $flags = 0) { global $wgUseSquid, $wgIgnoreImageErrors, $wgThumbnailEpoch; wfProfileIn(__METHOD__); do { if (!$this->canRender()) { $thumb = $this->iconThumb(); break; // not a bitmap or renderable image, don't try } // Get the descriptionUrl to embed it as comment into the thumbnail. Bug 19791. $descriptionUrl = $this->getDescriptionUrl(); if ($descriptionUrl) { $params['descriptionUrl'] = wfExpandUrl($descriptionUrl, PROTO_CANONICAL); } $handler = $this->getHandler(); $script = $this->getTransformScript(); if ($script && !($flags & self::RENDER_NOW)) { // Use a script to transform on client request, if possible $thumb = $handler->getScriptedTransform($this, $script, $params); if ($thumb) { break; } } $normalisedParams = $params; $handler->normaliseParams($this, $normalisedParams); $thumbName = $this->thumbName($normalisedParams); $thumbUrl = $this->getThumbUrl($thumbName); $thumbPath = $this->getThumbPath($thumbName); // final thumb path if ($this->repo) { // Defer rendering if a 404 handler is set up... if ($this->repo->canTransformVia404() && !($flags & self::RENDER_NOW)) { wfDebug(__METHOD__ . " transformation deferred."); // XXX: Pass in the storage path even though we are not rendering anything // and the path is supposed to be an FS path. This is due to getScalerType() // getting called on the path and clobbering $thumb->getUrl() if it's false. $thumb = $handler->getTransform($this, $thumbPath, $thumbUrl, $params); break; } // Clean up broken thumbnails as needed $this->migrateThumbFile($thumbName); // Check if an up-to-date thumbnail already exists... wfDebug(__METHOD__ . ": Doing stat for {$thumbPath}\n"); if (!($flags & self::RENDER_FORCE) && $this->repo->fileExists($thumbPath)) { $timestamp = $this->repo->getFileTimestamp($thumbPath); if ($timestamp !== false && $timestamp >= $wgThumbnailEpoch) { // XXX: Pass in the storage path even though we are not rendering anything // and the path is supposed to be an FS path. This is due to getScalerType() // getting called on the path and clobbering $thumb->getUrl() if it's false. $thumb = $handler->getTransform($this, $thumbPath, $thumbUrl, $params); $thumb->setStoragePath($thumbPath); break; } } elseif ($flags & self::RENDER_FORCE) { wfDebug(__METHOD__ . " forcing rendering per flag File::RENDER_FORCE\n"); } } // If the backend is ready-only, don't keep generating thumbnails // only to return transformation errors, just return the error now. if ($this->repo->getReadOnlyReason() !== false) { $thumb = $this->transformErrorOutput($thumbPath, $thumbUrl, $params, $flags); break; } // Create a temp FS file with the same extension and the thumbnail $thumbExt = FileBackend::extensionFromPath($thumbPath); $tmpFile = TempFSFile::factory('transform_', $thumbExt); if (!$tmpFile) { $thumb = $this->transformErrorOutput($thumbPath, $thumbUrl, $params, $flags); break; } $tmpThumbPath = $tmpFile->getPath(); // path of 0-byte temp file // Actually render the thumbnail... wfProfileIn(__METHOD__ . '-doTransform'); $thumb = $handler->doTransform($this, $tmpThumbPath, $thumbUrl, $params); wfProfileOut(__METHOD__ . '-doTransform'); $tmpFile->bind($thumb); // keep alive with $thumb if (!$thumb) { // bad params? $thumb = null; } elseif ($thumb->isError()) { // transform error $this->lastError = $thumb->toText(); // Ignore errors if requested if ($wgIgnoreImageErrors && !($flags & self::RENDER_NOW)) { $thumb = $handler->getTransform($this, $tmpThumbPath, $thumbUrl, $params); } } elseif ($this->repo && $thumb->hasFile() && !$thumb->fileIsSource()) { // Copy the thumbnail from the file system into storage... $disposition = $this->getThumbDisposition($thumbName); $status = $this->repo->quickImport($tmpThumbPath, $thumbPath, $disposition); if ($status->isOK()) { $thumb->setStoragePath($thumbPath); } else { $thumb = $this->transformErrorOutput($thumbPath, $thumbUrl, $params, $flags); } // Give extensions a chance to do something with this thumbnail... wfRunHooks('FileTransformed', array($this, $thumb, $tmpThumbPath, $thumbPath)); } // Purge. Useful in the event of Core -> Squid connection failure or squid // purge collisions from elsewhere during failure. Don't keep triggering for // "thumbs" which have the main image URL though (bug 13776) if ($wgUseSquid) { if (!$thumb || $thumb->isError() || $thumb->getUrl() != $this->getURL()) { SquidUpdate::purge(array($thumbUrl)); } } } while (false); wfProfileOut(__METHOD__); return is_object($thumb) ? $thumb : false; }
private function formatIWLinks($iw) { $result = array(); foreach ($iw as $prefix => $titles) { foreach (array_keys($titles) as $title) { $entry = array(); $entry['prefix'] = $prefix; $title = Title::newFromText("{$prefix}:{$title}"); if ($title) { $entry['url'] = wfExpandUrl($title->getFullURL(), PROTO_CURRENT); } $this->getResult()->setContent($entry, $title->getFullText()); $result[] = $entry; } } return $result; }
/** * 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()); }
/** * @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; }
/** * Like a Http:get request, but with custom User-Agent. * @see Http:get */ public static function httpGet($url, $timeout = 'default', $options = array()) { $options['timeout'] = $timeout; /* Http::get */ $url = wfExpandUrl($url, PROTO_HTTP); wfDebug("ForeignAPIRepo: HTTP GET: {$url}\n"); $options['method'] = "GET"; if (!isset($options['timeout'])) { $options['timeout'] = 'default'; } $req = MWHttpRequest::factory($url, $options); $req->setUserAgent(ForeignAPIRepo::getUserAgent()); $status = $req->execute(); if ($status->isOK()) { return $req->getContent(); } else { return false; } }
/** * Return information about the repository. * * @return array * @since 1.22 */ function getInfo() { global $wgFavicon; return array_merge(parent::getInfo(), array('favicon' => wfExpandUrl($wgFavicon))); }
/** * Get the URL for a canonical link, for use in things like IRC and * e-mail notifications. Uses $wgCanonicalServer and the * GetCanonicalURL hook. * * NOTE: Unlike getInternalURL(), the canonical URL includes the fragment * * @see self::getLocalURL for the arguments. * @return string The URL * @since 1.18 */ public function getCanonicalURL($query = '', $query2 = false) { $query = self::fixUrlQueryArgs($query, $query2); $url = wfExpandUrl($this->getLocalURL($query) . $this->getFragmentForURL(), PROTO_CANONICAL); Hooks::run('GetCanonicalURL', array(&$this, &$url, $query)); return $url; }
static function diffPermalinkURL($thread, $revision) { $query = self::diffQuery($thread, $revision); return wfExpandUrl(self::permalinkUrl($thread, null, null, $query), PROTO_RELATIVE); }
/** * Return the request URI with the canonical service and hostname, path, * and query string. This will be suitable for use as an absolute link * in HTML or other output. * * If $wgServer is protocol-relative, this will return a fully * qualified URL with the protocol that was used for this request. * * @return String */ public function getFullRequestURL() { return wfExpandUrl($this->getRequestURL(), PROTO_CURRENT); }
/** * Replace the result data with the information about an exception. * Returns the error code * @param Exception $e * @return string */ protected function substituteResultWithError($e) { $result = $this->getResult(); $config = $this->getConfig(); if ($e instanceof UsageException) { // User entered incorrect parameters - generate error response $errMessage = $e->getMessageArray(); $link = wfExpandUrl(wfScript('api')); ApiResult::setContentValue($errMessage, 'docref', "See {$link} for API usage"); } else { // Something is seriously wrong if ($e instanceof DBQueryError && !$config->get('ShowSQLErrors')) { $info = 'Database query error'; } else { $info = "Exception Caught: {$e->getMessage()}"; } $errMessage = array('code' => 'internal_api_error_' . get_class($e), 'info' => '[' . MWExceptionHandler::getLogId($e) . '] ' . $info); if ($config->get('ShowExceptionDetails')) { ApiResult::setContentValue($errMessage, 'trace', MWExceptionHandler::getRedactedTraceAsString($e)); } } // Remember all the warnings to re-add them later $warnings = $result->getResultData(array('warnings')); $result->reset(); // Re-add the id $requestid = $this->getParameter('requestid'); if (!is_null($requestid)) { $result->addValue(null, 'requestid', $requestid, ApiResult::NO_SIZE_CHECK); } if ($config->get('ShowHostnames')) { // servedby is especially useful when debugging errors $result->addValue(null, 'servedby', wfHostName(), ApiResult::NO_SIZE_CHECK); } if ($warnings !== null) { $result->addValue(null, 'warnings', $warnings, ApiResult::NO_SIZE_CHECK); } $result->addValue(null, 'error', $errMessage, ApiResult::NO_SIZE_CHECK); return $errMessage['code']; }
/** * Builds an internal list of APIs to expose information about. * Normally this only lists the MediaWiki API, with its base URL, * link to documentation, and a marker as to available authentication * (to aid in OAuth client apps switching to support in the future). * * Extensions can expose other APIs, such as WordPress or Twitter- * compatible APIs, by hooking 'ApiRsdServiceApis' and adding more * elements to the array. * * See http://cyber.law.harvard.edu/blogs/gems/tech/rsd.html for * the base RSD spec, and check WordPress and StatusNet sites for * in-production examples listing several blogging and micrblogging * APIs. * * @return array */ protected function getRsdApiList() { $apis = array('MediaWiki' => array('apiLink' => wfExpandUrl(wfScript('api'), PROTO_CURRENT), 'docs' => 'https://www.mediawiki.org/wiki/API', 'blogID' => '', 'settings' => array('OAuth' => false))); Hooks::run('ApiRsdServiceApis', array(&$apis)); return $apis; }