MediaWiki master
HTMLFileCache.php
Go to the documentation of this file.
1<?php
24namespace MediaWiki\Cache;
25
26use InvalidArgumentException;
32
41 public const MODE_NORMAL = 0; // normal cache mode
42 public const MODE_OUTAGE = 1; // fallback cache for DB outages
43 public const MODE_REBUILD = 2; // background cache rebuild mode
44
45 private const CACHEABLE_ACTIONS = [
46 'view',
47 'history',
48 ];
49
54 public function __construct( $page, $action ) {
55 parent::__construct();
56
57 if ( !in_array( $action, self::CACHEABLE_ACTIONS ) ) {
58 throw new InvalidArgumentException( 'Invalid file cache type given.' );
59 }
60
61 $this->mKey = CacheKeyHelper::getKeyForPage( $page );
62 $this->mType = (string)$action;
63 $this->mExt = 'html';
64 }
65
70 protected function cacheDirectory() {
71 return $this->baseCacheDirectory(); // no subdir for b/c with old cache files
72 }
73
80 protected function typeSubdirectory() {
81 if ( $this->mType === 'view' ) {
82 return ''; // b/c to not skip existing cache
83 } else {
84 return $this->mType . '/';
85 }
86 }
87
94 public static function useFileCache( IContextSource $context, $mode = self::MODE_NORMAL ) {
96 $config = $services->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::CACHEABLE_ACTIONS ) ) {
109 continue;
110 // Below are header setting params
111 } elseif ( $query === 'maxage' || $query === 'smaxage' ) {
112 continue;
113 // Uselang value is checked below
114 } elseif ( $query === 'uselang' ) {
115 continue;
116 }
117
118 return false;
119 }
120
121 $user = $context->getUser();
122 // Check for non-standard user language; this covers uselang,
123 // and extensions for auto-detecting user language.
124 $ulang = $context->getLanguage();
125
126 // Check that there are no other sources of variation
127 if ( $user->isRegistered() ||
128 !$ulang->equals( $services->getContentLanguage() ) ) {
129 return false;
130 }
131
132 $userHasNewMessages = $services->getTalkPageNotificationManager()->userHasNewMessages( $user );
133 if ( ( $mode === self::MODE_NORMAL ) && $userHasNewMessages ) {
134 return false;
135 }
136
137 // Allow extensions to disable caching
138 return ( new HookRunner( $services->getHookContainer() ) )->onHTMLFileCache__useFileCache( $context );
139 }
140
147 public function loadFromFileCache( IContextSource $context, $mode = self::MODE_NORMAL ) {
148 wfDebug( __METHOD__ . "()" );
149 $filename = $this->cachePath();
150
151 if ( $mode === self::MODE_OUTAGE ) {
152 // Avoid DB errors for queries in sendCacheControl()
153 $context->getTitle()->resetArticleID( 0 );
154 }
155
156 $context->getOutput()->sendCacheControl();
157 header( "Content-Type: {$this->options->get( MainConfigNames::MimeType )}; charset=UTF-8" );
158 header( 'Content-Language: ' .
159 MediaWikiServices::getInstance()->getContentLanguage()->getHtmlCode() );
160 if ( $this->useGzip() ) {
161 if ( wfClientAcceptsGzip() ) {
162 header( 'Content-Encoding: gzip' );
163 readfile( $filename );
164 } else {
165 /* Send uncompressed */
166 wfDebug( __METHOD__ . " uncompressing cache file and sending it" );
167 readgzfile( $filename );
168 }
169 } else {
170 readfile( $filename );
171 }
172
173 $context->getOutput()->disable(); // tell $wgOut that output is taken care of
174 }
175
188 public function saveToFileCache( $text ) {
189 if ( strlen( $text ) < 512 ) {
190 // Disabled or empty/broken output (OOM and PHP errors)
191 return $text;
192 }
193
194 wfDebug( __METHOD__ . "()\n", 'private' );
195
196 $now = wfTimestampNow();
197 if ( $this->useGzip() ) {
198 $text = str_replace(
199 '</html>', '<!-- Cached/compressed ' . $now . " -->\n</html>", $text );
200 } else {
201 $text = str_replace(
202 '</html>', '<!-- Cached ' . $now . " -->\n</html>", $text );
203 }
204
205 // Store text to FS...
206 $compressed = $this->saveText( $text );
207 if ( $compressed === false ) {
208 return $text; // error
209 }
210
211 // gzip output to buffer as needed and set headers...
212 // @todo Ugly wfClientAcceptsGzip() function - use context!
213 if ( $this->useGzip() && wfClientAcceptsGzip() ) {
214 header( 'Content-Encoding: gzip' );
215
216 return $compressed;
217 }
218
219 return $text;
220 }
221
228 public static function clearFileCache( $page ) {
229 $config = MediaWikiServices::getInstance()->getMainConfig();
230 if ( !$config->get( MainConfigNames::UseFileCache ) ) {
231 return false;
232 }
233
234 foreach ( self::CACHEABLE_ACTIONS as $type ) {
235 $fc = new self( $page, $type );
236 $fc->clearCache();
237 }
238
239 return true;
240 }
241}
242
244class_alias( HTMLFileCache::class, 'HTMLFileCache' );
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.
saveText( $text)
Save and compress text to the cache.
baseCacheDirectory()
Get the base file cache directory.
cachePath()
Get the path to the cache file.
useGzip()
Check if the cache is gzipped.
Page view caching in the file system.
saveToFileCache( $text)
Save this cache object with the given text.
static clearFileCache( $page)
Clear the file caches for a page for all actions.
typeSubdirectory()
Get the cache type subdirectory (with the trailing slash) or the empty string Alter the type -> direc...
static useFileCache(IContextSource $context, $mode=self::MODE_NORMAL)
Check if pages can be cached for this request/user.
loadFromFileCache(IContextSource $context, $mode=self::MODE_NORMAL)
Read from cache to context output.
cacheDirectory()
Get the base file cache directory.
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
A class containing constants representing the names of configuration variables.
const UseFileCache
Name constant for the UseFileCache setting, for use with Config::get()
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
Interface for objects which can provide a MediaWiki context on request.
Interface for objects (potentially) representing an editable wiki page.