MediaWiki master
HTMLFileCache.php
Go to the documentation of this file.
1<?php
10namespace MediaWiki\Cache;
11
12use InvalidArgumentException;
19
28 public const MODE_NORMAL = 0; // normal cache mode
29 public const MODE_OUTAGE = 1; // fallback cache for DB outages
30 public const MODE_REBUILD = 2; // background cache rebuild mode
31
32 private const CACHEABLE_ACTIONS = [
33 'view',
34 'history',
35 ];
36
41 public function __construct( $page, $action ) {
42 parent::__construct();
43
44 if ( !in_array( $action, self::CACHEABLE_ACTIONS ) ) {
45 throw new InvalidArgumentException( 'Invalid file cache type given.' );
46 }
47
48 $this->mKey = CacheKeyHelper::getKeyForPage( $page );
49 $this->mType = (string)$action;
50 $this->mExt = 'html';
51 }
52
57 protected function cacheDirectory() {
58 return $this->baseCacheDirectory(); // no subdir for b/c with old cache files
59 }
60
67 protected function typeSubdirectory() {
68 if ( $this->mType === 'view' ) {
69 return ''; // b/c to not skip existing cache
70 } else {
71 return $this->mType . '/';
72 }
73 }
74
81 public static function useFileCache( IContextSource $context, $mode = self::MODE_NORMAL ) {
83 $config = $services->getMainConfig();
84
85 if ( !$config->get( MainConfigNames::UseFileCache ) && $mode !== self::MODE_REBUILD ) {
86 return false;
87 }
88
89 // Get all query values
90 $queryVals = $context->getRequest()->getValues();
91 foreach ( $queryVals as $query => $val ) {
92 if ( $query === 'title' || $query === 'curid' ) {
93 continue; // note: curid sets title
94 // Normal page view in query form can have action=view.
95 } elseif ( $query === 'action' && in_array( $val, self::CACHEABLE_ACTIONS ) ) {
96 continue;
97 // Below are header setting params
98 } elseif ( $query === 'maxage' || $query === 'smaxage' ) {
99 continue;
100 // Uselang value is checked below
101 } elseif ( $query === 'uselang' ) {
102 continue;
103 }
104
105 return false;
106 }
107
108 $user = $context->getUser();
109 // Check for non-standard user language; this covers uselang,
110 // and extensions for auto-detecting user language.
111 $ulang = $context->getLanguage();
112
113 // Check that there are no other sources of variation
114 if ( $user->isRegistered() ||
115 !$ulang->equals( $services->getContentLanguage() ) ) {
116 return false;
117 }
118
119 $userHasNewMessages = $services->getTalkPageNotificationManager()->userHasNewMessages( $user );
120 if ( ( $mode === self::MODE_NORMAL ) && $userHasNewMessages ) {
121 return false;
122 }
123
124 // Allow extensions to disable caching
125 return ( new HookRunner( $services->getHookContainer() ) )->onHTMLFileCache__useFileCache( $context );
126 }
127
134 public function loadFromFileCache( IContextSource $context, $mode = self::MODE_NORMAL ) {
135 wfDebug( __METHOD__ . "()" );
136 $filename = $this->cachePath();
137
138 if ( $mode === self::MODE_OUTAGE ) {
139 // Avoid DB errors for queries in sendCacheControl()
140 $context->getTitle()->resetArticleID( 0 );
141 }
142
143 $context->getOutput()->sendCacheControl();
144 header( "Content-Type: {$this->options->get( MainConfigNames::MimeType )}; charset=UTF-8" );
145 header( 'Content-Language: ' .
146 MediaWikiServices::getInstance()->getContentLanguage()->getHtmlCode() );
147 if ( $this->useGzip() ) {
148 if ( wfClientAcceptsGzip() ) {
149 header( 'Content-Encoding: gzip' );
150 readfile( $filename );
151 } else {
152 /* Send uncompressed */
153 wfDebug( __METHOD__ . " uncompressing cache file and sending it" );
154 readgzfile( $filename );
155 }
156 } else {
157 readfile( $filename );
158 }
159
160 $context->getOutput()->disable(); // tell $wgOut that output is taken care of
161 }
162
175 public function saveToFileCache( $text ) {
176 if ( strlen( $text ) < 512 ) {
177 // Disabled or empty/broken output (OOM and PHP errors)
178 return $text;
179 }
180
181 wfDebug( __METHOD__ . "()\n", 'private' );
182
183 $now = wfTimestampNow();
184 if ( $this->useGzip() ) {
185 $text = str_replace(
186 '</html>', '<!-- Cached/compressed ' . $now . " -->\n</html>", $text );
187 } else {
188 $text = str_replace(
189 '</html>', '<!-- Cached ' . $now . " -->\n</html>", $text );
190 }
191
192 // Store text to FS...
193 $compressed = $this->saveText( $text );
194 if ( $compressed === false ) {
195 return $text; // error
196 }
197
198 // gzip output to buffer as needed and set headers...
199 // @todo Ugly wfClientAcceptsGzip() function - use context!
200 if ( $this->useGzip() && wfClientAcceptsGzip() ) {
201 header( 'Content-Encoding: gzip' );
202
203 return $compressed;
204 }
205
206 return $text;
207 }
208
215 public static function clearFileCache( $page ) {
216 $config = MediaWikiServices::getInstance()->getMainConfig();
217 if ( !$config->get( MainConfigNames::UseFileCache ) ) {
218 return false;
219 }
220
221 foreach ( self::CACHEABLE_ACTIONS as $type ) {
222 $fc = new self( $page, $type );
223 $fc->clearCache();
224 }
225
226 return true;
227 }
228}
229
231class_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.
Helper class for mapping page value objects to a string key.
Interface for objects which can provide a MediaWiki context on request.
Interface for objects (potentially) representing an editable wiki page.