00001 <?php
00007 namespace Habari;
00008
00014 class FileCache extends Cache
00015 {
00016 protected $cache_location;
00017 protected $enabled = false;
00018 protected $cache_files = array();
00019 protected $cache_data = array();
00020 protected $index_file;
00021
00027 public function __construct()
00028 {
00029 if ( !defined( 'FILE_CACHE_LOCATION' ) ) {
00030 define( 'FILE_CACHE_LOCATION', HABARI_PATH . '/user/cache/' );
00031 }
00032 $this->cache_location = FILE_CACHE_LOCATION;
00033 $this->index_file = $this->cache_location . md5( 'index' . Options::get( 'private-GUID' ) ) . '.data';
00034 $this->enabled = is_writeable( $this->cache_location );
00035 if ( $this->enabled ) {
00036 if ( file_exists( $this->index_file ) ) {
00037 $this->cache_files = unserialize( file_get_contents( $this->index_file ) );
00038 }
00039 }
00040 else {
00041 Session::error( _t( "The cache directory '%s' is not writable - the cache is disabled. The user, or group, which your web server is running as, needs to have read, write, and execute permissions on this directory.", array( $this->cache_location ) ), 'filecache' );
00042 EventLog::log( _t( "The cache directory '%s' is not writable - the cache is disabled.", array( $this->cache_location ) ), 'notice', 'cache', 'habari' );
00043 }
00044 }
00045
00052 protected function _has( $name, $group )
00053 {
00054 if ( !$this->enabled ) {
00055 return false;
00056 }
00057 $hash = $this->get_name_hash( $name );
00058 $ghash = $this->get_group_hash( $group );
00059
00060 return isset( $this->cache_files[$ghash][$hash] )
00061 && ( $this->cache_files[$ghash][$hash]['keep'] || $this->cache_files[$ghash][$hash]['expires'] > time() )
00062 && file_exists( $this->cache_files[$ghash][$hash]['file'] );
00063 }
00064
00071 protected function _has_group( $group )
00072 {
00073 if ( !$this->enabled ) {
00074 return false;
00075 }
00076 $ghash = $this->get_group_hash( $group );
00077
00078 $valid = true;
00079 $now = time();
00080 foreach ( $this->cache_files[$ghash] as $hash => $record ) {
00081 if ( ! file_exists( $record['file'] ) || $record['expires'] <= $now ) {
00082 $valid = false;
00083 break;
00084 }
00085 }
00086
00087 return ( isset( $this->cache_files[$ghash] ) && count( $this->cache_files[$ghash] ) > 1 ) && $valid;
00088 }
00089
00096 protected function _get_group( $group )
00097 {
00098 if ( !$this->enabled ) {
00099 return null;
00100 }
00101 $ghash = $this->get_group_hash( $group );
00102
00103 if ( !isset( $this->cache_data[$group] ) ) {
00104 $this->cache_data[$group] = array();
00105 if ( isset( $this->cache_files[$ghash] ) ) {
00106 foreach ( $this->cache_files[$ghash] as $hash => $record ) {
00107 $this->cache_data[$group][$record['name']] = unserialize(
00108 file_get_contents( $record['file'] )
00109 );
00110 }
00111 }
00112 }
00113 return $this->cache_data[$group];
00114 }
00115
00122 protected function _get( $name, $group )
00123 {
00124 if ( !$this->enabled ) {
00125 return null;
00126 }
00127 $hash = $this->get_name_hash( $name );
00128 $ghash = $this->get_group_hash( $group );
00129
00130 if ( !isset( $this->cache_data[$group][$name] ) ) {
00131 $this->cache_data[$group][$name] = null;
00132 if ( isset( $this->cache_files[$ghash][$hash] ) && ($this->cache_files[$ghash][$hash]['keep'] || $this->cache_files[$ghash][$hash]['expires'] > time()) && file_exists( $this->cache_files[$ghash][$hash]['file'] ) ) {
00133 $this->cache_data[$group][$name] = unserialize( file_get_contents( $this->cache_files[$ghash][$hash]['file'] ) );
00134 }
00135 }
00136 return $this->cache_data[$group][$name];
00137 }
00138
00139 protected function _set( $name, $value, $expiry, $group, $keep )
00140 {
00141 if ( !$this->enabled ) {
00142 return null;
00143 }
00144
00145 Plugins::act( 'cache_set_before', $name, $group, $value, $expiry );
00146
00147 $hash = $this->get_name_hash( $name );
00148 $ghash = $this->get_group_hash( $group );
00149
00150 if ( !isset( $this->cache_data[$group] ) ) {
00151
00152 $this->_get_group( $group );
00153 }
00154 $this->cache_data[$group][$name] = $value;
00155
00156 file_put_contents( $this->cache_location . $ghash . $hash, serialize( $value ) );
00157 $this->cache_files[$ghash][$hash] = array( 'file' => $this->cache_location . $ghash . $hash, 'expires' => time() + $expiry, 'name' => $name, 'keep' => $keep );
00158 $this->clear_expired();
00159 file_put_contents( $this->index_file, serialize( $this->cache_files ) );
00160
00161 Plugins::act( 'cache_set_after', $name, $group, $value, $expiry );
00162
00163 return true;
00164 }
00165
00173 protected function _expire( $name, $group, $match_mode = 'strict' )
00174 {
00175 if ( !$this->enabled ) {
00176 return null;
00177 }
00178
00179
00180
00181
00182 $this->_get_group($group);
00183
00184 $keys = array();
00185 switch ( strtolower( $match_mode ) ) {
00186 case 'glob':
00187 if ( array_key_exists( $group, $this->cache_data ) ) {
00188 $keys = preg_grep( Utils::glob_to_regex( $name ), array_keys( $this->cache_data[$group] ) );
00189 }
00190 break;
00191 case 'regex':
00192 if ( array_key_exists( $group, $this->cache_data ) ) {
00193 $keys = preg_grep( $name, array_keys( $this->cache_data[$group] ) );
00194 }
00195 break;
00196 case 'strict':
00197 default:
00198 $keys = array( $name );
00199 break;
00200 }
00201
00202 $ghash = $this->get_group_hash( $group );
00203 foreach ( $keys as $key ) {
00204 Plugins::act( 'cache_expire_before', $name, $group );
00205
00206 $hash = $this->get_name_hash( $key );
00207
00208 if ( isset( $this->cache_files[$ghash][$hash] ) && file_exists( $this->cache_files[$ghash][$hash]['file'] ) ) {
00209 unlink( $this->cache_files[$ghash][$hash]['file'] );
00210 unset( $this->cache_files[$ghash][$hash] );
00211 unset( $this->cache_data[$group][$name] );
00212 }
00213
00214 Plugins::act( 'cache_expire_after', $name, $group );
00215 }
00216
00217 $this->clear_expired();
00218 file_put_contents( $this->index_file, serialize( $this->cache_files ) );
00219 }
00220
00221
00229 protected function _expired( $name, $group )
00230 {
00231 if ( !$this->enabled ) {
00232 return null;
00233 }
00234 $hash = $this->get_name_hash( $name );
00235 $ghash = $this->get_group_hash( $group );
00236
00237
00238 if ( isset( $this->cache_files[$ghash][$hash] ) && $this->cache_files[$ghash][$hash]['expires'] > time() && file_exists( $this->cache_files[$ghash][$hash]['file'] ) ) {
00239 return false;
00240 }
00241 else {
00242 return true;
00243 }
00244 }
00245
00252 protected function _extend( $name, $expiry, $group )
00253 {
00254 if ( !$this->enabled ) {
00255 return null;
00256 }
00257
00258 Plugins::act( 'cache_extend_before', $name, $group, $expiry );
00259
00260 $hash = $this->get_name_hash( $name );
00261 $ghash = $this->get_group_hash( $group );
00262
00263 if ( isset( $this->cache_files[$ghash][$hash] ) ) {
00264 $this->cache_files[$ghash][$hash]['expires'] = time() + $expiry;
00265 $this->clear_expired();
00266 file_put_contents( $this->index_file, serialize( $this->cache_files ) );
00267 }
00268
00269 Plugins::act( 'cache_extend_after', $name, $group, $expiry );
00270 }
00271
00275 protected function _purge()
00276 {
00277 Plugins::act( 'cache_purge_before' );
00278
00279 $glob = Utils::glob( FILE_CACHE_LOCATION . '*.data' );
00280 foreach ( $glob as $file ) {
00281 unlink( $file );
00282 }
00283 $glob = Utils::glob( FILE_CACHE_LOCATION . '*.cache' );
00284 foreach ( $glob as $file ) {
00285 unlink( $file );
00286 }
00287
00288 Plugins::act( 'cache_purge_after' );
00289 }
00290
00296 private function get_name_hash( $name )
00297 {
00298 return md5( $name . Options::get( 'private-GUID' ) ) . '.cache';
00299 }
00300
00306 private function get_group_hash( $group )
00307 {
00308 return md5( $group . Options::get( 'private-GUID' ) ) . '.';
00309 }
00310
00314 private function record_fresh( $record )
00315 {
00316 if ( $record['expires'] > time() || $record['keep'] ) {
00317 return true;
00318 }
00319 elseif ( file_exists( $record['file'] ) ) {
00320 unlink( $record['file'] );
00321 }
00322 return false;
00323 }
00324
00328 private function clear_expired()
00329 {
00330 foreach ( $this->cache_files as $ghash => $records ) {
00331 $this->cache_files[$ghash] = array_filter( $records, array( $this, 'record_fresh' ) );
00332 }
00333 }
00334
00335 }
00336
00337 ?>