[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Data storage in the file system. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 * @ingroup Cache 22 */ 23 24 /** 25 * Base class for data storage in the file system. 26 * 27 * @ingroup Cache 28 */ 29 abstract class FileCacheBase { 30 protected $mKey; 31 protected $mType = 'object'; 32 protected $mExt = 'cache'; 33 protected $mFilePath; 34 protected $mUseGzip; 35 /* lazy loaded */ 36 protected $mCached; 37 38 /* @todo configurable? */ 39 const MISS_FACTOR = 15; // log 1 every MISS_FACTOR cache misses 40 const MISS_TTL_SEC = 3600; // how many seconds ago is "recent" 41 42 protected function __construct() { 43 global $wgUseGzip; 44 45 $this->mUseGzip = (bool)$wgUseGzip; 46 } 47 48 /** 49 * Get the base file cache directory 50 * @return string 51 */ 52 final protected function baseCacheDirectory() { 53 global $wgFileCacheDirectory; 54 55 return $wgFileCacheDirectory; 56 } 57 58 /** 59 * Get the base cache directory (not specific to this file) 60 * @return string 61 */ 62 abstract protected function cacheDirectory(); 63 64 /** 65 * Get the path to the cache file 66 * @return string 67 */ 68 protected function cachePath() { 69 if ( $this->mFilePath !== null ) { 70 return $this->mFilePath; 71 } 72 73 $dir = $this->cacheDirectory(); 74 # Build directories (methods include the trailing "/") 75 $subDirs = $this->typeSubdirectory() . $this->hashSubdirectory(); 76 # Avoid extension confusion 77 $key = str_replace( '.', '%2E', urlencode( $this->mKey ) ); 78 # Build the full file path 79 $this->mFilePath = "{$dir}/{$subDirs}{$key}.{$this->mExt}"; 80 if ( $this->useGzip() ) { 81 $this->mFilePath .= '.gz'; 82 } 83 84 return $this->mFilePath; 85 } 86 87 /** 88 * Check if the cache file exists 89 * @return bool 90 */ 91 public function isCached() { 92 if ( $this->mCached === null ) { 93 $this->mCached = file_exists( $this->cachePath() ); 94 } 95 96 return $this->mCached; 97 } 98 99 /** 100 * Get the last-modified timestamp of the cache file 101 * @return string|bool TS_MW timestamp 102 */ 103 public function cacheTimestamp() { 104 $timestamp = filemtime( $this->cachePath() ); 105 106 return ( $timestamp !== false ) 107 ? wfTimestamp( TS_MW, $timestamp ) 108 : false; 109 } 110 111 /** 112 * Check if up to date cache file exists 113 * @param string $timestamp MW_TS timestamp 114 * 115 * @return bool 116 */ 117 public function isCacheGood( $timestamp = '' ) { 118 global $wgCacheEpoch; 119 120 if ( !$this->isCached() ) { 121 return false; 122 } 123 124 $cachetime = $this->cacheTimestamp(); 125 $good = ( $timestamp <= $cachetime && $wgCacheEpoch <= $cachetime ); 126 wfDebug( __METHOD__ . 127 ": cachetime $cachetime, touched '{$timestamp}' epoch {$wgCacheEpoch}, good $good\n" ); 128 129 return $good; 130 } 131 132 /** 133 * Check if the cache is gzipped 134 * @return bool 135 */ 136 protected function useGzip() { 137 return $this->mUseGzip; 138 } 139 140 /** 141 * Get the uncompressed text from the cache 142 * @return string 143 */ 144 public function fetchText() { 145 if ( $this->useGzip() ) { 146 $fh = gzopen( $this->cachePath(), 'rb' ); 147 148 return stream_get_contents( $fh ); 149 } else { 150 return file_get_contents( $this->cachePath() ); 151 } 152 } 153 154 /** 155 * Save and compress text to the cache 156 * @param string $text 157 * @return string Compressed text 158 */ 159 public function saveText( $text ) { 160 global $wgUseFileCache; 161 162 if ( !$wgUseFileCache ) { 163 return false; 164 } 165 166 if ( $this->useGzip() ) { 167 $text = gzencode( $text ); 168 } 169 170 $this->checkCacheDirs(); // build parent dir 171 if ( !file_put_contents( $this->cachePath(), $text, LOCK_EX ) ) { 172 wfDebug( __METHOD__ . "() failed saving " . $this->cachePath() . "\n" ); 173 $this->mCached = null; 174 175 return false; 176 } 177 178 $this->mCached = true; 179 180 return $text; 181 } 182 183 /** 184 * Clear the cache for this page 185 * @return void 186 */ 187 public function clearCache() { 188 wfSuppressWarnings(); 189 unlink( $this->cachePath() ); 190 wfRestoreWarnings(); 191 $this->mCached = false; 192 } 193 194 /** 195 * Create parent directors of $this->cachePath() 196 * @return void 197 */ 198 protected function checkCacheDirs() { 199 wfMkdirParents( dirname( $this->cachePath() ), null, __METHOD__ ); 200 } 201 202 /** 203 * Get the cache type subdirectory (with trailing slash) 204 * An extending class could use that method to alter the type -> directory 205 * mapping. @see HTMLFileCache::typeSubdirectory() for an example. 206 * 207 * @return string 208 */ 209 protected function typeSubdirectory() { 210 return $this->mType . '/'; 211 } 212 213 /** 214 * Return relative multi-level hash subdirectory (with trailing slash) 215 * or the empty string if not $wgFileCacheDepth 216 * @return string 217 */ 218 protected function hashSubdirectory() { 219 global $wgFileCacheDepth; 220 221 $subdir = ''; 222 if ( $wgFileCacheDepth > 0 ) { 223 $hash = md5( $this->mKey ); 224 for ( $i = 1; $i <= $wgFileCacheDepth; $i++ ) { 225 $subdir .= substr( $hash, 0, $i ) . '/'; 226 } 227 } 228 229 return $subdir; 230 } 231 232 /** 233 * Roughly increments the cache misses in the last hour by unique visitors 234 * @param WebRequest $request 235 * @return void 236 */ 237 public function incrMissesRecent( WebRequest $request ) { 238 global $wgMemc; 239 if ( mt_rand( 0, self::MISS_FACTOR - 1 ) == 0 ) { 240 # Get a large IP range that should include the user even if that 241 # person's IP address changes 242 $ip = $request->getIP(); 243 if ( !IP::isValid( $ip ) ) { 244 return; 245 } 246 $ip = IP::isIPv6( $ip ) 247 ? IP::sanitizeRange( "$ip/32" ) 248 : IP::sanitizeRange( "$ip/16" ); 249 250 # Bail out if a request already came from this range... 251 $key = wfMemcKey( get_class( $this ), 'attempt', $this->mType, $this->mKey, $ip ); 252 if ( $wgMemc->get( $key ) ) { 253 return; // possibly the same user 254 } 255 $wgMemc->set( $key, 1, self::MISS_TTL_SEC ); 256 257 # Increment the number of cache misses... 258 $key = $this->cacheMissKey(); 259 if ( $wgMemc->get( $key ) === false ) { 260 $wgMemc->set( $key, 1, self::MISS_TTL_SEC ); 261 } else { 262 $wgMemc->incr( $key ); 263 } 264 } 265 } 266 267 /** 268 * Roughly gets the cache misses in the last hour by unique visitors 269 * @return int 270 */ 271 public function getMissesRecent() { 272 global $wgMemc; 273 274 return self::MISS_FACTOR * $wgMemc->get( $this->cacheMissKey() ); 275 } 276 277 /** 278 * @return string 279 */ 280 protected function cacheMissKey() { 281 return wfMemcKey( get_class( $this ), 'misses', $this->mType, $this->mKey ); 282 } 283 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |