MediaWiki master
HTMLFileCache.php
Go to the documentation of this file.
1<?php
31
40 public const MODE_NORMAL = 0; // normal cache mode
41 public const MODE_OUTAGE = 1; // fallback cache for DB outages
42 public const MODE_REBUILD = 2; // background cache rebuild mode
43
44 private const CACHEABLE_ACTIONS = [
45 'view',
46 'history',
47 ];
48
53 public function __construct( $page, $action ) {
54 parent::__construct();
55
56 if ( !in_array( $action, self::CACHEABLE_ACTIONS ) ) {
57 throw new InvalidArgumentException( 'Invalid file cache type given.' );
58 }
59
60 $this->mKey = CacheKeyHelper::getKeyForPage( $page );
61 $this->mType = (string)$action;
62 $this->mExt = 'html';
63 }
64
69 protected function cacheDirectory() {
70 return $this->baseCacheDirectory(); // no subdir for b/c with old cache files
71 }
72
79 protected function typeSubdirectory() {
80 if ( $this->mType === 'view' ) {
81 return ''; // b/c to not skip existing cache
82 } else {
83 return $this->mType . '/';
84 }
85 }
86
93 public static function useFileCache( IContextSource $context, $mode = self::MODE_NORMAL ) {
94 $services = MediaWikiServices::getInstance();
95 $config = $services->getMainConfig();
96
97 if ( !$config->get( MainConfigNames::UseFileCache ) && $mode !== self::MODE_REBUILD ) {
98 return false;
99 }
100
101 // Get all query values
102 $queryVals = $context->getRequest()->getValues();
103 foreach ( $queryVals as $query => $val ) {
104 if ( $query === 'title' || $query === 'curid' ) {
105 continue; // note: curid sets title
106 // Normal page view in query form can have action=view.
107 } elseif ( $query === 'action' && in_array( $val, self::CACHEABLE_ACTIONS ) ) {
108 continue;
109 // Below are header setting params
110 } elseif ( $query === 'maxage' || $query === 'smaxage' ) {
111 continue;
112 // Uselang value is checked below
113 } elseif ( $query === 'uselang' ) {
114 continue;
115 }
116
117 return false;
118 }
119
120 $user = $context->getUser();
121 // Check for non-standard user language; this covers uselang,
122 // and extensions for auto-detecting user language.
123 $ulang = $context->getLanguage();
124
125 // Check that there are no other sources of variation
126 if ( $user->isRegistered() ||
127 !$ulang->equals( $services->getContentLanguage() ) ) {
128 return false;
129 }
130
131 $userHasNewMessages = $services->getTalkPageNotificationManager()->userHasNewMessages( $user );
132 if ( ( $mode === self::MODE_NORMAL ) && $userHasNewMessages ) {
133 return false;
134 }
135
136 // Allow extensions to disable caching
137 return ( new HookRunner( $services->getHookContainer() ) )->onHTMLFileCache__useFileCache( $context );
138 }
139
146 public function loadFromFileCache( IContextSource $context, $mode = self::MODE_NORMAL ) {
147 wfDebug( __METHOD__ . "()" );
148 $filename = $this->cachePath();
149
150 if ( $mode === self::MODE_OUTAGE ) {
151 // Avoid DB errors for queries in sendCacheControl()
152 $context->getTitle()->resetArticleID( 0 );
153 }
154
155 $context->getOutput()->sendCacheControl();
156 header( "Content-Type: {$this->options->get( MainConfigNames::MimeType )}; charset=UTF-8" );
157 header( 'Content-Language: ' .
158 MediaWikiServices::getInstance()->getContentLanguage()->getHtmlCode() );
159 if ( $this->useGzip() ) {
160 if ( wfClientAcceptsGzip() ) {
161 header( 'Content-Encoding: gzip' );
162 readfile( $filename );
163 } else {
164 /* Send uncompressed */
165 wfDebug( __METHOD__ . " uncompressing cache file and sending it" );
166 readgzfile( $filename );
167 }
168 } else {
169 readfile( $filename );
170 }
171
172 $context->getOutput()->disable(); // tell $wgOut that output is taken care of
173 }
174
187 public function saveToFileCache( $text ) {
188 if ( strlen( $text ) < 512 ) {
189 // Disabled or empty/broken output (OOM and PHP errors)
190 return $text;
191 }
192
193 wfDebug( __METHOD__ . "()\n", 'private' );
194
195 $now = wfTimestampNow();
196 if ( $this->useGzip() ) {
197 $text = str_replace(
198 '</html>', '<!-- Cached/compressed ' . $now . " -->\n</html>", $text );
199 } else {
200 $text = str_replace(
201 '</html>', '<!-- Cached ' . $now . " -->\n</html>", $text );
202 }
203
204 // Store text to FS...
205 $compressed = $this->saveText( $text );
206 if ( $compressed === false ) {
207 return $text; // error
208 }
209
210 // gzip output to buffer as needed and set headers...
211 // @todo Ugly wfClientAcceptsGzip() function - use context!
212 if ( $this->useGzip() && wfClientAcceptsGzip() ) {
213 header( 'Content-Encoding: gzip' );
214
215 return $compressed;
216 }
217
218 return $text;
219 }
220
227 public static function clearFileCache( $page ) {
228 $config = MediaWikiServices::getInstance()->getMainConfig();
229 if ( !$config->get( MainConfigNames::UseFileCache ) ) {
230 return false;
231 }
232
233 foreach ( self::CACHEABLE_ACTIONS as $type ) {
234 $fc = new self( $page, $type );
235 $fc->clearCache();
236 }
237
238 return true;
239 }
240}
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.
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...
Helper class for mapping value objects representing basic entities to cache keys.
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.
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.
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.