MediaWiki  master
FileCacheBase.php
Go to the documentation of this file.
1 <?php
25 use Wikimedia\IPUtils;
26 
32 abstract class FileCacheBase {
33  protected $mKey;
34  protected $mType = 'object';
35  protected $mExt = 'cache';
36  protected $mFilePath;
37  protected $mUseGzip;
39  protected $mCached;
40 
41  /* @todo configurable? */
42  private const MISS_FACTOR = 15; // log 1 every MISS_FACTOR cache misses
43  private const MISS_TTL_SEC = 3600; // how many seconds ago is "recent"
44 
45  protected function __construct() {
46  $useGzip = MediaWikiServices::getInstance()->getMainConfig()->get( 'UseGzip' );
47 
48  $this->mUseGzip = (bool)$useGzip;
49  }
50 
55  final protected function baseCacheDirectory() {
56  $fileCacheDirectory = MediaWikiServices::getInstance()->getMainConfig()->get( 'FileCacheDirectory' );
57 
58  return $fileCacheDirectory;
59  }
60 
65  abstract protected function cacheDirectory();
66 
71  protected function cachePath() {
72  if ( $this->mFilePath !== null ) {
73  return $this->mFilePath;
74  }
75 
76  $dir = $this->cacheDirectory();
77  # Build directories (methods include the trailing "/")
78  $subDirs = $this->typeSubdirectory() . $this->hashSubdirectory();
79  # Avoid extension confusion
80  $key = str_replace( '.', '%2E', urlencode( $this->mKey ) );
81  # Build the full file path
82  $this->mFilePath = "{$dir}/{$subDirs}{$key}.{$this->mExt}";
83  if ( $this->useGzip() ) {
84  $this->mFilePath .= '.gz';
85  }
86 
87  return $this->mFilePath;
88  }
89 
94  public function isCached() {
95  if ( $this->mCached === null ) {
96  $this->mCached = is_file( $this->cachePath() );
97  }
98 
99  return $this->mCached;
100  }
101 
106  public function cacheTimestamp() {
107  $timestamp = filemtime( $this->cachePath() );
108 
109  return ( $timestamp !== false )
110  ? wfTimestamp( TS_MW, $timestamp )
111  : false;
112  }
113 
120  public function isCacheGood( $timestamp = '' ) {
121  $cacheEpoch = MediaWikiServices::getInstance()->getMainConfig()->get( 'CacheEpoch' );
122 
123  if ( !$this->isCached() ) {
124  return false;
125  }
126 
127  $cachetime = $this->cacheTimestamp();
128  $good = ( $timestamp <= $cachetime && $cacheEpoch <= $cachetime );
129  wfDebug( __METHOD__ .
130  ": cachetime $cachetime, touched '{$timestamp}' epoch {$cacheEpoch}, good $good" );
131 
132  return $good;
133  }
134 
139  protected function useGzip() {
140  return $this->mUseGzip;
141  }
142 
147  public function fetchText() {
148  if ( $this->useGzip() ) {
149  $fh = gzopen( $this->cachePath(), 'rb' );
150 
151  return stream_get_contents( $fh );
152  } else {
153  return file_get_contents( $this->cachePath() );
154  }
155  }
156 
162  public function saveText( $text ) {
163  if ( $this->useGzip() ) {
164  $text = gzencode( $text );
165  }
166 
167  $this->checkCacheDirs(); // build parent dir
168  if ( !file_put_contents( $this->cachePath(), $text, LOCK_EX ) ) {
169  wfDebug( __METHOD__ . "() failed saving " . $this->cachePath() );
170  $this->mCached = null;
171 
172  return false;
173  }
174 
175  $this->mCached = true;
176 
177  return $text;
178  }
179 
184  public function clearCache() {
185  Wikimedia\suppressWarnings();
186  unlink( $this->cachePath() );
187  Wikimedia\restoreWarnings();
188  $this->mCached = false;
189  }
190 
195  protected function checkCacheDirs() {
196  wfMkdirParents( dirname( $this->cachePath() ), null, __METHOD__ );
197  }
198 
206  protected function typeSubdirectory() {
207  return $this->mType . '/';
208  }
209 
215  protected function hashSubdirectory() {
216  $fileCacheDepth = MediaWikiServices::getInstance()->getMainConfig()->get( 'FileCacheDepth' );
217 
218  $subdir = '';
219  if ( $fileCacheDepth > 0 ) {
220  $hash = md5( $this->mKey );
221  for ( $i = 1; $i <= $fileCacheDepth; $i++ ) {
222  $subdir .= substr( $hash, 0, $i ) . '/';
223  }
224  }
225 
226  return $subdir;
227  }
228 
234  public function incrMissesRecent( WebRequest $request ) {
235  if ( mt_rand( 0, self::MISS_FACTOR - 1 ) == 0 ) {
236  # Get a large IP range that should include the user even if that
237  # person's IP address changes
238  $ip = $request->getIP();
239  if ( !IPUtils::isValid( $ip ) ) {
240  return;
241  }
242 
243  $ip = IPUtils::isIPv6( $ip )
244  ? IPUtils::sanitizeRange( "$ip/32" )
245  : IPUtils::sanitizeRange( "$ip/16" );
246 
247  # Bail out if a request already came from this range...
249  $key = $cache->makeKey( static::class, 'attempt', $this->mType, $this->mKey, $ip );
250  if ( !$cache->add( $key, 1, self::MISS_TTL_SEC ) ) {
251  return; // possibly the same user
252  }
253 
254  # Increment the number of cache misses...
255  $cache->incrWithInit( $this->cacheMissKey( $cache ), self::MISS_TTL_SEC );
256  }
257  }
258 
263  public function getMissesRecent() {
265 
266  return self::MISS_FACTOR * $cache->get( $this->cacheMissKey( $cache ) );
267  }
268 
273  protected function cacheMissKey( BagOStuff $cache ) {
274  return $cache->makeKey( static::class, 'misses', $this->mType, $this->mKey );
275  }
276 }
FileCacheBase\__construct
__construct()
Definition: FileCacheBase.php:45
FileCacheBase\cacheMissKey
cacheMissKey(BagOStuff $cache)
Definition: FileCacheBase.php:273
FileCacheBase\MISS_FACTOR
const MISS_FACTOR
Definition: FileCacheBase.php:42
ObjectCache\getLocalClusterInstance
static getLocalClusterInstance()
Get the main cluster-local cache object.
Definition: ObjectCache.php:273
FileCacheBase\saveText
saveText( $text)
Save and compress text to the cache.
Definition: FileCacheBase.php:162
FileCacheBase\isCacheGood
isCacheGood( $timestamp='')
Check if up to date cache file exists.
Definition: FileCacheBase.php:120
wfMkdirParents
wfMkdirParents( $dir, $mode=null, $caller=null)
Make directory, and make all parent directories if they don't exist.
Definition: GlobalFunctions.php:1731
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:203
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1649
FileCacheBase\$mUseGzip
$mUseGzip
Definition: FileCacheBase.php:37
BagOStuff
Class representing a cache/ephemeral data store.
Definition: BagOStuff.php:86
FileCacheBase\hashSubdirectory
hashSubdirectory()
Return relative multi-level hash subdirectory (with trailing slash) or the empty string if not $wgFil...
Definition: FileCacheBase.php:215
FileCacheBase\$mKey
$mKey
Definition: FileCacheBase.php:33
FileCacheBase\$mExt
$mExt
Definition: FileCacheBase.php:35
FileCacheBase\useGzip
useGzip()
Check if the cache is gzipped.
Definition: FileCacheBase.php:139
FileCacheBase\baseCacheDirectory
baseCacheDirectory()
Get the base file cache directory.
Definition: FileCacheBase.php:55
FileCacheBase\fetchText
fetchText()
Get the uncompressed text from the cache.
Definition: FileCacheBase.php:147
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:894
FileCacheBase\typeSubdirectory
typeSubdirectory()
Get the cache type subdirectory (with trailing slash) An extending class could use that method to alt...
Definition: FileCacheBase.php:206
FileCacheBase\MISS_TTL_SEC
const MISS_TTL_SEC
Definition: FileCacheBase.php:43
FileCacheBase\$mCached
bool null $mCached
lazy loaded
Definition: FileCacheBase.php:39
FileCacheBase\isCached
isCached()
Check if the cache file exists.
Definition: FileCacheBase.php:94
FileCacheBase\cacheDirectory
cacheDirectory()
Get the base cache directory (not specific to this file)
FileCacheBase\clearCache
clearCache()
Clear the cache for this page.
Definition: FileCacheBase.php:184
WebRequest
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
Definition: WebRequest.php:43
WebRequest\getIP
getIP()
Work out the IP address based on various globals For trusted proxies, use the XFF client IP (first of...
Definition: WebRequest.php:1272
FileCacheBase\$mFilePath
$mFilePath
Definition: FileCacheBase.php:36
FileCacheBase\getMissesRecent
getMissesRecent()
Roughly gets the cache misses in the last hour by unique visitors.
Definition: FileCacheBase.php:263
FileCacheBase\$mType
$mType
Definition: FileCacheBase.php:34
$cache
$cache
Definition: mcc.php:33
FileCacheBase\cachePath
cachePath()
Get the path to the cache file.
Definition: FileCacheBase.php:71
FileCacheBase\incrMissesRecent
incrMissesRecent(WebRequest $request)
Roughly increments the cache misses in the last hour by unique visitors.
Definition: FileCacheBase.php:234
FileCacheBase\cacheTimestamp
cacheTimestamp()
Get the last-modified timestamp of the cache file.
Definition: FileCacheBase.php:106
FileCacheBase\checkCacheDirs
checkCacheDirs()
Create parent directors of $this->cachePath()
Definition: FileCacheBase.php:195
FileCacheBase
Base class for data storage in the file system.
Definition: FileCacheBase.php:32