function getLagTimes($serverIndexes, $wiki) { wfProfileIn(__METHOD__); $expiry = 5; $requestRate = 10; global $wgMemc; if (empty($wgMemc)) { $wgMemc = wfGetMainCache(); } $masterName = $this->parent->getServerName(0); $memcKey = wfMemcKey('lag_times', $masterName); $times = $wgMemc->get($memcKey); if ($times) { # Randomly recache with probability rising over $expiry $elapsed = time() - $times['timestamp']; $chance = max(0, ($expiry - $elapsed) * $requestRate); if (mt_rand(0, $chance) != 0) { unset($times['timestamp']); wfProfileOut(__METHOD__); return $times; } wfIncrStats('lag_cache_miss_expired'); } else { wfIncrStats('lag_cache_miss_absent'); } # Cache key missing or expired $times = array(); foreach ($serverIndexes as $i) { if ($i == 0) { # Master $times[$i] = 0; } elseif (false !== ($conn = $this->parent->getAnyOpenConnection($i))) { $times[$i] = $conn->getLag(); } elseif (false !== ($conn = $this->parent->openConnection($i, $wiki))) { $times[$i] = $conn->getLag(); } } # Add a timestamp key so we know when it was cached $times['timestamp'] = time(); $wgMemc->set($memcKey, $times, $expiry); # But don't give the timestamp to the caller unset($times['timestamp']); $lagTimes = $times; wfProfileOut(__METHOD__); return $lagTimes; }
function get(&$article, &$user) { global $wgCacheEpoch; $fname = 'ParserCache::get'; wfProfileIn($fname); $key = $this->getKey($article, $user); wfDebug("Trying parser cache {$key}\n"); $value = $this->mMemc->get($key); if (is_object($value)) { wfDebug("Found.\n"); # Delete if article has changed since the cache was made $canCache = $article->checkTouched(); $cacheTime = $value->getCacheTime(); $touched = $article->mTouched; if (!$canCache || $value->expired($touched)) { if (!$canCache) { wfIncrStats("pcache_miss_invalid"); wfDebug("Invalid cached redirect, touched {$touched}, epoch {$wgCacheEpoch}, cached {$cacheTime}\n"); } else { wfIncrStats("pcache_miss_expired"); wfDebug("Key expired, touched {$touched}, epoch {$wgCacheEpoch}, cached {$cacheTime}\n"); } $this->mMemc->delete($key); $value = false; } else { if (isset($value->mTimestamp)) { $article->mTimestamp = $value->mTimestamp; } wfIncrStats("pcache_hit"); } } else { wfDebug("Parser cache miss.\n"); wfIncrStats("pcache_miss_absent"); $value = false; } wfProfileOut($fname); return $value; }
/** * Try to load file metadata from memcached. Returns true on success. * @return bool */ function loadFromCache() { $this->dataLoaded = false; $this->extraDataLoaded = false; $key = $this->getCacheKey(); if (!$key) { return false; } $cache = ObjectCache::getMainWANInstance(); $cachedValues = $cache->get($key); // Check if the key existed and belongs to this version of MediaWiki if (is_array($cachedValues) && $cachedValues['version'] == MW_FILE_VERSION) { $this->fileExists = $cachedValues['fileExists']; if ($this->fileExists) { $this->setProps($cachedValues); } $this->dataLoaded = true; $this->extraDataLoaded = true; foreach ($this->getLazyCacheFields('') as $field) { $this->extraDataLoaded = $this->extraDataLoaded && isset($cachedValues[$field]); } } if ($this->dataLoaded) { wfIncrStats('image_cache.hit'); } else { wfIncrStats('image_cache.miss'); } return $this->dataLoaded; }
/** * Remove jobs in the job queue which are duplicates of this job. * This is deadlock-prone and so starts its own transaction. */ function removeDuplicates() { if (!$this->removeDuplicates) { return; } $fields = $this->insertFields(); unset($fields['job_id']); $dbw = wfGetDB(DB_MASTER); $dbw->begin(__METHOD__); $dbw->delete('job', $fields, __METHOD__); $affected = $dbw->affectedRows(); $dbw->commit(__METHOD__); if ($affected) { wfIncrStats('job-dup-delete', $affected); } }
public function addWikiTextTitle($text, &$title, $linestart, $tidy = false) { global $wgParser; wfProfileIn(__METHOD__); wfIncrStats('pcache_not_possible'); $popts = $this->parserOptions(); $oldTidy = $popts->setTidy($tidy); $parserOutput = $wgParser->parse($text, $title, $popts, $linestart, true, $this->mRevisionId); $popts->setTidy($oldTidy); $this->addParserOutput($parserOutput); wfProfileOut(__METHOD__); }
/** * Get a ParserOutput for the given ParserOptions and revision ID. * * The parser cache will be used if possible. Cache misses that result * in parser runs are debounced with PoolCounter. * * @since 1.19 * @param ParserOptions $parserOptions ParserOptions to use for the parse operation * @param null|int $oldid Revision ID to get the text from, passing null or 0 will * get the current revision (default value) * @param bool $forceParse Force reindexing, regardless of cache settings * @return bool|ParserOutput ParserOutput or false if the revision was not found */ public function getParserOutput(ParserOptions $parserOptions, $oldid = null, $forceParse = false) { $useParserCache = !$forceParse && $this->shouldCheckParserCache($parserOptions, $oldid); wfDebug(__METHOD__ . ': using parser cache: ' . ($useParserCache ? 'yes' : 'no') . "\n"); if ($parserOptions->getStubThreshold()) { wfIncrStats('pcache.miss.stub'); } if ($useParserCache) { $parserOutput = ParserCache::singleton()->get($this, $parserOptions); if ($parserOutput !== false) { return $parserOutput; } } if ($oldid === null || $oldid === 0) { $oldid = $this->getLatest(); } $pool = new PoolWorkArticleView($this, $parserOptions, $oldid, $useParserCache); $pool->execute(); return $pool->getParserOutput(); }
function addWikiTextTitle($text, &$title, $linestart) { global $wgParser; $fname = 'OutputPage:addWikiTextTitle'; wfProfileIn($fname); wfIncrStats('pcache_not_possible'); $parserOutput = $wgParser->parse($text, $title, $this->parserOptions(), $linestart, true, $this->mRevisionId); $this->addParserOutput($parserOutput); wfProfileOut($fname); }
/** * Retrieve the ParserOutput from ParserCache. * false if not found or outdated. * * @param WikiPage|Article $article * @param ParserOptions $popts * @param bool $useOutdated (default false) * * @return ParserOutput|bool False on failure */ public function get($article, $popts, $useOutdated = false) { global $wgCacheEpoch; $canCache = $article->checkTouched(); if (!$canCache) { // It's a redirect now return false; } $touched = $article->getTouched(); $parserOutputKey = $this->getKey($article, $popts, $useOutdated); if ($parserOutputKey === false) { wfIncrStats('pcache.miss.absent'); return false; } $value = $this->mMemc->get($parserOutputKey); if (!$value) { wfDebug("ParserOutput cache miss.\n"); wfIncrStats("pcache.miss.absent"); return false; } wfDebug("ParserOutput cache found.\n"); // The edit section preference may not be the appropiate one in // the ParserOutput, as we are not storing it in the parsercache // key. Force it here. See bug 31445. $value->setEditSectionTokens($popts->getEditSection()); $wikiPage = method_exists($article, 'getPage') ? $article->getPage() : $article; if (!$useOutdated && $value->expired($touched)) { wfIncrStats("pcache.miss.expired"); $cacheTime = $value->getCacheTime(); wfDebug("ParserOutput key expired, touched {$touched}, " . "epoch {$wgCacheEpoch}, cached {$cacheTime}\n"); $value = false; } elseif ($value->isDifferentRevision($article->getLatest())) { wfIncrStats("pcache.miss.revid"); $revId = $article->getLatest(); $cachedRevId = $value->getCacheRevisionId(); wfDebug("ParserOutput key is for an old revision, latest {$revId}, cached {$cachedRevId}\n"); $value = false; } elseif (Hooks::run('RejectParserCacheValue', array($value, $wikiPage, $popts)) === false) { wfIncrStats('pcache.miss.rejected'); wfDebug("ParserOutput key valid, but rejected by RejectParserCacheValue hook handler.\n"); $value = false; } else { wfIncrStats("pcache.hit"); } return $value; }
/** * Lightweight method to get the parser output for a page, checking the parser cache * and so on. Doesn't consider most of the stuff that Article::view is forced to * consider, so it's not appropriate to use there. * * @since 1.16 (r52326) for LiquidThreads * * @param $oldid mixed integer Revision ID or null */ public function getParserOutput($oldid = null) { global $wgEnableParserCache, $wgUser; // Should the parser cache be used? $useParserCache = $wgEnableParserCache && $wgUser->getStubThreshold() == 0 && $this->exists() && $oldid === null; wfDebug(__METHOD__ . ': using parser cache: ' . ($useParserCache ? 'yes' : 'no') . "\n"); if ($wgUser->getStubThreshold()) { wfIncrStats('pcache_miss_stub'); } $parserOutput = false; if ($useParserCache) { $parserOutput = ParserCache::singleton()->get($this, $this->getParserOptions()); } if ($parserOutput === false) { // Cache miss; parse and output it. $rev = Revision::newFromTitle($this->getTitle(), $oldid); return $this->getOutputFromWikitext($rev->getText(), $useParserCache); } else { return $parserOutput; } }
/** * Get the diff table body, without header * * @return mixed */ function getDiffBody() { global $wgMemc; $fname = 'DifferenceEngine::getDiffBody'; wfProfileIn($fname); // Cacheable? $key = false; if ($this->mOldid && $this->mNewid) { $key = wfMemcKey('diff', 'version', MW_DIFF_VERSION, 'oldid', $this->mOldid, 'newid', $this->mNewid); // Try cache if (!$this->mRefreshCache) { $difftext = $wgMemc->get($key); if ($difftext) { wfIncrStats('diff_cache_hit'); $difftext = $this->localiseLineNumbers($difftext); $difftext .= "\n<!-- diff cache key {$key} -->\n"; wfProfileOut($fname); return $difftext; } } // don't try to load but save the result } else { } // Loadtext is permission safe, this just clears out the diff if (!$this->loadText()) { wfProfileOut($fname); return false; } else { if ($this->mOldRev && !$this->mOldRev->userCan(Revision::DELETED_TEXT)) { return ''; } else { if ($this->mNewRev && !$this->mNewRev->userCan(Revision::DELETED_TEXT)) { return ''; } } } $difftext = $this->generateDiffBody($this->mOldtext, $this->mNewtext); // Save to cache for 7 days // Only do this for public revs, otherwise an admin can view the diff and a non-admin can nab it! if ($this->mOldRev && $this->mOldRev->isDeleted(Revision::DELETED_TEXT)) { wfIncrStats('diff_uncacheable'); } else { if ($this->mNewRev && $this->mNewRev->isDeleted(Revision::DELETED_TEXT)) { wfIncrStats('diff_uncacheable'); } else { if ($key !== false && $difftext !== false) { wfIncrStats('diff_cache_miss'); $wgMemc->set($key, $difftext, 7 * 86400); } else { wfIncrStats('diff_uncacheable'); } } } // Replace line numbers with the text in the user's language if ($difftext !== false) { $difftext = $this->localiseLineNumbers($difftext); } wfProfileOut($fname); return $difftext; }
/** * Try to load video metadata from memcached. * @return Boolean: true on success. */ private function loadFromCache() { global $wgMemc; wfProfileIn(__METHOD__); $this->dataLoaded = false; $key = $this->getCacheKey(); $data = $wgMemc->get($key); if (!empty($data) && is_array($data)) { $this->url = $data['url']; $this->type = $data['type']; $this->submitter_user_id = $data['user_id']; $this->submitter_user_name = $data['user_name']; $this->create_date = $data['create_date']; $this->dataLoaded = true; $this->exists = true; } if ($this->dataLoaded) { wfDebug("Loaded Video:{$this->name} from cache\n"); wfIncrStats('video_cache_hit'); } else { wfIncrStats('video_cache_miss'); } wfProfileOut(__METHOD__); return $this->dataLoaded; }
/** * Retrieve the ParserOutput from ParserCache. * false if not found or outdated. * * @param Article $article * @param ParserOptions $popts * @param bool $useOutdated (default false) * * @return ParserOutput|bool False on failure */ public function get($article, $popts, $useOutdated = false) { global $wgCacheEpoch; wfProfileIn(__METHOD__); $canCache = $article->checkTouched(); if (!$canCache) { // It's a redirect now wfProfileOut(__METHOD__); return false; } $touched = $article->getTouched(); $parserOutputKey = $this->getKey($article, $popts, $useOutdated); if ($parserOutputKey === false) { wfIncrStats('pcache_miss_absent'); wfProfileOut(__METHOD__); return false; } $value = $this->mMemc->get($parserOutputKey); if (!$value) { wfDebug("ParserOutput cache miss.\n"); wfIncrStats("pcache_miss_absent"); wfProfileOut(__METHOD__); return false; } wfDebug("ParserOutput cache found.\n"); // The edit section preference may not be the appropiate one in // the ParserOutput, as we are not storing it in the parsercache // key. Force it here. See bug 31445. $value->setEditSectionTokens($popts->getEditSection()); if (!$useOutdated && $value->expired($touched)) { wfIncrStats("pcache_miss_expired"); $cacheTime = $value->getCacheTime(); wfDebug("ParserOutput key expired, touched {$touched}, " . "epoch {$wgCacheEpoch}, cached {$cacheTime}\n"); $value = false; } elseif ($value->isDifferentRevision($article->getLatest())) { wfIncrStats("pcache_miss_revid"); $revId = $article->getLatest(); $cachedRevId = $value->getCacheRevisionId(); wfDebug("ParserOutput key is for an old revision, latest {$revId}, cached {$cachedRevId}\n"); $value = false; } else { wfIncrStats("pcache_hit"); } wfProfileOut(__METHOD__); return $value; }
/** * Retrieve the ParserOutput from ParserCache. * false if not found or outdated. * * @param $article Article * @param $popts ParserOptions * @param $useOutdated * * @return ParserOutput|false */ public function get($article, $popts, $useOutdated = false) { global $wgCacheEpoch; wfProfileIn(__METHOD__); $canCache = $article->checkTouched(); if (!$canCache) { // It's a redirect now wfProfileOut(__METHOD__); return false; } $touched = $article->getTouched(); $parserOutputKey = $this->getKey($article, $popts, $useOutdated); if ($parserOutputKey === false) { wfIncrStats('pcache_miss_absent'); wfProfileOut(__METHOD__); return false; } $value = $this->mMemc->get($parserOutputKey); if (self::try116cache && !$value && strpos($value, '*') !== -1) { wfDebug("New format parser cache miss.\n"); $parserOutputKey = $this->getParserOutputKey($article, $popts->optionsHash(ParserOptions::legacyOptions(), $article->getTitle())); $value = $this->mMemc->get($parserOutputKey); } if (!$value) { wfDebug("ParserOutput cache miss.\n"); wfIncrStats("pcache_miss_absent"); wfProfileOut(__METHOD__); return false; } wfDebug("ParserOutput cache found.\n"); // The edit section preference may not be the appropiate one in // the ParserOutput, as we are not storing it in the parsercache // key. Force it here. See bug 31445. $value->setEditSectionTokens($popts->getEditSection()); if (!$useOutdated && $value->expired($touched)) { wfIncrStats("pcache_miss_expired"); $cacheTime = $value->getCacheTime(); wfDebug("ParserOutput key expired, touched {$touched}, epoch {$wgCacheEpoch}, cached {$cacheTime}\n"); $value = false; } else { wfIncrStats("pcache_hit"); } wfProfileOut(__METHOD__); return $value; }
/** * @param $out OutputPage * @param $text String * @return bool */ public function beforePageDisplayHTML(&$out, &$text) { global $wgContLang, $wgRequest, $wgMemc, $wgUser; wfProfileIn(__METHOD__); $userAgent = $_SERVER['HTTP_USER_AGENT']; $acceptHeader = isset($_SERVER["HTTP_ACCEPT"]) ? $_SERVER["HTTP_ACCEPT"] : ''; $uAmd5 = md5($userAgent); $key = wfMemcKey('mobile', 'ua', $uAmd5); $props = null; try { $props = $wgMemc->get($key); if (!$props) { $wurflConfigFile = RESOURCES_DIR . 'wurfl-config.xml'; $wurflConfig = new WURFL_Configuration_XmlConfig($wurflConfigFile); $wurflManagerFactory = new WURFL_WURFLManagerFactory($wurflConfig); $wurflManager = $wurflManagerFactory->create(); $device = $wurflManager->getDeviceForHttpRequest($_SERVER); if ($device->isSpecific() === true) { $props = $device->getAllCapabilities(); $wgMemc->set($key, $props, 86400); } else { $wgMemc->set($key, 'generic', 86400); $props = 'generic'; } } } catch (Exception $e) { // echo $e->getMessage(); } // Note: The WebRequest Class calls are made in this block because // since PHP 5.1.x, all objects have their destructors called // before the output buffer callback function executes. // Thus, globalized objects will not be available as expected in the function. // This is stated to be intended behavior, as per the following: [http://bugs.php.net/bug.php?id=40104] $xDevice = isset($_SERVER['HTTP_X_DEVICE']) ? $_SERVER['HTTP_X_DEVICE'] : ''; self::$useFormat = $wgRequest->getText('useformat'); $mobileAction = $wgRequest->getText('mobileaction'); $action = $wgRequest->getText('action'); if (self::$useFormat !== 'mobile' && self::$useFormat !== 'mobile-wap' && !$xDevice) { wfProfileOut(__METHOD__); return true; } if ($action === 'edit' || $mobileAction === 'view_normal_site') { wfProfileOut(__METHOD__); return true; } self::$title = $out->getTitle(); if (self::$title->isMainPage()) { self::$isMainPage = true; } if (self::$title->getNamespace() == NS_FILE) { self::$isFilePage = true; } self::$htmlTitle = $out->getHTMLTitle(); self::$disableImages = $wgRequest->getText('disableImages', 0); self::$enableImages = $wgRequest->getText('enableImages', 0); self::$displayNoticeId = $wgRequest->getText('noticeid', ''); if (self::$disableImages == 1) { $wgRequest->response()->setcookie('disableImages', 1); $location = str_replace('?disableImages=1', '', str_replace('&disableImages=1', '', $wgRequest->getFullRequestURL())); $location = str_replace('&mfi=1', '', str_replace('&mfi=0', '', $location)); $location = $this->getRelativeURL($location); $wgRequest->response()->header('Location: ' . $location . '&mfi=0'); } elseif (self::$disableImages == 0) { $disableImages = $wgRequest->getCookie('disableImages'); if ($disableImages) { self::$disableImages = $disableImages; } } if (self::$enableImages == 1) { $disableImages = $wgRequest->getCookie('disableImages'); if ($disableImages) { $wgRequest->response()->setcookie('disableImages', ''); } $location = str_replace('?enableImages=1', '', str_replace('&enableImages=1', '', $wgRequest->getFullRequestURL())); $location = str_replace('&mfi=1', '', str_replace('&mfi=0', '', $location)); $location = $this->getRelativeURL($location); $wgRequest->response()->header('Location: ' . $location . '&mfi=1'); } self::$format = $wgRequest->getText('format'); self::$callback = $wgRequest->getText('callback'); self::$requestedSegment = $wgRequest->getText('seg', 0); self::$search = $wgRequest->getText('search'); self::$searchField = $wgRequest->getText('search', ''); $device = new DeviceDetection(); if ($xDevice) { $formatName = $xDevice; } else { $formatName = $device->formatName($userAgent, $acceptHeader); } self::$device = $device->format($formatName); if (self::$device['view_format'] === 'wml') { $this->contentFormat = 'WML'; } elseif (self::$device['view_format'] === 'html') { $this->contentFormat = 'XHTML'; } if (self::$useFormat === 'mobile-wap') { $this->contentFormat = 'WML'; } if ($mobileAction == 'leave_feedback') { echo $this->renderLeaveFeedbackXHTML(); wfProfileOut(__METHOD__); exit; } if ($mobileAction == 'leave_feedback_post') { $this->getMsg(); $subject = $wgRequest->getText('subject', ''); $message = $wgRequest->getText('message', ''); $token = $wgRequest->getText('edittoken', ''); $title = Title::newFromText(self::$messages['mobile-frontend-feedback-page']); if ($title->userCan('edit') && !$wgUser->isBlockedFrom($title) && $wgUser->matchEditToken($token)) { $article = new Article($title, 0); $rawtext = $article->getRawText(); $rawtext .= "\n== {$subject} == \n {$message} ~~~~ \n <small>User agent: {$userAgent}</small> "; $article->doEdit($rawtext, ''); } $location = str_replace('&mobileaction=leave_feedback_post', '', $wgRequest->getFullRequestURL() . '¬iceid=1&useformat=mobile'); $location = $this->getRelativeURL($location); $wgRequest->response()->header('Location: ' . $location); wfProfileOut(__METHOD__); exit; } if ($mobileAction == 'disable_mobile_site' && $this->contentFormat == 'XHTML') { echo $this->renderDisableMobileSiteXHTML(); wfProfileOut(__METHOD__); exit; } if ($mobileAction == 'opt_in_mobile_site' && $this->contentFormat == 'XHTML') { echo $this->renderOptInMobileSiteXHTML(); wfProfileOut(__METHOD__); exit; } if ($mobileAction == 'opt_out_mobile_site' && $this->contentFormat == 'XHTML') { echo $this->renderOptOutMobileSiteXHTML(); wfProfileOut(__METHOD__); exit; } if ($mobileAction == 'opt_in_cookie') { wfIncrStats('mobile.opt_in_cookie_set'); $this->setOptInOutCookie('1'); $this->disableCaching(); $location = wfExpandUrl(Title::newMainPage()->getFullURL(), PROTO_CURRENT); $wgRequest->response()->header('Location: ' . $location); } if ($mobileAction == 'opt_out_cookie') { $this->setOptInOutCookie(''); } $this->getMsg(); $this->disableCaching(); $this->sendXDeviceVaryHeader(); $this->sendApplicationVersionVaryHeader(); $this->checkUserStatus(); $this->checkUserLoggedIn(); if (self::$title->isSpecial('Userlogin') && self::$isBetaGroupMember) { self::$wsLoginToken = $wgRequest->getSessionData('wsLoginToken'); $q = array('action' => 'submitlogin', 'type' => 'login'); $returnToVal = $wgRequest->getVal('returnto'); if ($returnToVal) { $q['returnto'] = $returnToVal; } self::$wsLoginFormAction = self::$title->getLocalURL($q); } $this->setDefaultLogo(); ob_start(array($this, 'DOMParse')); wfProfileOut(__METHOD__); return true; }
/** * Get lag time for each DB * Results are cached for a short time in memcached */ function getLagTimes() { wfProfileIn(__METHOD__); $expiry = 5; $requestRate = 10; global $wgMemc; $times = $wgMemc->get(wfMemcKey('lag_times')); if ($times) { # Randomly recache with probability rising over $expiry $elapsed = time() - $times['timestamp']; $chance = max(0, ($expiry - $elapsed) * $requestRate); if (mt_rand(0, $chance) != 0) { unset($times['timestamp']); wfProfileOut(__METHOD__); return $times; } wfIncrStats('lag_cache_miss_expired'); } else { wfIncrStats('lag_cache_miss_absent'); } # Cache key missing or expired $times = array(); foreach ($this->mServers as $i => $conn) { if ($i == 0) { # Master $times[$i] = 0; } elseif ($this->openConnection($i)) { $times[$i] = $this->mConnections[$i]->getLag(); } } # Add a timestamp key so we know when it was cached $times['timestamp'] = time(); $wgMemc->set(wfMemcKey('lag_times'), $times, $expiry); # But don't give the timestamp to the caller unset($times['timestamp']); wfProfileOut(__METHOD__); return $times; }
/** * Get data of requested article. * @param Title $title * @param boolean $noImages * @return array */ private function getData(Title $title, $noImages) { global $wgMemc, $wgUseTidy, $wgMFTidyMobileViewSections, $wgMFMinCachedPageSize, $wgMFSpecialCaseMainPage; $wp = $this->makeWikiPage($title); if ($this->followRedirects && $wp->isRedirect()) { $newTitle = $wp->getRedirectTarget(); if ($newTitle) { $title = $newTitle; $this->getResult()->addValue(null, $this->getModuleName(), array('redirected' => $title->getPrefixedText())); if ($title->getNamespace() < 0) { $this->getResult()->addValue(null, $this->getModuleName(), array('viewable' => 'no')); return array(); } $wp = $this->makeWikiPage($title); } } $latest = $wp->getLatest(); if ($this->file) { $key = wfMemcKey('mf', 'mobileview', self::CACHE_VERSION, $noImages, $latest, $this->noTransform, $this->file->getSha1(), $this->variant); $cacheExpiry = 3600; } else { if (!$latest) { // https://bugzilla.wikimedia.org/show_bug.cgi?id=53378 // Title::exists() above doesn't seem to always catch recently deleted pages $this->dieUsageMsg(array('notanarticle', $title->getPrefixedText())); } $parserOptions = $this->makeParserOptions($wp); $parserCacheKey = ParserCache::singleton()->getKey($wp, $parserOptions); $key = wfMemcKey('mf', 'mobileview', self::CACHE_VERSION, $noImages, $latest, $this->noTransform, $parserCacheKey); } $data = $wgMemc->get($key); if ($data) { wfIncrStats('mobile.view.cache-hit'); return $data; } wfIncrStats('mobile.view.cache-miss'); if ($this->file) { $html = $this->getFilePage($title); } else { $parserOutput = $this->getParserOutput($wp, $parserOptions); $html = $parserOutput->getText(); $cacheExpiry = $parserOutput->getCacheExpiry(); } if (!$this->noTransform) { $mf = new MobileFormatter(MobileFormatter::wrapHTML($html), $title); $mf->setRemoveMedia($noImages); $mf->filterContent(); $mf->setIsMainPage($this->mainPage && $wgMFSpecialCaseMainPage); $html = $mf->getText(); } if ($this->mainPage || $this->file) { $data = array('sections' => array(), 'text' => array($html), 'refsections' => array()); } else { $data = array(); $data['sections'] = $parserOutput->getSections(); $sectionCount = count($data['sections']); for ($i = 0; $i < $sectionCount; $i++) { $data['sections'][$i]['line'] = $title->getPageLanguage()->convert($data['sections'][$i]['line']); } $chunks = preg_split('/<h(?=[1-6]\\b)/i', $html); if (count($chunks) != count($data['sections']) + 1) { wfDebugLog('mobile', __METHOD__ . "(): mismatching number of " . "sections from parser and split on page {$title->getPrefixedText()}, oldid={$latest}"); // We can't be sure about anything here, return all page HTML as one big section $chunks = array($html); $data['sections'] = array(); } $data['text'] = array(); $data['refsections'] = array(); foreach ($chunks as $chunk) { if (count($data['text'])) { $chunk = "<h{$chunk}"; } if ($wgUseTidy && $wgMFTidyMobileViewSections && count($chunks) > 1) { $chunk = MWTidy::tidy($chunk); } if (preg_match('/<ol\\b[^>]*?class="references"/', $chunk)) { $data['refsections'][count($data['text'])] = true; } $data['text'][] = $chunk; } if ($this->usePageImages) { $image = $this->getPageImage($title); if ($image) { $data['image'] = $image->getTitle()->getText(); } } } $data['lastmodified'] = wfTimestamp(TS_ISO_8601, $wp->getTimestamp()); // Page id $data['id'] = $wp->getId(); $user = User::newFromId($wp->getUser()); if (!$user->isAnon()) { $data['lastmodifiedby'] = array('name' => $wp->getUserText(), 'gender' => $user->getOption('gender')); } else { $data['lastmodifiedby'] = null; } $data['revision'] = $title->getLatestRevID(); if (isset($parserOutput)) { $languages = $parserOutput->getLanguageLinks(); $data['languagecount'] = count($languages); $data['displaytitle'] = $parserOutput->getDisplayTitle(); // @fixme: Does no work for some extension properties that get added in LinksUpdate $data['pageprops'] = $parserOutput->getProperties(); } else { $data['languagecount'] = 0; $data['displaytitle'] = $title->getPrefixedText(); $data['pageprops'] = array(); } if ($title->getPageLanguage()->hasVariants()) { $data['hasvariants'] = true; } // Don't store small pages to decrease cache size requirements if (strlen($html) >= $wgMFMinCachedPageSize) { // store for the same time as original parser output $wgMemc->set($key, $data, $cacheExpiry); } return $data; }
/** * Call wfIncrStats() for the queue overall and for the queue type * * @param string $key Event type * @param string $type Job type * @param int $delta * @param string $wiki Wiki ID (added in 1.23) * @since 1.22 */ public static function incrStats($key, $type, $delta = 1, $wiki = null) { wfIncrStats($key, $delta); wfIncrStats("{$key}-{$type}", $delta); if ($wiki !== null) { wfIncrStats("{$key}-{$type}-{$wiki}", $delta); } }
/** * This is the default action of the script: just view the page of * the given title. */ function view() { global $wgUser, $wgOut, $wgRequest, $wgContLang; global $wgEnableParserCache, $wgStylePath, $wgUseRCPatrol, $wgParser; global $wgUseTrackbacks, $wgNamespaceRobotPolicies; $sk = $wgUser->getSkin(); wfProfileIn(__METHOD__); $parserCache =& ParserCache::singleton(); $ns = $this->mTitle->getNamespace(); # shortcut # Get variables from query string $oldid = $this->getOldID(); # getOldID may want us to redirect somewhere else if ($this->mRedirectUrl) { $wgOut->redirect($this->mRedirectUrl); wfProfileOut(__METHOD__); return; } $diff = $wgRequest->getVal('diff'); $rcid = $wgRequest->getVal('rcid'); $rdfrom = $wgRequest->getVal('rdfrom'); $wgOut->setArticleFlag(true); if (isset($wgNamespaceRobotPolicies[$ns])) { $policy = $wgNamespaceRobotPolicies[$ns]; } else { # The default policy. Dev note: make sure you change the documentation # in DefaultSettings.php before changing it. $policy = 'index,follow'; } $wgOut->setRobotpolicy($policy); # If we got diff and oldid in the query, we want to see a # diff page instead of the article. if (!is_null($diff)) { $wgOut->setPageTitle($this->mTitle->getPrefixedText()); $de = new DifferenceEngine($this->mTitle, $oldid, $diff, $rcid); // DifferenceEngine directly fetched the revision: $this->mRevIdFetched = $de->mNewid; $de->showDiffPage(); // Needed to get the page's current revision $this->loadPageData(); if ($diff == 0 || $diff == $this->mLatest) { # Run view updates for current revision only $this->viewUpdates(); } wfProfileOut(__METHOD__); return; } if (empty($oldid) && $this->checkTouched()) { $wgOut->setETag($parserCache->getETag($this, $wgUser)); if ($wgOut->checkLastModified($this->mTouched)) { wfProfileOut(__METHOD__); return; } else { if ($this->tryFileCache()) { # tell wgOut that output is taken care of $wgOut->disable(); $this->viewUpdates(); wfProfileOut(__METHOD__); return; } } } # Should the parser cache be used? $pcache = $wgEnableParserCache && intval($wgUser->getOption('stubthreshold')) == 0 && $this->exists() && empty($oldid); wfDebug('Article::view using parser cache: ' . ($pcache ? 'yes' : 'no') . "\n"); if ($wgUser->getOption('stubthreshold')) { wfIncrStats('pcache_miss_stub'); } $wasRedirected = false; if (isset($this->mRedirectedFrom)) { // This is an internally redirected page view. // We'll need a backlink to the source page for navigation. if (wfRunHooks('ArticleViewRedirect', array(&$this))) { $sk = $wgUser->getSkin(); $redir = $sk->makeKnownLinkObj($this->mRedirectedFrom, '', 'redirect=no'); $s = wfMsg('redirectedfrom', $redir); $wgOut->setSubtitle($s); // Set the fragment if one was specified in the redirect if (strval($this->mTitle->getFragment()) != '') { $fragment = Xml::escapeJsString($this->mTitle->getFragmentForURL()); $wgOut->addInlineScript("redirectToFragment(\"{$fragment}\");"); } $wasRedirected = true; } } elseif (!empty($rdfrom)) { // This is an externally redirected view, from some other wiki. // If it was reported from a trusted site, supply a backlink. global $wgRedirectSources; if ($wgRedirectSources && preg_match($wgRedirectSources, $rdfrom)) { $sk = $wgUser->getSkin(); $redir = $sk->makeExternalLink($rdfrom, $rdfrom); $s = wfMsg('redirectedfrom', $redir); $wgOut->setSubtitle($s); $wasRedirected = true; } } $outputDone = false; if ($pcache) { if ($wgOut->tryParserCache($this, $wgUser)) { wfRunHooks('ArticleViewHeader', array(&$this)); $outputDone = true; } } if (!$outputDone) { $text = $this->getContent(); if ($text === false) { # Failed to load, replace text with error message $t = $this->mTitle->getPrefixedText(); if ($oldid) { $t .= ',oldid=' . $oldid; $text = wfMsg('missingarticle', $t); } else { $text = wfMsg('noarticletext', $t); } } # Another whitelist check in case oldid is altering the title if (!$this->mTitle->userCanRead()) { $wgOut->loginToUse(); $wgOut->output(); exit; } # We're looking at an old revision if (!empty($oldid)) { $wgOut->setRobotpolicy('noindex,nofollow'); if (is_null($this->mRevision)) { // FIXME: This would be a nice place to load the 'no such page' text. } else { $this->setOldSubtitle(isset($this->mOldId) ? $this->mOldId : $oldid); if ($this->mRevision->isDeleted(Revision::DELETED_TEXT)) { if (!$this->mRevision->userCan(Revision::DELETED_TEXT)) { $wgOut->addWikiText(wfMsg('rev-deleted-text-permission')); $wgOut->setPageTitle($this->mTitle->getPrefixedText()); return; } else { $wgOut->addWikiText(wfMsg('rev-deleted-text-view')); // and we are allowed to see... } } } } } if (!$outputDone) { /** * @fixme: this hook doesn't work most of the time, as it doesn't * trigger when the parser cache is used. */ wfRunHooks('ArticleViewHeader', array(&$this)); $wgOut->setRevisionId($this->getRevIdFetched()); # wrap user css and user js in pre and don't parse # XXX: use $this->mTitle->usCssJsSubpage() when php is fixed/ a workaround is found if ($ns == NS_USER && preg_match('/\\/[\\w]+\\.(css|js)$/', $this->mTitle->getDBkey())) { $wgOut->addWikiText(wfMsg('clearyourcache')); $wgOut->addHTML('<pre>' . htmlspecialchars($this->mContent) . "\n</pre>"); } else { if ($rt = Title::newFromRedirect($text)) { # Display redirect $imageDir = $wgContLang->isRTL() ? 'rtl' : 'ltr'; $imageUrl = $wgStylePath . '/common/images/redirect' . $imageDir . '.png'; # Don't overwrite the subtitle if this was an old revision if (!$wasRedirected && $this->isCurrent()) { $wgOut->setSubtitle(wfMsgHtml('redirectpagesub')); } $link = $sk->makeLinkObj($rt, $rt->getFullText()); $wgOut->addHTML('<img src="' . $imageUrl . '" alt="#REDIRECT " />' . '<span class="redirectText">' . $link . '</span>'); $parseout = $wgParser->parse($text, $this->mTitle, ParserOptions::newFromUser($wgUser)); $wgOut->addParserOutputNoText($parseout); } else { if ($pcache) { # Display content and save to parser cache $wgOut->addPrimaryWikiText($text, $this); } else { # Display content, don't attempt to save to parser cache # Don't show section-edit links on old revisions... this way lies madness. if (!$this->isCurrent()) { $oldEditSectionSetting = $wgOut->parserOptions()->setEditSection(false); } # Display content and don't save to parser cache $wgOut->addPrimaryWikiText($text, $this, false); if (!$this->isCurrent()) { $wgOut->parserOptions()->setEditSection($oldEditSectionSetting); } } } } } /* title may have been set from the cache */ $t = $wgOut->getPageTitle(); if (empty($t)) { $wgOut->setPageTitle($this->mTitle->getPrefixedText()); } # check if we're displaying a [[User talk:x.x.x.x]] anonymous talk page if ($ns == NS_USER_TALK && User::isIP($this->mTitle->getText())) { $wgOut->addWikiText(wfMsg('anontalkpagetext')); } # If we have been passed an &rcid= parameter, we want to give the user a # chance to mark this new article as patrolled. if ($wgUseRCPatrol && !is_null($rcid) && $rcid != 0 && $wgUser->isAllowed('patrol')) { $wgOut->addHTML("<div class='patrollink'>" . wfMsg('markaspatrolledlink', $sk->makeKnownLinkObj($this->mTitle, wfMsg('markaspatrolledtext'), "action=markpatrolled&rcid={$rcid}")) . '</div>'); } # Trackbacks if ($wgUseTrackbacks) { $this->addTrackbacks(); } $this->viewUpdates(); wfProfileOut(__METHOD__); }
/** * This is the default action of the index.php entry point: just view the * page of the given title. */ public function view() { global $wgParser, $wgUseFileCache, $wgUseETag, $wgDebugToolbar; wfProfileIn(__METHOD__); # Get variables from query string # As side effect this will load the revision and update the title # in a revision ID is passed in the request, so this should remain # the first call of this method even if $oldid is used way below. $oldid = $this->getOldID(); $user = $this->getContext()->getUser(); # Another whitelist check in case getOldID() is altering the title $permErrors = $this->getTitle()->getUserPermissionsErrors('read', $user); if (count($permErrors)) { wfDebug(__METHOD__ . ": denied on secondary read check\n"); wfProfileOut(__METHOD__); throw new PermissionsError('read', $permErrors); } $outputPage = $this->getContext()->getOutput(); # getOldID() may as well want us to redirect somewhere else if ($this->mRedirectUrl) { $outputPage->redirect($this->mRedirectUrl); wfDebug(__METHOD__ . ": redirecting due to oldid\n"); wfProfileOut(__METHOD__); return; } # If we got diff in the query, we want to see a diff page instead of the article. if ($this->getContext()->getRequest()->getCheck('diff')) { wfDebug(__METHOD__ . ": showing diff page\n"); $this->showDiffPage(); wfProfileOut(__METHOD__); return; } # Set page title (may be overridden by DISPLAYTITLE) $outputPage->setPageTitle($this->getTitle()->getPrefixedText()); $outputPage->setArticleFlag(true); # Allow frames by default $outputPage->allowClickjacking(); $parserCache = ParserCache::singleton(); $parserOptions = $this->getParserOptions(); # Render printable version, use printable version cache if ($outputPage->isPrintable()) { $parserOptions->setIsPrintable(true); $parserOptions->setEditSection(false); } elseif (!$this->isCurrent() || !$this->getTitle()->quickUserCan('edit', $user)) { $parserOptions->setEditSection(false); } # Try client and file cache if (!$wgDebugToolbar && $oldid === 0 && $this->mPage->checkTouched()) { if ($wgUseETag) { $outputPage->setETag($parserCache->getETag($this, $parserOptions)); } # Is it client cached? if ($outputPage->checkLastModified($this->mPage->getTouched())) { wfDebug(__METHOD__ . ": done 304\n"); wfProfileOut(__METHOD__); return; # Try file cache } elseif ($wgUseFileCache && $this->tryFileCache()) { wfDebug(__METHOD__ . ": done file cache\n"); # tell wgOut that output is taken care of $outputPage->disable(); $this->mPage->doViewUpdates($user); wfProfileOut(__METHOD__); return; } } # Should the parser cache be used? $useParserCache = $this->mPage->isParserCacheUsed($parserOptions, $oldid); wfDebug('Article::view using parser cache: ' . ($useParserCache ? 'yes' : 'no') . "\n"); if ($user->getStubThreshold()) { wfIncrStats('pcache_miss_stub'); } $this->showRedirectedFromHeader(); $this->showNamespaceHeader(); # Iterate through the possible ways of constructing the output text. # Keep going until $outputDone is set, or we run out of things to do. $pass = 0; $outputDone = false; $this->mParserOutput = false; while (!$outputDone && ++$pass) { switch ($pass) { case 1: wfRunHooks('ArticleViewHeader', array(&$this, &$outputDone, &$useParserCache)); break; case 2: # Early abort if the page doesn't exist if (!$this->mPage->exists()) { wfDebug(__METHOD__ . ": showing missing article\n"); $this->showMissingArticle(); wfProfileOut(__METHOD__); return; } # Try the parser cache if ($useParserCache) { $this->mParserOutput = $parserCache->get($this, $parserOptions); if ($this->mParserOutput !== false) { if ($oldid) { wfDebug(__METHOD__ . ": showing parser cache contents for current rev permalink\n"); $this->setOldSubtitle($oldid); } else { wfDebug(__METHOD__ . ": showing parser cache contents\n"); } $outputPage->addParserOutput($this->mParserOutput); # Ensure that UI elements requiring revision ID have # the correct version information. $outputPage->setRevisionId($this->mPage->getLatest()); # Preload timestamp to avoid a DB hit $cachedTimestamp = $this->mParserOutput->getTimestamp(); if ($cachedTimestamp !== null) { $outputPage->setRevisionTimestamp($cachedTimestamp); $this->mPage->setTimestamp($cachedTimestamp); } $outputDone = true; } } break; case 3: # This will set $this->mRevision if needed $this->fetchContentObject(); # Are we looking at an old revision if ($oldid && $this->mRevision) { $this->setOldSubtitle($oldid); if (!$this->showDeletedRevisionHeader()) { wfDebug(__METHOD__ . ": cannot view deleted revision\n"); wfProfileOut(__METHOD__); return; } } # Ensure that UI elements requiring revision ID have # the correct version information. $outputPage->setRevisionId($this->getRevIdFetched()); # Preload timestamp to avoid a DB hit $outputPage->setRevisionTimestamp($this->getTimestamp()); # Pages containing custom CSS or JavaScript get special treatment if ($this->getTitle()->isCssOrJsPage() || $this->getTitle()->isCssJsSubpage()) { wfDebug(__METHOD__ . ": showing CSS/JS source\n"); $this->showCssOrJsPage(); $outputDone = true; } elseif (!wfRunHooks('ArticleContentViewCustom', array($this->fetchContentObject(), $this->getTitle(), $outputPage))) { # Allow extensions do their own custom view for certain pages $outputDone = true; } elseif (!ContentHandler::runLegacyHooks('ArticleViewCustom', array($this->fetchContentObject(), $this->getTitle(), $outputPage))) { # Allow extensions do their own custom view for certain pages $outputDone = true; } else { $content = $this->getContentObject(); $rt = $content->getRedirectChain(); if ($rt) { wfDebug(__METHOD__ . ": showing redirect=no page\n"); # Viewing a redirect page (e.g. with parameter redirect=no) $outputPage->addHTML($this->viewRedirect($rt)); # Parse just to get categories, displaytitle, etc. $this->mParserOutput = $content->getParserOutput($this->getTitle(), $oldid, $parserOptions, false); $outputPage->addParserOutputNoText($this->mParserOutput); $outputDone = true; } } break; case 4: # Run the parse, protected by a pool counter wfDebug(__METHOD__ . ": doing uncached parse\n"); // @todo: shouldn't we be passing $this->getPage() to PoolWorkArticleView instead of plain $this? $poolArticleView = new PoolWorkArticleView($this, $parserOptions, $this->getRevIdFetched(), $useParserCache, $this->getContentObject(), $this->getContext()); if (!$poolArticleView->execute()) { $error = $poolArticleView->getError(); if ($error) { $outputPage->clearHTML(); // for release() errors $outputPage->enableClientCache(false); $outputPage->setRobotPolicy('noindex,nofollow'); $errortext = $error->getWikiText(false, 'view-pool-error'); $outputPage->addWikiText('<div class="errorbox">' . $errortext . '</div>'); } # Connection or timeout error wfProfileOut(__METHOD__); return; } $this->mParserOutput = $poolArticleView->getParserOutput(); $outputPage->addParserOutput($this->mParserOutput); # Don't cache a dirty ParserOutput object if ($poolArticleView->getIsDirty()) { $outputPage->setSquidMaxage(0); $outputPage->addHTML("<!-- parser cache is expired, sending anyway due to pool overload-->\n"); } $outputDone = true; break; # Should be unreachable, but just in case... # Should be unreachable, but just in case... default: break 2; } } # Get the ParserOutput actually *displayed* here. # Note that $this->mParserOutput is the *current* version output. $pOutput = $outputDone instanceof ParserOutput ? $outputDone : $this->mParserOutput; # Adjust title for main page & pages with displaytitle if ($pOutput) { $this->adjustDisplayTitle($pOutput); } # For the main page, overwrite the <title> element with the con- # tents of 'pagetitle-view-mainpage' instead of the default (if # that's not empty). # This message always exists because it is in the i18n files if ($this->getTitle()->isMainPage()) { $msg = wfMessage('pagetitle-view-mainpage')->inContentLanguage(); if (!$msg->isDisabled()) { $outputPage->setHTMLTitle($msg->title($this->getTitle())->text()); } } # Check for any __NOINDEX__ tags on the page using $pOutput $policy = $this->getRobotPolicy('view', $pOutput); $outputPage->setIndexPolicy($policy['index']); $outputPage->setFollowPolicy($policy['follow']); $this->showViewFooter(); $this->mPage->doViewUpdates($user); wfProfileOut(__METHOD__); }
public function getLagTimes($serverIndexes, $wiki) { if (count($serverIndexes) == 1 && reset($serverIndexes) == 0) { // Single server only, just return zero without caching return array(0 => 0); } $section = new ProfileSection(__METHOD__); $expiry = 5; $requestRate = 10; global $wgMemc; if (empty($wgMemc)) { $wgMemc = wfGetMainCache(); } $masterName = $this->parent->getServerName(0); $memcKey = wfMemcKey('lag_times', $masterName); $times = $wgMemc->get($memcKey); if (is_array($times)) { # Randomly recache with probability rising over $expiry $elapsed = time() - $times['timestamp']; $chance = max(0, ($expiry - $elapsed) * $requestRate); if (mt_rand(0, $chance) != 0) { unset($times['timestamp']); // hide from caller return $times; } wfIncrStats('lag_cache_miss_expired'); } else { wfIncrStats('lag_cache_miss_absent'); } # Cache key missing or expired if ($wgMemc->add("{$memcKey}:lock", 1, 10)) { # Let this process alone update the cache value $unlocker = new ScopedCallback(function () use($wgMemc, $memcKey) { $wgMemc->delete($memcKey); }); } elseif (is_array($times)) { # Could not acquire lock but an old cache exists, so use it unset($times['timestamp']); // hide from caller return $times; } $times = array(); foreach ($serverIndexes as $i) { if ($i == 0) { # Master $times[$i] = 0; } elseif (false !== ($conn = $this->parent->getAnyOpenConnection($i))) { $times[$i] = $conn->getLag(); } elseif (false !== ($conn = $this->parent->openConnection($i, $wiki))) { $times[$i] = $conn->getLag(); } } # Add a timestamp key so we know when it was cached $times['timestamp'] = time(); $wgMemc->set($memcKey, $times, $expiry + 10); unset($times['timestamp']); // hide from caller return $times; }
/** * Run JavaScript or CSS data through a filter, caching the filtered result for future calls. * * Available filters are: * * - minify-js \see JavaScriptMinifier::minify * - minify-css \see CSSMin::minify * * If $data is empty, only contains whitespace or the filter was unknown, * $data is returned unmodified. * * @param string $filter Name of filter to run * @param string $data Text to filter, such as JavaScript or CSS text * @param string $cacheReport Whether to include the cache key report * @return string Filtered data, or a comment containing an error message */ public function filter($filter, $data, $cacheReport = true) { // For empty/whitespace-only data or for unknown filters, don't perform // any caching or processing if (trim($data) === '' || !in_array($filter, array('minify-js', 'minify-css'))) { return $data; } // Try for cache hit // Use CACHE_ANYTHING since filtering is very slow compared to DB queries $key = wfMemcKey('resourceloader', 'filter', $filter, self::$filterCacheVersion, md5($data)); $cache = wfGetCache(CACHE_ANYTHING); $cacheEntry = $cache->get($key); if (is_string($cacheEntry)) { wfIncrStats("rl-{$filter}-cache-hits"); return $cacheEntry; } $result = ''; // Run the filter - we've already verified one of these will work try { wfIncrStats("rl-{$filter}-cache-misses"); switch ($filter) { case 'minify-js': $result = JavaScriptMinifier::minify($data, $this->config->get('ResourceLoaderMinifierStatementsOnOwnLine'), $this->config->get('ResourceLoaderMinifierMaxLineLength')); if ($cacheReport) { $result .= "\n/* cache key: {$key} */"; } break; case 'minify-css': $result = CSSMin::minify($data); if ($cacheReport) { $result .= "\n/* cache key: {$key} */"; } break; } // Save filtered text to Memcached $cache->set($key, $result); } catch (Exception $e) { MWExceptionHandler::logException($e); wfDebugLog('resourceloader', __METHOD__ . ": minification failed: {$e}"); $this->errors[] = self::formatExceptionNoComment($e); } return $result; }
/** * Saves the settings submitted by the settings form. Redirects the user to the destination * of returnto or, if not set, back to this special page */ private function submitSettingsForm() { $schema = 'MobileOptionsTracking'; $schemaRevision = 14003392; $schemaData = array('action' => 'success', 'images' => "nochange", 'beta' => "nochange"); $context = MobileContext::singleton(); $request = $this->getRequest(); $user = $this->getUser(); if ($user->isLoggedIn() && !$user->matchEditToken($request->getVal('token'))) { $errorText = __METHOD__ . '(): token mismatch'; wfIncrStats('mobile.options.errors'); wfDebugLog('mobile', $errorText); $this->getOutput()->addHTML('<div class="error">' . $this->msg("mobile-frontend-save-error")->parse() . '</div>'); $schemaData['action'] = 'error'; $schemaData['errorText'] = $errorText; ExtMobileFrontend::eventLog($schema, $schemaRevision, $schemaData); $this->getSettingsForm(); return; } wfIncrStats('mobile.options.saves'); if ($request->getBool('enableBeta')) { $group = 'beta'; if (!$context->isBetaGroupMember()) { // The request was to turn on beta $schemaData['beta'] = "on"; } } else { $group = ''; if ($context->isBetaGroupMember()) { // beta was turned off $schemaData['beta'] = "off"; } } $context->setMobileMode($group); $imagesDisabled = !$request->getBool('enableImages'); if ($context->imagesDisabled() !== $imagesDisabled) { // Only record when the state has changed $schemaData['images'] = $imagesDisabled ? "off" : "on"; } $context->setDisableImagesCookie($imagesDisabled); $returnToTitle = Title::newFromText($request->getText('returnto')); if ($returnToTitle) { $url = $returnToTitle->getFullURL(); } else { $url = $this->getPageTitle()->getFullURL('success'); } ExtMobileFrontend::eventLog($schema, $schemaRevision, $schemaData); $context->getOutput()->redirect(MobileContext::singleton()->getMobileUrl($url)); }
/** * Try to load file metadata from memcached. Returns true on success. * @return bool */ function loadFromCache() { global $wgMemc; wfProfileIn(__METHOD__); $this->dataLoaded = false; $this->extraDataLoaded = false; $key = $this->getCacheKey(); if (!$key) { wfProfileOut(__METHOD__); return false; } $cachedValues = $wgMemc->get($key); // Check if the key existed and belongs to this version of MediaWiki if (isset($cachedValues['version']) && $cachedValues['version'] == MW_FILE_VERSION) { wfDebug("Pulling file metadata from cache key {$key}\n"); $this->fileExists = $cachedValues['fileExists']; if ($this->fileExists) { $this->setProps($cachedValues); } $this->dataLoaded = true; $this->extraDataLoaded = true; foreach ($this->getLazyCacheFields('') as $field) { $this->extraDataLoaded = $this->extraDataLoaded && isset($cachedValues[$field]); } } if ($this->dataLoaded) { wfIncrStats('image_cache_hit'); } else { wfIncrStats('image_cache_miss'); } wfProfileOut(__METHOD__); return $this->dataLoaded; }
/** * Get a ParserOutput for the given ParserOptions and revision ID. * The parser cache will be used if possible. * * @since 1.19 * @param ParserOptions $parserOptions ParserOptions to use for the parse operation * @param null|int $oldid Revision ID to get the text from, passing null or 0 will * get the current revision (default value) * * @return ParserOutput or false if the revision was not found */ public function getParserOutput( ParserOptions $parserOptions, $oldid = null ) { wfProfileIn( __METHOD__ ); $useParserCache = $this->isParserCacheUsed( $parserOptions, $oldid ); wfDebug( __METHOD__ . ': using parser cache: ' . ( $useParserCache ? 'yes' : 'no' ) . "\n" ); if ( $parserOptions->getStubThreshold() ) { wfIncrStats( 'pcache_miss_stub' ); } if ( $useParserCache ) { $parserOutput = ParserCache::singleton()->get( $this, $parserOptions ); if ( $parserOutput !== false ) { wfProfileOut( __METHOD__ ); return $parserOutput; } } if ( $oldid === null || $oldid === 0 ) { $oldid = $this->getLatest(); } $pool = new PoolWorkArticleView( $this, $parserOptions, $oldid, $useParserCache ); $pool->execute(); wfProfileOut( __METHOD__ ); return $pool->getParserOutput(); }
/** * Call wfIncrStats() for the queue overall and for the queue type * * @param string $key Event type * @param string $type Job type * @param integer $delta * @since 1.22 */ public static function incrStats($key, $type, $delta = 1) { wfIncrStats($key, $delta); wfIncrStats("{$key}-{$type}", $delta); }
/** * Set the mf_useformat cookie * * This cookie can determine whether or not a user should see the mobile * version of pages. * * @param string $cookieFormat * @param null $expiry */ public function setUseFormatCookie($cookieFormat = 'true', $expiry = null) { if (is_null($expiry)) { $expiry = $this->getUseFormatCookieExpiry(); } $this->getRequest()->response()->setcookie(self::USEFORMAT_COOKIE_NAME, $cookieFormat, $expiry, array('prefix' => '', 'httpOnly' => false)); wfIncrStats('mobile.useformat_' . $cookieFormat . '_cookie_set'); }
/** * Get the diff table body, without header * * @return mixed (string/false) */ public function getDiffBody() { $this->mCacheHit = true; // Check if the diff should be hidden from this user if (!$this->loadRevisionData()) { return false; } elseif ($this->mOldRev && !$this->mOldRev->userCan(Revision::DELETED_TEXT, $this->getUser())) { return false; } elseif ($this->mNewRev && !$this->mNewRev->userCan(Revision::DELETED_TEXT, $this->getUser())) { return false; } // Short-circuit if ($this->mOldRev === false || $this->mOldRev && $this->mNewRev && $this->mOldRev->getID() == $this->mNewRev->getID()) { return ''; } // Cacheable? $key = false; $cache = ObjectCache::getMainWANInstance(); if ($this->mOldid && $this->mNewid) { $key = $this->getDiffBodyCacheKey(); // Try cache if (!$this->mRefreshCache) { $difftext = $cache->get($key); if ($difftext) { wfIncrStats('diff_cache.hit'); $difftext = $this->localiseLineNumbers($difftext); $difftext .= "\n<!-- diff cache key {$key} -->\n"; return $difftext; } } // don't try to load but save the result } $this->mCacheHit = false; // Loadtext is permission safe, this just clears out the diff if (!$this->loadText()) { return false; } $difftext = $this->generateContentDiffBody($this->mOldContent, $this->mNewContent); // Save to cache for 7 days if (!Hooks::run('AbortDiffCache', array(&$this))) { wfIncrStats('diff_cache.uncacheable'); } elseif ($key !== false && $difftext !== false) { wfIncrStats('diff_cache.miss'); $cache->set($key, $difftext, 7 * 86400); } else { wfIncrStats('diff_cache.uncacheable'); } // Replace line numbers with the text in the user's language if ($difftext !== false) { $difftext = $this->localiseLineNumbers($difftext); } return $difftext; }
} else { $wgCookiePrefix = $wgDBname; } } $wgCookiePrefix = strtr($wgCookiePrefix, "=,; +.\"'\\[", "__________"); # If session.auto_start is there, we can't touch session name # if (!wfIniGetBool('session.auto_start')) { session_name($wgSessionName ? $wgSessionName : $wgCookiePrefix . '_session'); } if (!$wgCommandLineMode && ($wgRequest->checkSessionCookie() || isset($_COOKIE[$wgCookiePrefix . 'Token']))) { wfIncrStats('request_with_session'); wfSetupSession(); $wgSessionStarted = true; } else { wfIncrStats('request_without_session'); $wgSessionStarted = false; } wfProfileOut($fname . '-SetupSession'); wfProfileIn($fname . '-globals'); $wgContLang = new StubContLang(); // Now that variant lists may be available... $wgRequest->interpolateTitle(); $wgUser = new StubUser(); $wgLang = new StubUserLang(); $wgOut = new StubObject('wgOut', 'OutputPage'); $wgParser = new StubObject('wgParser', $wgParserConf['class'], array($wgParserConf)); $wgMessageCache = new StubObject('wgMessageCache', 'MessageCache', array($messageMemc, $wgUseDatabaseMessages, $wgMsgCacheExpiry, wfWikiID())); wfProfileOut($fname . '-globals'); wfProfileIn($fname . '-User'); # Skin setup functions
/** * Get the diff table body, without header * * @return mixed (string/false) */ public function getDiffBody() { global $wgMemc; wfProfileIn(__METHOD__); $this->mCacheHit = true; // Check if the diff should be hidden from this user if (!$this->loadRevisionData()) { wfProfileOut(__METHOD__); return false; } elseif ($this->mOldRev && !$this->mOldRev->userCan(Revision::DELETED_TEXT)) { wfProfileOut(__METHOD__); return false; } elseif ($this->mNewRev && !$this->mNewRev->userCan(Revision::DELETED_TEXT)) { wfProfileOut(__METHOD__); return false; } // Short-circuit if ($this->mOldRev && $this->mNewRev && $this->mOldRev->getID() == $this->mNewRev->getID()) { wfProfileOut(__METHOD__); return ''; } // Cacheable? $key = false; if ($this->mOldid && $this->mNewid) { $key = wfMemcKey('diff', 'version', MW_DIFF_VERSION, 'oldid', $this->mOldid, 'newid', $this->mNewid); // Try cache if (!$this->mRefreshCache) { $difftext = $wgMemc->get($key); if ($difftext) { wfIncrStats('diff_cache_hit'); $difftext = $this->localiseLineNumbers($difftext); $difftext .= "\n<!-- diff cache key {$key} -->\n"; wfProfileOut(__METHOD__); return $difftext; } } // don't try to load but save the result } $this->mCacheHit = false; // Loadtext is permission safe, this just clears out the diff if (!$this->loadText()) { wfProfileOut(__METHOD__); return false; } $difftext = $this->generateDiffBody($this->mOldtext, $this->mNewtext); // Save to cache for 7 days if (!wfRunHooks('AbortDiffCache', array(&$this))) { wfIncrStats('diff_uncacheable'); } elseif ($key !== false && $difftext !== false) { wfIncrStats('diff_cache_miss'); $wgMemc->set($key, $difftext, 7 * 86400); } else { wfIncrStats('diff_uncacheable'); } // Replace line numbers with the text in the user's language if ($difftext !== false) { $difftext = $this->localiseLineNumbers($difftext); } wfProfileOut(__METHOD__); return $difftext; }
/** * Try to load image metadata from memcached. Returns true on success. */ function loadFromCache() { global $wgUseSharedUploads, $wgMemc; $fname = 'Image::loadFromMemcached'; wfProfileIn($fname); $this->dataLoaded = false; $keys = $this->getCacheKeys(); $cachedValues = $wgMemc->get($keys[0]); // Check if the key existed and belongs to this version of MediaWiki if (!empty($cachedValues) && is_array($cachedValues) && isset($cachedValues['version']) && $cachedValues['version'] == MW_IMAGE_VERSION && $cachedValues['fileExists'] && isset($cachedValues['mime']) && isset($cachedValues['metadata'])) { if ($wgUseSharedUploads && $cachedValues['fromShared']) { # if this is shared file, we need to check if image # in shared repository has not changed if (isset($keys[1])) { $commonsCachedValues = $wgMemc->get($keys[1]); if (!empty($commonsCachedValues) && is_array($commonsCachedValues) && isset($commonsCachedValues['version']) && $commonsCachedValues['version'] == MW_IMAGE_VERSION && isset($commonsCachedValues['mime'])) { wfDebug("Pulling image metadata from shared repository cache\n"); $this->name = $commonsCachedValues['name']; $this->imagePath = $commonsCachedValues['imagePath']; $this->fileExists = $commonsCachedValues['fileExists']; $this->width = $commonsCachedValues['width']; $this->height = $commonsCachedValues['height']; $this->bits = $commonsCachedValues['bits']; $this->type = $commonsCachedValues['type']; $this->mime = $commonsCachedValues['mime']; $this->metadata = $commonsCachedValues['metadata']; $this->size = $commonsCachedValues['size']; $this->fromSharedDirectory = true; $this->dataLoaded = true; $this->imagePath = $this->getFullPath(true); } } } else { wfDebug("Pulling image metadata from local cache\n"); $this->name = $cachedValues['name']; $this->imagePath = $cachedValues['imagePath']; $this->fileExists = $cachedValues['fileExists']; $this->width = $cachedValues['width']; $this->height = $cachedValues['height']; $this->bits = $cachedValues['bits']; $this->type = $cachedValues['type']; $this->mime = $cachedValues['mime']; $this->metadata = $cachedValues['metadata']; $this->size = $cachedValues['size']; $this->fromSharedDirectory = false; $this->dataLoaded = true; $this->imagePath = $this->getFullPath(); } } if ($this->dataLoaded) { wfIncrStats('image_cache_hit'); } else { wfIncrStats('image_cache_miss'); } wfProfileOut($fname); return $this->dataLoaded; }