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