/** * Purge the cache for backlinking pages (that is, pages containing * a reference to the Title associated with this task) * * @param string|array $tables */ public function purge($tables) { global $wgUseFileCache, $wgUseSquid; $affectedTitles = $this->getAffectedTitles((array) $tables); $affectedCount = count($affectedTitles); $this->info("Purge Request", ['title' => $this->title->getPrefixedText(), 'count' => $affectedCount, 'tables' => $tables]); // abort if no pages link to the associated Title if ($affectedCount == 0) { return 0; } $dbw = wfGetDB(DB_MASTER); (new \WikiaSQL())->UPDATE('page')->SET('page_touched', $dbw->timestamp())->WHERE('page_id')->IN(array_map(function ($t) { return $t->getArticleID(); }, $affectedTitles))->run($dbw); // Update squid/varnish if ($wgUseSquid) { \SquidUpdate::newFromTitles($affectedTitles)->doUpdate(); } // Update file cache if ($wgUseFileCache) { foreach ($affectedTitles as $title) { \HTMLFileCache::clearFileCache($title); } } return $affectedCount; }
/** * Purge the cache for pages containing gallery tags */ public function purge() { global $wgUseFileCache, $wgUseSquid; $totalGalleryPageCount = 0; // Keeps track of actual existing titles with gallery $dbGalleryCount = $this->getGalleryPageCount(); // All counts including those with missing titles // Paginate the operation to prevent db/memory overload for ($limitCount = 0; $limitCount < $dbGalleryCount; $limitCount += self::PAGE_COUNT_LIMIT) { $galleryPageIds = $this->getGalleryPageIds($limitCount); $galleryPageTitles = \Title::newFromIDs($galleryPageIds); $galleryPageCount = count($galleryPageTitles); // abort if no pages were found if ($galleryPageCount == 0) { continue; } // Update squid/varnish/parser cache if ($wgUseSquid) { foreach ($galleryPageTitles as $title) { $title->purgeSquid(); } } // Update file cache if used if ($wgUseFileCache) { foreach ($galleryPageTitles as $title) { \HTMLFileCache::clearFileCache($title); } } $totalGalleryPageCount += $galleryPageCount; } $this->info('Gallery page purge request', ['title' => __METHOD__, 'count' => $totalGalleryPageCount]); return $totalGalleryPageCount; }
/** * @since 2.1 */ public function doPurgeHtmlCache() { foreach ($this->titles as $title) { $title->touchLinks(); // @see MW 1.19 Title::invalidateCache \HTMLFileCache::clearFileCache($title); } }
/** * Invalidate an array (or iterator) of Title objects, right now * @param $titleArray array */ protected function invalidateTitles($titleArray) { global $wgUseFileCache, $wgUseSquid; $dbw = wfGetDB(DB_MASTER); $timestamp = $dbw->timestamp(); # Get all IDs in this query into an array $ids = array(); foreach ($titleArray as $title) { $ids[] = $title->getArticleID(); } if (!$ids) { return; } # Update page_touched $batches = array_chunk($ids, $this->mRowsPerQuery); foreach ($batches as $batch) { $dbw->update('page', array('page_touched' => $timestamp), array('page_id' => $batch), __METHOD__); } # Update squid if ($wgUseSquid) { $u = SquidUpdate::newFromTitles($titleArray); $u->doUpdate(); } # Update file cache if ($wgUseFileCache) { foreach ($titleArray as $title) { HTMLFileCache::clearFileCache($title); } } }
/** * Check if the page can be cached * @return bool */ public function isFileCacheable() { $cacheable = false; if (HTMLFileCache::useFileCache($this->getContext())) { $cacheable = $this->mPage->getID() && !$this->mRedirectedFrom && !$this->getTitle()->isRedirect(); // Extension may have reason to disable file caching on some pages. if ($cacheable) { $cacheable = Hooks::run('IsFileCacheable', array(&$this)); } } return $cacheable; }
/** * Print the history page for an article. */ function onView() { $out = $this->getOutput(); $request = $this->getRequest(); /** * Allow client caching. */ if ($out->checkLastModified($this->page->getTouched())) { return; // Client cache fresh and headers sent, nothing more to do. } wfProfileIn(__METHOD__); $this->preCacheMessages(); $config = $this->context->getConfig(); # Fill in the file cache if not set already $useFileCache = $config->get('UseFileCache'); if ($useFileCache && HTMLFileCache::useFileCache($this->getContext())) { $cache = HTMLFileCache::newFromTitle($this->getTitle(), 'history'); if (!$cache->isCacheGood()) { ob_start(array(&$cache, 'saveToFileCache')); } } // Setup page variables. $out->setFeedAppendQuery('action=history'); $out->addModules('mediawiki.action.history'); if ($config->get('UseMediaWikiUIEverywhere')) { $out = $this->getOutput(); $out->addModuleStyles(array('mediawiki.ui.input', 'mediawiki.ui.checkbox')); } // Handle atom/RSS feeds. $feedType = $request->getVal('feed'); if ($feedType) { $this->feed($feedType); wfProfileOut(__METHOD__); return; } // Fail nicely if article doesn't exist. if (!$this->page->exists()) { $out->addWikiMsg('nohistory'); # show deletion/move log if there is an entry LogEventsList::showLogExtract($out, array('delete', 'move'), $this->getTitle(), '', array('lim' => 10, 'conds' => array("log_action != 'revision'"), 'showIfEmpty' => false, 'msgKey' => array('moveddeleted-notice'))); wfProfileOut(__METHOD__); return; } /** * Add date selector to quickly get to a certain time */ $year = $request->getInt('year'); $month = $request->getInt('month'); $tagFilter = $request->getVal('tagfilter'); $tagSelector = ChangeTags::buildTagFilterSelector($tagFilter); /** * Option to show only revisions that have been (partially) hidden via RevisionDelete */ if ($request->getBool('deleted')) { $conds = array('rev_deleted != 0'); } else { $conds = array(); } if ($this->getUser()->isAllowed('deletedhistory')) { $checkDeleted = Xml::checkLabel($this->msg('history-show-deleted')->text(), 'deleted', 'mw-show-deleted-only', $request->getBool('deleted')) . "\n"; } else { $checkDeleted = ''; } // Add the general form $action = htmlspecialchars(wfScript()); $out->addHTML("<form action=\"{$action}\" method=\"get\" id=\"mw-history-searchform\">" . Xml::fieldset($this->msg('history-fieldset-title')->text(), false, array('id' => 'mw-history-search')) . Html::hidden('title', $this->getTitle()->getPrefixedDBkey()) . "\n" . Html::hidden('action', 'history') . "\n" . Xml::dateMenu($year == null ? MWTimestamp::getLocalInstance()->format('Y') : $year, $month) . ' ' . ($tagSelector ? implode(' ', $tagSelector) . ' ' : '') . $checkDeleted . Xml::submitButton($this->msg('allpagessubmit')->text()) . "\n" . '</fieldset></form>'); wfRunHooks('PageHistoryBeforeList', array(&$this->page, $this->getContext())); // Create and output the list. $pager = new HistoryPager($this, $year, $month, $tagFilter, $conds); $out->addHTML($pager->getNavigationBar() . $pager->getBody() . $pager->getNavigationBar()); $out->preventClickjacking($pager->getPreventClickjacking()); wfProfileOut(__METHOD__); }
/** * Invalidate an array (or iterator) of Title objects, right now * @param $titleArray array */ protected function invalidateTitles($titleArray) { global $wgUseFileCache, $wgUseSquid; $dbw = wfGetDB(DB_MASTER); $timestamp = $dbw->timestamp(); # Get all IDs in this query into an array $ids = array(); foreach ($titleArray as $title) { $ids[] = $title->getArticleID(); } if (!$ids) { return; } # Don't invalidated pages that were already invalidated $touchedCond = isset($this->params['rootJobTimestamp']) ? array("page_touched < " . $dbw->addQuotes($dbw->timestamp($this->params['rootJobTimestamp']))) : array(); # Update page_touched $batches = array_chunk($ids, $this->rowsPerQuery); foreach ($batches as $batch) { $dbw->update('page', array('page_touched' => $timestamp), array('page_id' => $batch) + $touchedCond, __METHOD__); } # Update squid if ($wgUseSquid) { $u = SquidUpdate::newFromTitles($titleArray); $u->doUpdate(); } # Update file cache if ($wgUseFileCache) { foreach ($titleArray as $title) { HTMLFileCache::clearFileCache($title); } } }
/** * Updates page_touched for this page; called from LinksUpdate.php * * @return Bool true if the update succeded */ public function invalidateCache() { if (wfReadOnly()) { return; } $dbw = wfGetDB(DB_MASTER); $success = $dbw->update('page', array('page_touched' => $dbw->timestamp()), $this->pageCond(), __METHOD__); HTMLFileCache::clearFileCache($this); return $success; }
// Go through each page and save the output while ($blockEnd <= $end) { // Get the pages $res = $dbr->select('page', array('page_namespace', 'page_title', 'page_id'), array('page_namespace' => $wgContentNamespaces, "page_id BETWEEN {$blockStart} AND {$blockEnd}"), array('ORDER BY' => 'page_id ASC', 'USE INDEX' => 'PRIMARY')); while ($row = $dbr->fetchObject($res)) { $rebuilt = false; $wgTitle = Title::makeTitleSafe($row->page_namespace, $row->page_title); if (null == $wgTitle) { echo "Page {$row->page_id} bad title\n"; continue; // broken title? } $wgArticle = new Article($wgTitle); // If the article is cacheable, then load it if ($wgArticle->isFileCacheable()) { $cache = new HTMLFileCache($wgTitle); if ($cache->isFileCacheGood()) { if ($overwrite) { $rebuilt = true; } else { echo "Page {$row->page_id} already cached\n"; continue; // done already! } } ob_start(array(&$cache, 'saveToFileCache')); // save on ob_end_clean() $wgUseFileCache = false; // hack, we don't want $wgArticle fiddling with filecache $wgArticle->view(); @$wgOut->output();
public function execute() { global $wgUseFileCache, $wgReadOnly, $wgContentNamespaces, $wgRequestTime; global $wgOut; if (!$wgUseFileCache) { $this->error("Nothing to do -- \$wgUseFileCache is disabled.", true); } $wgReadOnly = 'Building cache'; // avoid DB writes (like enotif/counters) $start = $this->getOption('start', "0"); if (!ctype_digit($start)) { $this->error("Invalid value for start parameter.", true); } $start = intval($start); $end = $this->getOption('end', "0"); if (!ctype_digit($end)) { $this->error("Invalid value for end parameter.", true); } $end = intval($end); $this->output("Building content page file cache from page {$start}!\n"); $dbr = $this->getDB(DB_SLAVE); $overwrite = $this->getOption('overwrite', false); $start = $start > 0 ? $start : $dbr->selectField('page', 'MIN(page_id)', false, __FUNCTION__); $end = $end > 0 ? $end : $dbr->selectField('page', 'MAX(page_id)', false, __FUNCTION__); if (!$start) { $this->error("Nothing to do.", true); } $_SERVER['HTTP_ACCEPT_ENCODING'] = 'bgzip'; // hack, no real client # Do remaining chunk $end += $this->mBatchSize - 1; $blockStart = $start; $blockEnd = $start + $this->mBatchSize - 1; $dbw = $this->getDB(DB_MASTER); // Go through each page and save the output while ($blockEnd <= $end) { // Get the pages $res = $dbr->select('page', array('page_namespace', 'page_title', 'page_id'), array('page_namespace' => $wgContentNamespaces, "page_id BETWEEN {$blockStart} AND {$blockEnd}"), array('ORDER BY' => 'page_id ASC', 'USE INDEX' => 'PRIMARY')); $this->beginTransaction($dbw, __METHOD__); // for any changes foreach ($res as $row) { $rebuilt = false; $wgRequestTime = microtime(true); # bug 22852 $title = Title::makeTitleSafe($row->page_namespace, $row->page_title); if (null == $title) { $this->output("Page {$row->page_id} has bad title\n"); continue; // broken title? } $context = new RequestContext(); $context->setTitle($title); $article = Article::newFromTitle($title, $context); $context->setWikiPage($article->getPage()); $wgOut = $context->getOutput(); // set display title // If the article is cacheable, then load it if ($article->isFileCacheable()) { $cache = HTMLFileCache::newFromTitle($title, 'view'); if ($cache->isCacheGood()) { if ($overwrite) { $rebuilt = true; } else { $this->output("Page {$row->page_id} already cached\n"); continue; // done already! } } ob_start(array(&$cache, 'saveToFileCache')); // save on ob_end_clean() $wgUseFileCache = false; // hack, we don't want $article fiddling with filecache $article->view(); MediaWiki\suppressWarnings(); // header notices $wgOut->output(); MediaWiki\restoreWarnings(); $wgUseFileCache = true; ob_end_clean(); // clear buffer if ($rebuilt) { $this->output("Re-cached page {$row->page_id}\n"); } else { $this->output("Cached page {$row->page_id}\n"); } } else { $this->output("Page {$row->page_id} not cacheable\n"); } } $this->commitTransaction($dbw, __METHOD__); // commit any changes (just for sanity) $blockStart += $this->mBatchSize; $blockEnd += $this->mBatchSize; } $this->output("Done!\n"); }
function view() { global $wgOut, $wgScript; if (isset($_SERVER['SCRIPT_URL'])) { # Normally we use PHP_SELF to get the URL to the script # as it was called, minus the query string. # # Some sites use Apache rewrite rules to handle subdomains, # and have PHP set up in a weird way that causes PHP_SELF # to contain the rewritten URL instead of the one that the # outside world sees. # # If in this mode, use SCRIPT_URL instead, which mod_rewrite # provides containing the "before" URL. $url = $_SERVER['SCRIPT_URL']; } else { $url = $_SERVER['PHP_SELF']; } if (strcmp($wgScript, $url)) { # Internet Explorer will ignore the Content-Type header if it # thinks it sees a file extension it recognizes. Make sure that # all raw requests are done through the script node, which will # have eg '.php' and should remain safe. # # We used to redirect to a canonical-form URL as a general # backwards-compatibility / good-citizen nice thing. However # a lot of servers are set up in buggy ways, resulting in # redirect loops which hang the browser until the CSS load # times out. # # Just return a 403 Forbidden and get it over with. wfHttpError(403, 'Forbidden', 'Raw pages must be accessed through the primary script entry point.'); return; } header("Content-type: " . $this->mContentType . '; charset=' . $this->mCharset); # allow the client to cache this for 24 hours $mode = $this->mPrivateCache ? 'private' : 'public'; header('Cache-Control: ' . $mode . ', s-maxage=' . $this->mSmaxage . ', max-age=' . $this->mMaxage); if (HTMLFileCache::useFileCache()) { $cache = new HTMLFileCache($this->mTitle, 'raw'); if ($cache->isFileCacheGood()) { $cache->loadFromFileCache(); $wgOut->disable(); return; } else { ob_start(array(&$cache, 'saveToFileCache')); } } $text = $this->getRawText(); if (!wfRunHooks('RawPageViewBeforeOutput', array(&$this, &$text))) { wfDebug(__METHOD__ . ': RawPageViewBeforeOutput hook broke raw page output.'); } echo $text; $wgOut->disable(); }
function view() { global $wgOut, $wgScript, $wgRequest; if ($wgRequest->isPathInfoBad()) { # Internet Explorer will ignore the Content-Type header if it # thinks it sees a file extension it recognizes. Make sure that # all raw requests are done through the script node, which will # have eg '.php' and should remain safe. # # We used to redirect to a canonical-form URL as a general # backwards-compatibility / good-citizen nice thing. However # a lot of servers are set up in buggy ways, resulting in # redirect loops which hang the browser until the CSS load # times out. # # Just return a 403 Forbidden and get it over with. wfHttpError(403, 'Forbidden', 'Invalid file extension found in PATH_INFO or QUERY_STRING. ' . 'Raw pages must be accessed through the primary script entry point.'); return; } header("Content-type: " . $this->mContentType . '; charset=' . $this->mCharset); # allow the client to cache this for 24 hours $mode = $this->mPrivateCache ? 'private' : 'public'; header('Cache-Control: ' . $mode . ', s-maxage=' . $this->mSmaxage . ', max-age=' . $this->mMaxage); global $wgUseFileCache; if ($wgUseFileCache and HTMLFileCache::useFileCache()) { $cache = new HTMLFileCache($this->mTitle, 'raw'); if ($cache->isFileCacheGood()) { $cache->loadFromFileCache(); $wgOut->disable(); return; } else { ob_start(array(&$cache, 'saveToFileCache')); } } $text = $this->getRawText(); if (!wfRunHooks('RawPageViewBeforeOutput', array(&$this, &$text))) { wfDebug(__METHOD__ . ": RawPageViewBeforeOutput hook broke raw page output.\n"); } echo $text; $wgOut->disable(); }
function getHTML() { global $wgTitle, $wgUseFileCache, $title, $wgInputEncoding; global $wgSitename, $wgServer, $wgMessageCache; # I give up, Brion is right. Getting the message cache to work when there is no DB is tricky. # Hard coding strings instead. $noconnect = '<style type="text/css" media="screen,projection">/*<![CDATA[*/ @import "/skins/WikiHow/main.css"; /*]]>*/</style>' . "<p style='padding-left:80px;'><strong>Sorry! This site is under going routine maintenance. </strong><br/>\n\t\t\t\t<br/><br/>\n\t\t\tThe maintenance will problem will likely be completed shortly, try waiting a few minutes and refreshing the page. <br/><br/>\n\t\t\t<b>Thanks for your patience.</b><br/><br/>\n\t\t\tIn the meantime, you can try accessing <a href='http://72.14.209.104/search?q=cache:" . $_SERVER['SCRIPT_URI'] . "'>Google's cached copy of this page</a>.\n\t\t\t<!-- (Can't contact the database server: \$1) -->\n\t\t\t</p>"; $mainpage = 'Main Page'; $searchdisabled = <<<EOT <p style="margin: 1.5em 2em 1em">{$wgSitename} search is disabled for performance reasons. You can search via Google in the meantime. <span style="font-size: 89%; display: block; margin-left: .2em">Note that their indexes of {$wgSitename} content may be out of date.</span></p>', EOT; $googlesearch = "\n<!-- SiteSearch Google -->\n<FORM method=GET action=\"http://www.google.com/search\">\n<TABLE bgcolor=\"#FFFFFF\"><tr><td>\n<A HREF=\"http://www.google.com/\">\n<IMG SRC=\"http://www.google.com/logos/Logo_40wht.gif\"\nborder=\"0\" ALT=\"Google\"></A>\n</td>\n<td>\n<INPUT TYPE=text name=q size=31 maxlength=255 value=\"\$1\">\n<INPUT type=submit name=btnG VALUE=\"Google Search\">\n<font size=-1>\n<input type=hidden name=domains value=\"{$wgServer}\"><br /><input type=radio name=sitesearch value=\"\"> WWW <input type=radio name=sitesearch value=\"{$wgServer}\" checked> {$wgServer} <br />\n<input type='hidden' name='ie' value='\$2'>\n<input type='hidden' name='oe' value='\$2'>\n</font>\n</td></tr></TABLE>\n</FORM>\n<!-- SiteSearch Google -->"; $cachederror = "The following is a cached copy of the requested page, and may not be up to date. "; # No database access if (is_object($wgMessageCache)) { $wgMessageCache->disable(); } if (trim($this->error) == '') { $this->error = $this->db->getProperty('mServer'); } $text = str_replace('$1', $this->error, $noconnect); // $text .= wfGetSiteNotice(); if ($wgUseFileCache) { if ($wgTitle) { $t =& $wgTitle; } else { if ($title) { $t = Title::newFromURL($title); } elseif (@$_REQUEST['search']) { $search = $_REQUEST['search']; return $searchdisabled . str_replace(array('$1', '$2'), array(htmlspecialchars($search), $wgInputEncoding), $googlesearch); } else { $t = Title::newFromText($mainpage); } } $cache = new HTMLFileCache($t); if ($cache->isFileCached()) { // @todo, FIXME: $msg is not defined on the next line. $msg = '<p style="color: red"><b>' . $msg . "<br />\n" . $cachederror . "</b></p>\n"; $tag = '<div id="article">'; $text = str_replace($tag, $tag . $msg, $cache->fetchPageText()); } } return $text; }
function fileCachedPage() { global $wgTitle, $wgLang, $wgOut; if ($wgOut->isDisabled()) { return; // Done already? } $mainpage = 'Main Page'; if ($wgLang instanceof Language) { $mainpage = htmlspecialchars($wgLang->getMessage('mainpage')); } if ($wgTitle) { $t =& $wgTitle; } else { $t = Title::newFromText($mainpage); } $cache = new HTMLFileCache($t); if ($cache->isFileCached()) { return $cache->fetchPageText(); } else { return ''; } }
function getHTML() { global $wgTitle, $wgUseFileCache, $title, $wgInputEncoding; global $wgSitename, $wgServer, $wgMessageCache; # I give up, Brion is right. Getting the message cache to work when there is no DB is tricky. # Hard coding strings instead. $noconnect = "<p><strong>Sorry! This site is experiencing technical difficulties.</strong></p><p>Try waiting a few minutes and reloading.</p><p><small>(Can't contact the database server: \$1)</small></p>"; $mainpage = 'Main Page'; $searchdisabled = <<<EOT <p style="margin: 1.5em 2em 1em">{$wgSitename} search is disabled for performance reasons. You can search via Google in the meantime. <span style="font-size: 89%; display: block; margin-left: .2em">Note that their indexes of {$wgSitename} content may be out of date.</span></p>', EOT; $googlesearch = "\n<!-- SiteSearch Google -->\n<FORM method=GET action=\"http://www.google.com/search\">\n<TABLE bgcolor=\"#FFFFFF\"><tr><td>\n<A HREF=\"http://www.google.com/\">\n<IMG SRC=\"http://www.google.com/logos/Logo_40wht.gif\"\nborder=\"0\" ALT=\"Google\"></A>\n</td>\n<td>\n<INPUT TYPE=text name=q size=31 maxlength=255 value=\"\$1\">\n<INPUT type=submit name=btnG VALUE=\"Google Search\">\n<font size=-1>\n<input type=hidden name=domains value=\"{$wgServer}\"><br /><input type=radio name=sitesearch value=\"\"> WWW <input type=radio name=sitesearch value=\"{$wgServer}\" checked> {$wgServer} <br />\n<input type='hidden' name='ie' value='\$2'>\n<input type='hidden' name='oe' value='\$2'>\n</font>\n</td></tr></TABLE>\n</FORM>\n<!-- SiteSearch Google -->"; $cachederror = "The following is a cached copy of the requested page, and may not be up to date. "; # No database access if (is_object($wgMessageCache)) { $wgMessageCache->disable(); } if (trim($this->error) == '') { $this->error = $this->db->getProperty('mServer'); } $text = str_replace('$1', $this->error, $noconnect); $text .= wfGetSiteNotice(); if ($wgUseFileCache) { if ($wgTitle) { $t =& $wgTitle; } else { if ($title) { $t = Title::newFromURL($title); } elseif (@$_REQUEST['search']) { $search = $_REQUEST['search']; return $searchdisabled . str_replace(array('$1', '$2'), array(htmlspecialchars($search), $wgInputEncoding), $googlesearch); } else { $t = Title::newFromText($mainpage); } } $cache = new HTMLFileCache($t); if ($cache->isFileCached()) { // @todo, FIXME: $msg is not defined on the next line. $msg = '<p style="color: red"><b>' . $msg . "<br />\n" . $cachederror . "</b></p>\n"; $tag = '<div id="article">'; $text = str_replace($tag, $tag . $msg, $cache->fetchPageText()); } } return $text; }
/** * Invalidate a set of IDs, right now */ function invalidateIDs(ResultWrapper $res) { global $wgUseFileCache, $wgUseSquid; if ($res->numRows() == 0) { return; } $dbw = wfGetDB(DB_MASTER); $timestamp = $dbw->timestamp(); $done = false; while (!$done) { # Get all IDs in this query into an array $ids = array(); for ($i = 0; $i < $this->mRowsPerQuery; $i++) { $row = $res->fetchRow(); if ($row) { $ids[] = $row[0]; } else { $done = true; break; } } if (!count($ids)) { break; } # Update page_touched $dbw->update('page', array('page_touched' => $timestamp), array('page_id IN (' . $dbw->makeList($ids) . ')'), __METHOD__); # Update squid if ($wgUseSquid || $wgUseFileCache) { $titles = Title::newFromIDs($ids); if ($wgUseSquid) { $u = SquidUpdate::newFromTitles($titles); $u->doUpdate(); } # Update file cache if ($wgUseFileCache) { foreach ($titles as $title) { $cm = new HTMLFileCache($title); @unlink($cm->fileCacheName()); } } } } }
private function main() { global $wgTitle; $output = $this->context->getOutput(); $request = $this->context->getRequest(); // Send Ajax requests to the Ajax dispatcher. if ($this->config->get('UseAjax') && $request->getVal('action') === 'ajax') { // Set a dummy title, because $wgTitle == null might break things $title = Title::makeTitle(NS_SPECIAL, 'Badtitle/performing an AJAX call in ' . __METHOD__); $this->context->setTitle($title); $wgTitle = $title; $dispatcher = new AjaxDispatcher($this->config); $dispatcher->performAction($this->context->getUser()); return; } // Get title from request parameters, // is set on the fly by parseTitle the first time. $title = $this->getTitle(); $action = $this->getAction(); $wgTitle = $title; // Set DB query expectations for this HTTP request $trxLimits = $this->config->get('TrxProfilerLimits'); $trxProfiler = Profiler::instance()->getTransactionProfiler(); $trxProfiler->setLogger(LoggerFactory::getInstance('DBPerformance')); if ($request->hasSafeMethod()) { $trxProfiler->setExpectations($trxLimits['GET'], __METHOD__); } else { $trxProfiler->setExpectations($trxLimits['POST'], __METHOD__); } // If the user has forceHTTPS set to true, or if the user // is in a group requiring HTTPS, or if they have the HTTPS // preference set, redirect them to HTTPS. // Note: Do this after $wgTitle is setup, otherwise the hooks run from // isLoggedIn() will do all sorts of weird stuff. if ($request->getProtocol() == 'http' && preg_match('#^https://#', wfExpandUrl($request->getRequestURL(), PROTO_HTTPS)) && ($request->getSession()->shouldForceHTTPS() || $request->getCookie('forceHTTPS', '') || $request->getCookie('forceHTTPS') || $this->context->getUser()->isLoggedIn() && $this->context->getUser()->requiresHTTPS())) { $oldUrl = $request->getFullRequestURL(); $redirUrl = preg_replace('#^http://#', 'https://', $oldUrl); // ATTENTION: This hook is likely to be removed soon due to overall design of the system. if (Hooks::run('BeforeHttpsRedirect', [$this->context, &$redirUrl])) { if ($request->wasPosted()) { // This is weird and we'd hope it almost never happens. This // means that a POST came in via HTTP and policy requires us // redirecting to HTTPS. It's likely such a request is going // to fail due to post data being lost, but let's try anyway // and just log the instance. // @todo FIXME: See if we could issue a 307 or 308 here, need // to see how clients (automated & browser) behave when we do wfDebugLog('RedirectedPosts', "Redirected from HTTP to HTTPS: {$oldUrl}"); } // Setup dummy Title, otherwise OutputPage::redirect will fail $title = Title::newFromText('REDIR', NS_MAIN); $this->context->setTitle($title); // Since we only do this redir to change proto, always send a vary header $output->addVaryHeader('X-Forwarded-Proto'); $output->redirect($redirUrl); $output->output(); return; } } if ($title->canExist() && HTMLFileCache::useFileCache($this->context)) { // Try low-level file cache hit $cache = new HTMLFileCache($title, $action); if ($cache->isCacheGood()) { // Check incoming headers to see if client has this cached $timestamp = $cache->cacheTimestamp(); if (!$output->checkLastModified($timestamp)) { $cache->loadFromFileCache($this->context); } // Do any stats increment/watchlist stuff, assuming user is viewing the // latest revision (which should always be the case for file cache) $this->context->getWikiPage()->doViewUpdates($this->context->getUser()); // Tell OutputPage that output is taken care of $output->disable(); return; } } // Actually do the work of the request and build up any output $this->performRequest(); // GUI-ify and stash the page output in MediaWiki::doPreOutputCommit() while // ChronologyProtector synchronizes DB positions or slaves accross all datacenters. $buffer = null; $outputWork = function () use($output, &$buffer) { if ($buffer === null) { $buffer = $output->output(true); } return $buffer; }; // Now commit any transactions, so that unreported errors after // output() don't roll back the whole DB transaction and so that // we avoid having both success and error text in the response $this->doPreOutputCommit($outputWork); // Now send the actual output print $outputWork(); }
/** * Update the semantic data stored for some individual. The data is * given as a SMWSemanticData object, which contains all semantic data * for one particular subject. * * @param $data SMWSemanticData */ public function updateData(SMWSemanticData $data) { /** * @since 1.6 */ wfRunHooks('SMWStore::updateDataBefore', array($this, $data)); // Invalidate the page, so data stored on it gets displayed immediately in queries. global $smwgAutoRefreshSubject; if ($smwgAutoRefreshSubject && !wfReadOnly()) { $title = Title::makeTitle($data->getSubject()->getNamespace(), $data->getSubject()->getDBkey()); $dbw = wfGetDB(DB_MASTER); $dbw->update('page', array('page_touched' => $dbw->timestamp(time() + 4)), $title->pageCond(), __METHOD__); HTMLFileCache::clearFileCache($title); } $this->doDataUpdate($data); /** * @since 1.6 */ wfRunHooks('SMWStore::updateDataAfter', array($this, $data)); }
/** * @return string */ private function fileCachedPage() { $context = RequestContext::getMain(); if ($context->getOutput()->isDisabled()) { // Done already? return ''; } if ($context->getTitle()) { // Use the main context's title if we managed to set it $t = $context->getTitle()->getPrefixedDBkey(); } else { // Fallback to the raw title URL param. We can't use the Title // class is it may hit the interwiki table and give a DB error. // We may get a cache miss due to not sanitizing the title though. $t = str_replace(' ', '_', $context->getRequest()->getVal('title')); if ($t == '') { // fallback to main page $t = Title::newFromText($this->msg('mainpage', 'Main Page'))->getPrefixedDBkey(); } } $cache = new HTMLFileCache($t, 'view'); if ($cache->isCached()) { return $cache->fetchText(); } else { return ''; } }
# Send Ajax requests to the Ajax dispatcher. # if ($wgUseAjax && $action == 'ajax') { require_once $IP . '/includes/AjaxDispatcher.php'; $dispatcher = new AjaxDispatcher(); $dispatcher->performAction(); $mediaWiki->restInPeace(); exit; } if ($wgUseFileCache && isset($wgTitle)) { wfProfileIn('main-try-filecache'); // Raw pages should handle cache control on their own, // even when using file cache. This reduces hits from clients. if ($action != 'raw' && HTMLFileCache::useFileCache()) { /* Try low-level file cache hit */ $cache = new HTMLFileCache($wgTitle, $action); if ($cache->isFileCacheGood()) { /* Check incoming headers to see if client has this cached */ if (!$wgOut->checkLastModified($cache->fileCacheTime())) { $cache->loadFromFileCache(); } # Do any stats increment/watchlist stuff $wgArticle = MediaWiki::articleFromTitle($wgTitle); $wgArticle->viewUpdates(); # Tell $wgOut that output is taken care of wfProfileOut('main-try-filecache'); $mediaWiki->restInPeace(); exit; } } wfProfileOut('main-try-filecache');
/** * Purge caches on page update etc * * @param $title Title object * @todo: verify that $title is always a Title object (and never false or null), add Title hint to parameter $title */ public static function onArticleEdit($title) { global $wgDeferredUpdateList; // Invalidate caches of articles which include this page $wgDeferredUpdateList[] = new HTMLCacheUpdate($title, 'templatelinks'); // Invalidate the caches of all pages which redirect here $wgDeferredUpdateList[] = new HTMLCacheUpdate($title, 'redirect'); # Purge squid for this page only $title->purgeSquid(); # Clear file cache for this page only HTMLFileCache::clearFileCache($title); }
/** * Updates page_touched for this page; called from LinksUpdate.php * * @return Bool true if the update succeded */ public function invalidateCache() { if (wfReadOnly()) { return false; } $dbw = wfGetDB(DB_MASTER); $success = $dbw->update('page', array('page_touched' => $dbw->timestamp()), $this->pageCond(), __METHOD__); # start wikia change global $wgMemc; $wgMemc->set(wfMemcKey("page_touched", implode("_", $this->pageCond())), $dbw->timestamp(), 60); $this->mTouchedCached = null; # end wikia change HTMLFileCache::clearFileCache($this); return $success; }
/** * Updates page_touched for this page; called from LinksUpdate.php * @return bool true if the update succeded */ public function invalidateCache() { global $wgUseFileCache; if (wfReadOnly()) { return; } $dbw = wfGetDB(DB_MASTER); $success = $dbw->update('page', array('page_touched' => $dbw->timestamp()), array('page_namespace' => $this->getNamespace(), 'page_title' => $this->getDBkey()), 'Title::invalidateCache'); if ($wgUseFileCache) { $cache = new HTMLFileCache($this); @unlink($cache->fileCacheName()); } return $success; }
/** * Purge caches on page update etc */ static function onArticleEdit($title) { global $wgDeferredUpdateList, $wgUseFileCache; // Invalidate caches of articles which include this page $update = new HTMLCacheUpdate($title, 'templatelinks'); $wgDeferredUpdateList[] = $update; # Purge squid for this page only $title->purgeSquid(); # Clear file cache if ($wgUseFileCache) { $cm = new HTMLFileCache($title); @unlink($cm->fileCacheName()); } }
/** * Purge caches on page update etc * * @param Title $title * @param Revision|null $revision Revision that was just saved, may be null */ public static function onArticleEdit(Title $title, Revision $revision = null) { // Invalidate caches of articles which include this page DeferredUpdates::addUpdate(new HTMLCacheUpdate($title, 'templatelinks')); // Invalidate the caches of all pages which redirect here DeferredUpdates::addUpdate(new HTMLCacheUpdate($title, 'redirect')); MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle($title); // Purge CDN for this page only $title->purgeSquid(); // Clear file cache for this page only HTMLFileCache::clearFileCache($title); $revid = $revision ? $revision->getId() : null; DeferredUpdates::addCallableUpdate(function () use($title, $revid) { InfoAction::invalidateCache($title, $revid); }); }
/** * @param array $pages Map of (page ID => (namespace, DB key)) entries */ protected function invalidateTitles(array $pages) { global $wgUpdateRowsPerQuery, $wgUseFileCache; // Get all page IDs in this query into an array $pageIds = array_keys($pages); if (!$pageIds) { return; } // The page_touched field will need to be bumped for these pages. // Only bump it to the present time if no "rootJobTimestamp" was known. // If it is known, it can be used instead, which avoids invalidating output // that was in fact generated *after* the relevant dependency change time // (e.g. template edit). This is particularily useful since refreshLinks jobs // save back parser output and usually run along side htmlCacheUpdate jobs; // their saved output would be invalidated by using the current timestamp. if (isset($this->params['rootJobTimestamp'])) { $touchTimestamp = $this->params['rootJobTimestamp']; } else { $touchTimestamp = wfTimestampNow(); } $dbw = wfGetDB(DB_MASTER); // Update page_touched (skipping pages already touched since the root job). // Check $wgUpdateRowsPerQuery for sanity; batch jobs are sized by that already. foreach (array_chunk($pageIds, $wgUpdateRowsPerQuery) as $batch) { $dbw->commit(__METHOD__, 'flush'); wfWaitForSlaves(); $dbw->update('page', array('page_touched' => $dbw->timestamp($touchTimestamp)), array('page_id' => $batch, "page_touched < " . $dbw->addQuotes($dbw->timestamp($touchTimestamp))), __METHOD__); } // Get the list of affected pages (races only mean something else did the purge) $titleArray = TitleArray::newFromResult($dbw->select('page', array('page_namespace', 'page_title'), array('page_id' => $pageIds, 'page_touched' => $dbw->timestamp($touchTimestamp)), __METHOD__)); // Update squid $u = SquidUpdate::newFromTitles($titleArray); $u->doUpdate(); // Update file cache if ($wgUseFileCache) { foreach ($titleArray as $title) { HTMLFileCache::clearFileCache($title); } } }
private function main() { global $wgUseFileCache, $wgTitle, $wgUseAjax; wfProfileIn(__METHOD__); $request = $this->context->getRequest(); if ($request->getCookie('forceHTTPS') && $request->detectProtocol() == 'http' && $request->getMethod() == 'GET') { $redirUrl = $request->getFullRequestURL(); $redirUrl = str_replace('http://', 'https://', $redirUrl); // Setup dummy Title, otherwise OutputPage::redirect will fail $title = Title::newFromText(NS_MAIN, 'REDIR'); $this->context->setTitle($title); $output = $this->context->getOutput(); $output->redirect($redirUrl); $output->output(); wfProfileOut(__METHOD__); return; } // Send Ajax requests to the Ajax dispatcher. if ($wgUseAjax && $request->getVal('action', 'view') == 'ajax') { // Set a dummy title, because $wgTitle == null might break things $title = Title::makeTitle(NS_MAIN, 'AJAX'); $this->context->setTitle($title); $wgTitle = $title; $dispatcher = new AjaxDispatcher(); $dispatcher->performAction(); wfProfileOut(__METHOD__); return; } // Get title from request parameters, // is set on the fly by parseTitle the first time. $title = $this->getTitle(); $action = $this->getAction(); $wgTitle = $title; if ($wgUseFileCache && $title->getNamespace() >= 0) { wfProfileIn('main-try-filecache'); if (HTMLFileCache::useFileCache($this->context)) { // Try low-level file cache hit $cache = HTMLFileCache::newFromTitle($title, $action); if ($cache->isCacheGood()) { // Check incoming headers to see if client has this cached $timestamp = $cache->cacheTimestamp(); if (!$this->context->getOutput()->checkLastModified($timestamp)) { $cache->loadFromFileCache($this->context); } // Do any stats increment/watchlist stuff $this->context->getWikiPage()->doViewUpdates($this->context->getUser()); // Tell OutputPage that output is taken care of $this->context->getOutput()->disable(); wfProfileOut('main-try-filecache'); wfProfileOut(__METHOD__); return; } } wfProfileOut('main-try-filecache'); } $this->performRequest(); // Now commit any transactions, so that unreported errors after // output() don't roll back the whole DB transaction wfGetLBFactory()->commitMasterChanges(); // Output everything! $this->context->getOutput()->output(); wfProfileOut(__METHOD__); }
public function execute() { global $wgUseFileCache, $wgDisableCounters, $wgContentNamespaces, $wgRequestTime; global $wgTitle, $wgArticle, $wgOut, $wgUser; if (!$wgUseFileCache) { $this->error("Nothing to do -- \$wgUseFileCache is disabled.", true); } $wgDisableCounters = false; $start = $this->getArg(0, "0"); if (!ctype_digit($start)) { $this->error("Invalid value for start parameter.", true); } $start = intval($start); $overwrite = $this->hasArg(1) && $this->getArg(1) === 'overwrite'; $this->output("Building content page file cache from page {$start}!\n"); $dbr = wfGetDB(DB_SLAVE); $start = $start > 0 ? $start : $dbr->selectField('page', 'MIN(page_id)', false, __FUNCTION__); $end = $dbr->selectField('page', 'MAX(page_id)', false, __FUNCTION__); if (!$start) { $this->error("Nothing to do.", true); } $_SERVER['HTTP_ACCEPT_ENCODING'] = 'bgzip'; // hack, no real client OutputPage::setEncodings(); # Not really used yet # Do remaining chunk $end += $this->mBatchSize - 1; $blockStart = $start; $blockEnd = $start + $this->mBatchSize - 1; $dbw = wfGetDB(DB_MASTER); // Go through each page and save the output while ($blockEnd <= $end) { // Get the pages $res = $dbr->select('page', array('page_namespace', 'page_title', 'page_id'), array('page_namespace' => $wgContentNamespaces, "page_id BETWEEN {$blockStart} AND {$blockEnd}"), array('ORDER BY' => 'page_id ASC', 'USE INDEX' => 'PRIMARY')); foreach ($res as $row) { $rebuilt = false; $wgRequestTime = wfTime(); # bug 22852 $wgTitle = Title::makeTitleSafe($row->page_namespace, $row->page_title); if (null == $wgTitle) { $this->output("Page {$row->page_id} has bad title\n"); continue; // broken title? } $wgOut->setTitle($wgTitle); // set display title $wgUser->getSkin($wgTitle); // set skin title $wgArticle = new Article($wgTitle); // If the article is cacheable, then load it if ($wgArticle->isFileCacheable()) { $cache = new HTMLFileCache($wgTitle); if ($cache->isFileCacheGood()) { if ($overwrite) { $rebuilt = true; } else { $this->output("Page {$row->page_id} already cached\n"); continue; // done already! } } ob_start(array(&$cache, 'saveToFileCache')); // save on ob_end_clean() $wgUseFileCache = false; // hack, we don't want $wgArticle fiddling with filecache $wgArticle->view(); @$wgOut->output(); // header notices $wgUseFileCache = true; ob_end_clean(); // clear buffer $wgOut = new OutputPage(); // empty out any output page garbage if ($rebuilt) { $this->output("Re-cached page {$row->page_id}\n"); } else { $this->output("Cached page {$row->page_id}\n"); } } else { $this->output("Page {$row->page_id} not cacheable\n"); } $dbw->commit(); // commit any changes } $blockStart += $this->mBatchSize; $blockEnd += $this->mBatchSize; wfWaitForSlaves(5); } $this->output("Done!\n"); // Remove these to be safe if (isset($wgTitle)) { unset($wgTitle); } if (isset($wgArticle)) { unset($wgArticle); } }
/** * Purge caches on page update etc * * @param $title Title object * @todo Verify that $title is always a Title object (and never false or null), add Title hint to parameter $title */ public static function onArticleEdit( $title ) { // Invalidate caches of articles which include this page DeferredUpdates::addHTMLCacheUpdate( $title, 'templatelinks' ); // Invalidate the caches of all pages which redirect here DeferredUpdates::addHTMLCacheUpdate( $title, 'redirect' ); // Purge squid for this page only $title->purgeSquid(); // Clear file cache for this page only HTMLFileCache::clearFileCache( $title ); InfoAction::invalidateCache( $title ); }
private function main() { global $wgUseFileCache, $wgTitle, $wgUseAjax; wfProfileIn(__METHOD__); $request = $this->context->getRequest(); // Send Ajax requests to the Ajax dispatcher. if ($wgUseAjax && $request->getVal('action', 'view') == 'ajax') { // Set a dummy title, because $wgTitle == null might break things $title = Title::makeTitle(NS_MAIN, 'AJAX'); $this->context->setTitle($title); $wgTitle = $title; $dispatcher = new AjaxDispatcher(); $dispatcher->performAction(); wfProfileOut(__METHOD__); return; } // Get title from request parameters, // is set on the fly by parseTitle the first time. $title = $this->getTitle(); $action = $this->getAction(); $wgTitle = $title; // If the user has forceHTTPS set to true, or if the user // is in a group requiring HTTPS, or if they have the HTTPS // preference set, redirect them to HTTPS. // Note: Do this after $wgTitle is setup, otherwise the hooks run from // isLoggedIn() will do all sorts of weird stuff. if (($request->getCookie('forceHTTPS', '') || $request->getCookie('forceHTTPS') || $this->context->getUser()->isLoggedIn() && $this->context->getUser()->requiresHTTPS()) && $request->getProtocol() == 'http') { $oldUrl = $request->getFullRequestURL(); $redirUrl = str_replace('http://', 'https://', $oldUrl); if ($request->wasPosted()) { // This is weird and we'd hope it almost never happens. This // means that a POST came in via HTTP and policy requires us // redirecting to HTTPS. It's likely such a request is going // to fail due to post data being lost, but let's try anyway // and just log the instance. // // @todo @fixme See if we could issue a 307 or 308 here, need // to see how clients (automated & browser) behave when we do wfDebugLog('RedirectedPosts', "Redirected from HTTP to HTTPS: {$oldUrl}"); } // Setup dummy Title, otherwise OutputPage::redirect will fail $title = Title::newFromText(NS_MAIN, 'REDIR'); $this->context->setTitle($title); $output = $this->context->getOutput(); // Since we only do this redir to change proto, always send a vary header $output->addVaryHeader('X-Forwarded-Proto'); $output->redirect($redirUrl); $output->output(); wfProfileOut(__METHOD__); return; } if ($wgUseFileCache && $title->getNamespace() >= 0) { wfProfileIn('main-try-filecache'); if (HTMLFileCache::useFileCache($this->context)) { // Try low-level file cache hit $cache = HTMLFileCache::newFromTitle($title, $action); if ($cache->isCacheGood()) { // Check incoming headers to see if client has this cached $timestamp = $cache->cacheTimestamp(); if (!$this->context->getOutput()->checkLastModified($timestamp)) { $cache->loadFromFileCache($this->context); } // Do any stats increment/watchlist stuff // Assume we're viewing the latest revision (this should always be the case with file cache) $this->context->getWikiPage()->doViewUpdates($this->context->getUser()); // Tell OutputPage that output is taken care of $this->context->getOutput()->disable(); wfProfileOut('main-try-filecache'); wfProfileOut(__METHOD__); return; } } wfProfileOut('main-try-filecache'); } // Actually do the work of the request and build up any output $this->performRequest(); // Either all DB and deferred updates should happen or none. // The later should not be cancelled due to client disconnect. ignore_user_abort(true); // Now commit any transactions, so that unreported errors after // output() don't roll back the whole DB transaction wfGetLBFactory()->commitMasterChanges(); // Output everything! $this->context->getOutput()->output(); wfProfileOut(__METHOD__); }