MediaWiki  master
HTMLFileCache.php
Go to the documentation of this file.
1 <?php
28 
37  public const MODE_NORMAL = 0; // normal cache mode
38  public const MODE_OUTAGE = 1; // fallback cache for DB outages
39  public const MODE_REBUILD = 2; // background cache rebuild mode
40 
47  public function __construct( $page, $action ) {
48  parent::__construct();
49 
50  if ( !in_array( $action, self::cacheablePageActions() ) ) {
51  throw new InvalidArgumentException( 'Invalid file cache type given.' );
52  }
53 
54  $this->mKey = CacheKeyHelper::getKeyForPage( $page );
55  $this->mType = (string)$action;
56  $this->mExt = 'html';
57  }
58 
63  protected static function cacheablePageActions() {
64  return [ 'view', 'history' ];
65  }
66 
71  protected function cacheDirectory() {
72  return $this->baseCacheDirectory(); // no subdir for b/c with old cache files
73  }
74 
81  protected function typeSubdirectory() {
82  if ( $this->mType === 'view' ) {
83  return ''; // b/c to not skip existing cache
84  } else {
85  return $this->mType . '/';
86  }
87  }
88 
95  public static function useFileCache( IContextSource $context, $mode = self::MODE_NORMAL ) {
96  $config = MediaWikiServices::getInstance()->getMainConfig();
97 
98  if ( !$config->get( MainConfigNames::UseFileCache ) && $mode !== self::MODE_REBUILD ) {
99  return false;
100  }
101 
102  // Get all query values
103  $queryVals = $context->getRequest()->getValues();
104  foreach ( $queryVals as $query => $val ) {
105  if ( $query === 'title' || $query === 'curid' ) {
106  continue; // note: curid sets title
107  // Normal page view in query form can have action=view.
108  } elseif ( $query === 'action' && in_array( $val, self::cacheablePageActions() ) ) {
109  continue;
110  // Below are header setting params
111  } elseif ( $query === 'maxage' || $query === 'smaxage' ) {
112  continue;
113  }
114 
115  return false;
116  }
117 
118  $user = $context->getUser();
119  // Check for non-standard user language; this covers uselang,
120  // and extensions for auto-detecting user language.
121  $ulang = $context->getLanguage();
122 
123  // Check that there are no other sources of variation
124  if ( $user->isRegistered() ||
125  !$ulang->equals( MediaWikiServices::getInstance()->getContentLanguage() ) ) {
126  return false;
127  }
128 
129  $userHasNewMessages = MediaWikiServices::getInstance()
130  ->getTalkPageNotificationManager()->userHasNewMessages( $user );
131  if ( ( $mode === self::MODE_NORMAL ) && $userHasNewMessages ) {
132  return false;
133  }
134 
135  // Allow extensions to disable caching
136  return Hooks::runner()->onHTMLFileCache__useFileCache( $context );
137  }
138 
145  public function loadFromFileCache( IContextSource $context, $mode = self::MODE_NORMAL ) {
146  wfDebug( __METHOD__ . "()" );
147  $filename = $this->cachePath();
148 
149  if ( $mode === self::MODE_OUTAGE ) {
150  // Avoid DB errors for queries in sendCacheControl()
151  $context->getTitle()->resetArticleID( 0 );
152  }
153 
154  $context->getOutput()->sendCacheControl();
155  header( "Content-Type: {$this->options->get( MainConfigNames::MimeType )}; charset=UTF-8" );
156  header( 'Content-Language: ' .
157  MediaWikiServices::getInstance()->getContentLanguage()->getHtmlCode() );
158  if ( $this->useGzip() ) {
159  if ( wfClientAcceptsGzip() ) {
160  header( 'Content-Encoding: gzip' );
161  readfile( $filename );
162  } else {
163  /* Send uncompressed */
164  wfDebug( __METHOD__ . " uncompressing cache file and sending it" );
165  readgzfile( $filename );
166  }
167  } else {
168  readfile( $filename );
169  }
170 
171  $context->getOutput()->disable(); // tell $wgOut that output is taken care of
172  }
173 
186  public function saveToFileCache( $text ) {
187  if ( strlen( $text ) < 512 ) {
188  // Disabled or empty/broken output (OOM and PHP errors)
189  return $text;
190  }
191 
192  wfDebug( __METHOD__ . "()\n", 'private' );
193 
194  $now = wfTimestampNow();
195  if ( $this->useGzip() ) {
196  $text = str_replace(
197  '</html>', '<!-- Cached/compressed ' . $now . " -->\n</html>", $text );
198  } else {
199  $text = str_replace(
200  '</html>', '<!-- Cached ' . $now . " -->\n</html>", $text );
201  }
202 
203  // Store text to FS...
204  $compressed = $this->saveText( $text );
205  if ( $compressed === false ) {
206  return $text; // error
207  }
208 
209  // gzip output to buffer as needed and set headers...
210  // @todo Ugly wfClientAcceptsGzip() function - use context!
211  if ( $this->useGzip() && wfClientAcceptsGzip() ) {
212  header( 'Content-Encoding: gzip' );
213 
214  return $compressed;
215  }
216 
217  return $text;
218  }
219 
226  public static function clearFileCache( $page ) {
227  $config = MediaWikiServices::getInstance()->getMainConfig();
228  if ( !$config->get( MainConfigNames::UseFileCache ) ) {
229  return false;
230  }
231 
232  foreach ( self::cacheablePageActions() as $type ) {
233  $fc = new self( $page, $type );
234  $fc->clearCache();
235  }
236 
237  return true;
238  }
239 }
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfClientAcceptsGzip( $force=false)
Whether the client accept gzip encoding.
Base class for data storage in the file system.
useGzip()
Check if the cache is gzipped.
cachePath()
Get the path to the cache file.
saveText( $text)
Save and compress text to the cache.
baseCacheDirectory()
Get the base file cache directory.
Page view caching in the file system.
static useFileCache(IContextSource $context, $mode=self::MODE_NORMAL)
Check if pages can be cached for this request/user.
__construct( $page, $action)
loadFromFileCache(IContextSource $context, $mode=self::MODE_NORMAL)
Read from cache to context output.
static clearFileCache( $page)
Clear the file caches for a page for all actions.
saveToFileCache( $text)
Save this cache object with the given text.
cacheDirectory()
Get the base file cache directory.
typeSubdirectory()
Get the cache type subdirectory (with the trailing slash) or the empty string Alter the type -> direc...
static cacheablePageActions()
Cacheable actions.
static runner()
Get a HookRunner instance for calling hooks using the new interfaces.
Definition: Hooks.php:173
Helper class for mapping value objects representing basic entities to cache keys.
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
Interface for objects which can provide a MediaWiki context on request.
Interface for objects (potentially) representing an editable wiki page.