[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/cache/ -> FileCacheBase.php (source)

   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  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1