CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Team
    • Issues (Github)
    • YouTube Channel
    • Get Involved
    • Bakery
    • Featured Resources
    • Newsletter
    • Certification
    • My CakePHP
    • CakeFest
    • Facebook
    • Twitter
    • Help & Support
    • Forum
    • Stack Overflow
    • IRC
    • Slack
    • Paid Support
CakePHP

C CakePHP 3.7 Red Velvet API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 3.7
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Namespaces

  • Cake
    • Auth
      • Storage
    • Cache
      • Engine
    • Collection
      • Iterator
    • Command
    • Console
      • Exception
    • Controller
      • Component
      • Exception
    • Core
      • Configure
        • Engine
      • Exception
      • Retry
    • Database
      • Driver
      • Exception
      • Expression
      • Schema
      • Statement
      • Type
    • Datasource
      • Exception
    • Error
      • Middleware
    • Event
      • Decorator
    • Filesystem
    • Form
    • Http
      • Client
        • Adapter
        • Auth
      • Cookie
      • Exception
      • Middleware
      • Session
    • I18n
      • Formatter
      • Middleware
      • Parser
    • Log
      • Engine
    • Mailer
      • Exception
      • Transport
    • Network
      • Exception
    • ORM
      • Association
      • Behavior
        • Translate
      • Exception
      • Locator
      • Rule
    • Routing
      • Exception
      • Filter
      • Middleware
      • Route
    • Shell
      • Helper
      • Task
    • TestSuite
      • Fixture
      • Stub
    • Utility
      • Exception
    • Validation
    • View
      • Exception
      • Form
      • Helper
      • Widget
  • None

Classes

  • ApcuEngine
  • ArrayEngine
  • FileEngine
  • MemcachedEngine
  • NullEngine
  • RedisEngine
  • WincacheEngine
  • XcacheEngine
  1: <?php
  2: /**
  3:  * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4:  * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5:  *
  6:  * Licensed under The MIT License
  7:  * For full copyright and license information, please see the LICENSE.txt
  8:  * Redistributions of files must retain the above copyright notice.
  9:  *
 10:  * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 11:  * @link          https://cakephp.org CakePHP(tm) Project
 12:  * @since         1.2.0
 13:  * @license       https://opensource.org/licenses/mit-license.php MIT License
 14:  */
 15: namespace Cake\Cache\Engine;
 16: 
 17: use Cake\Cache\CacheEngine;
 18: use Cake\Utility\Inflector;
 19: use CallbackFilterIterator;
 20: use Exception;
 21: use LogicException;
 22: use RecursiveDirectoryIterator;
 23: use RecursiveIteratorIterator;
 24: use SplFileInfo;
 25: use SplFileObject;
 26: 
 27: /**
 28:  * File Storage engine for cache. Filestorage is the slowest cache storage
 29:  * to read and write. However, it is good for servers that don't have other storage
 30:  * engine available, or have content which is not performance sensitive.
 31:  *
 32:  * You can configure a FileEngine cache, using Cache::config()
 33:  */
 34: class FileEngine extends CacheEngine
 35: {
 36: 
 37:     /**
 38:      * Instance of SplFileObject class
 39:      *
 40:      * @var \SplFileObject|null
 41:      */
 42:     protected $_File;
 43: 
 44:     /**
 45:      * The default config used unless overridden by runtime configuration
 46:      *
 47:      * - `duration` Specify how long items in this cache configuration last.
 48:      * - `groups` List of groups or 'tags' associated to every key stored in this config.
 49:      *    handy for deleting a complete group from cache.
 50:      * - `isWindows` Automatically populated with whether the host is windows or not
 51:      * - `lock` Used by FileCache. Should files be locked before writing to them?
 52:      * - `mask` The mask used for created files
 53:      * - `path` Path to where cachefiles should be saved. Defaults to system's temp dir.
 54:      * - `prefix` Prepended to all entries. Good for when you need to share a keyspace
 55:      *    with either another cache config or another application.
 56:      * - `probability` Probability of hitting a cache gc cleanup. Setting to 0 will disable
 57:      *    cache::gc from ever being called automatically.
 58:      * - `serialize` Should cache objects be serialized first.
 59:      *
 60:      * @var array
 61:      */
 62:     protected $_defaultConfig = [
 63:         'duration' => 3600,
 64:         'groups' => [],
 65:         'isWindows' => false,
 66:         'lock' => true,
 67:         'mask' => 0664,
 68:         'path' => null,
 69:         'prefix' => 'cake_',
 70:         'probability' => 100,
 71:         'serialize' => true
 72:     ];
 73: 
 74:     /**
 75:      * True unless FileEngine::__active(); fails
 76:      *
 77:      * @var bool
 78:      */
 79:     protected $_init = true;
 80: 
 81:     /**
 82:      * Initialize File Cache Engine
 83:      *
 84:      * Called automatically by the cache frontend.
 85:      *
 86:      * @param array $config array of setting for the engine
 87:      * @return bool True if the engine has been successfully initialized, false if not
 88:      */
 89:     public function init(array $config = [])
 90:     {
 91:         parent::init($config);
 92: 
 93:         if ($this->_config['path'] === null) {
 94:             $this->_config['path'] = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'cake_cache' . DIRECTORY_SEPARATOR;
 95:         }
 96:         if (DIRECTORY_SEPARATOR === '\\') {
 97:             $this->_config['isWindows'] = true;
 98:         }
 99:         if (substr($this->_config['path'], -1) !== DIRECTORY_SEPARATOR) {
100:             $this->_config['path'] .= DIRECTORY_SEPARATOR;
101:         }
102:         if ($this->_groupPrefix) {
103:             $this->_groupPrefix = str_replace('_', DIRECTORY_SEPARATOR, $this->_groupPrefix);
104:         }
105: 
106:         return $this->_active();
107:     }
108: 
109:     /**
110:      * Garbage collection. Permanently remove all expired and deleted data
111:      *
112:      * @param int|null $expires [optional] An expires timestamp, invalidating all data before.
113:      * @return bool True if garbage collection was successful, false on failure
114:      */
115:     public function gc($expires = null)
116:     {
117:         return $this->clear(true);
118:     }
119: 
120:     /**
121:      * Write data for key into cache
122:      *
123:      * @param string $key Identifier for the data
124:      * @param mixed $data Data to be cached
125:      * @return bool True if the data was successfully cached, false on failure
126:      */
127:     public function write($key, $data)
128:     {
129:         if ($data === '' || !$this->_init) {
130:             return false;
131:         }
132: 
133:         $key = $this->_key($key);
134: 
135:         if ($this->_setKey($key, true) === false) {
136:             return false;
137:         }
138: 
139:         $lineBreak = "\n";
140: 
141:         if ($this->_config['isWindows']) {
142:             $lineBreak = "\r\n";
143:         }
144: 
145:         if (!empty($this->_config['serialize'])) {
146:             if ($this->_config['isWindows']) {
147:                 $data = str_replace('\\', '\\\\\\\\', serialize($data));
148:             } else {
149:                 $data = serialize($data);
150:             }
151:         }
152: 
153:         $duration = $this->_config['duration'];
154:         $expires = time() + $duration;
155:         $contents = implode([$expires, $lineBreak, $data, $lineBreak]);
156: 
157:         if ($this->_config['lock']) {
158:             $this->_File->flock(LOCK_EX);
159:         }
160: 
161:         $this->_File->rewind();
162:         $success = $this->_File->ftruncate(0) &&
163:             $this->_File->fwrite($contents) &&
164:             $this->_File->fflush();
165: 
166:         if ($this->_config['lock']) {
167:             $this->_File->flock(LOCK_UN);
168:         }
169:         $this->_File = null;
170: 
171:         return $success;
172:     }
173: 
174:     /**
175:      * Read a key from the cache
176:      *
177:      * @param string $key Identifier for the data
178:      * @return mixed The cached data, or false if the data doesn't exist, has
179:      *   expired, or if there was an error fetching it
180:      */
181:     public function read($key)
182:     {
183:         $key = $this->_key($key);
184: 
185:         if (!$this->_init || $this->_setKey($key) === false) {
186:             return false;
187:         }
188: 
189:         if ($this->_config['lock']) {
190:             $this->_File->flock(LOCK_SH);
191:         }
192: 
193:         $this->_File->rewind();
194:         $time = time();
195:         $cachetime = (int)$this->_File->current();
196: 
197:         if ($cachetime < $time) {
198:             if ($this->_config['lock']) {
199:                 $this->_File->flock(LOCK_UN);
200:             }
201: 
202:             return false;
203:         }
204: 
205:         $data = '';
206:         $this->_File->next();
207:         while ($this->_File->valid()) {
208:             $data .= $this->_File->current();
209:             $this->_File->next();
210:         }
211: 
212:         if ($this->_config['lock']) {
213:             $this->_File->flock(LOCK_UN);
214:         }
215: 
216:         $data = trim($data);
217: 
218:         if ($data !== '' && !empty($this->_config['serialize'])) {
219:             if ($this->_config['isWindows']) {
220:                 $data = str_replace('\\\\\\\\', '\\', $data);
221:             }
222:             $data = unserialize((string)$data);
223:         }
224: 
225:         return $data;
226:     }
227: 
228:     /**
229:      * Delete a key from the cache
230:      *
231:      * @param string $key Identifier for the data
232:      * @return bool True if the value was successfully deleted, false if it didn't
233:      *   exist or couldn't be removed
234:      */
235:     public function delete($key)
236:     {
237:         $key = $this->_key($key);
238: 
239:         if ($this->_setKey($key) === false || !$this->_init) {
240:             return false;
241:         }
242: 
243:         $path = $this->_File->getRealPath();
244:         $this->_File = null;
245: 
246:         //@codingStandardsIgnoreStart
247:         return @unlink($path);
248:         //@codingStandardsIgnoreEnd
249:     }
250: 
251:     /**
252:      * Delete all values from the cache
253:      *
254:      * @param bool $check Optional - only delete expired cache items
255:      * @return bool True if the cache was successfully cleared, false otherwise
256:      */
257:     public function clear($check)
258:     {
259:         if (!$this->_init) {
260:             return false;
261:         }
262:         $this->_File = null;
263: 
264:         $threshold = $now = false;
265:         if ($check) {
266:             $now = time();
267:             $threshold = $now - $this->_config['duration'];
268:         }
269: 
270:         $this->_clearDirectory($this->_config['path'], $now, $threshold);
271: 
272:         $directory = new RecursiveDirectoryIterator(
273:             $this->_config['path'],
274:             \FilesystemIterator::SKIP_DOTS
275:         );
276:         $contents = new RecursiveIteratorIterator(
277:             $directory,
278:             RecursiveIteratorIterator::SELF_FIRST
279:         );
280:         $cleared = [];
281:         foreach ($contents as $path) {
282:             if ($path->isFile()) {
283:                 continue;
284:             }
285: 
286:             $path = $path->getRealPath() . DIRECTORY_SEPARATOR;
287:             if (!in_array($path, $cleared)) {
288:                 $this->_clearDirectory($path, $now, $threshold);
289:                 $cleared[] = $path;
290:             }
291:         }
292: 
293:         return true;
294:     }
295: 
296:     /**
297:      * Used to clear a directory of matching files.
298:      *
299:      * @param string $path The path to search.
300:      * @param int $now The current timestamp
301:      * @param int $threshold Any file not modified after this value will be deleted.
302:      * @return void
303:      */
304:     protected function _clearDirectory($path, $now, $threshold)
305:     {
306:         if (!is_dir($path)) {
307:             return;
308:         }
309:         $prefixLength = strlen($this->_config['prefix']);
310: 
311:         $dir = dir($path);
312:         while (($entry = $dir->read()) !== false) {
313:             if (substr($entry, 0, $prefixLength) !== $this->_config['prefix']) {
314:                 continue;
315:             }
316: 
317:             try {
318:                 $file = new SplFileObject($path . $entry, 'r');
319:             } catch (Exception $e) {
320:                 continue;
321:             }
322: 
323:             if ($threshold) {
324:                 $mtime = $file->getMTime();
325:                 if ($mtime > $threshold) {
326:                     continue;
327:                 }
328: 
329:                 $expires = (int)$file->current();
330:                 if ($expires > $now) {
331:                     continue;
332:                 }
333:             }
334:             if ($file->isFile()) {
335:                 $filePath = $file->getRealPath();
336:                 $file = null;
337: 
338:                 //@codingStandardsIgnoreStart
339:                 @unlink($filePath);
340:                 //@codingStandardsIgnoreEnd
341:             }
342:         }
343: 
344:         $dir->close();
345:     }
346: 
347:     /**
348:      * Not implemented
349:      *
350:      * @param string $key The key to decrement
351:      * @param int $offset The number to offset
352:      * @return void
353:      * @throws \LogicException
354:      */
355:     public function decrement($key, $offset = 1)
356:     {
357:         throw new LogicException('Files cannot be atomically decremented.');
358:     }
359: 
360:     /**
361:      * Not implemented
362:      *
363:      * @param string $key The key to increment
364:      * @param int $offset The number to offset
365:      * @return void
366:      * @throws \LogicException
367:      */
368:     public function increment($key, $offset = 1)
369:     {
370:         throw new LogicException('Files cannot be atomically incremented.');
371:     }
372: 
373:     /**
374:      * Sets the current cache key this class is managing, and creates a writable SplFileObject
375:      * for the cache file the key is referring to.
376:      *
377:      * @param string $key The key
378:      * @param bool $createKey Whether the key should be created if it doesn't exists, or not
379:      * @return bool true if the cache key could be set, false otherwise
380:      */
381:     protected function _setKey($key, $createKey = false)
382:     {
383:         $groups = null;
384:         if ($this->_groupPrefix) {
385:             $groups = vsprintf($this->_groupPrefix, $this->groups());
386:         }
387:         $dir = $this->_config['path'] . $groups;
388: 
389:         if (!is_dir($dir)) {
390:             mkdir($dir, 0775, true);
391:         }
392: 
393:         $path = new SplFileInfo($dir . $key);
394: 
395:         if (!$createKey && !$path->isFile()) {
396:             return false;
397:         }
398:         if (empty($this->_File) ||
399:             $this->_File->getBasename() !== $key ||
400:             $this->_File->valid() === false
401:         ) {
402:             $exists = file_exists($path->getPathname());
403:             try {
404:                 $this->_File = $path->openFile('c+');
405:             } catch (Exception $e) {
406:                 trigger_error($e->getMessage(), E_USER_WARNING);
407: 
408:                 return false;
409:             }
410:             unset($path);
411: 
412:             if (!$exists && !chmod($this->_File->getPathname(), (int)$this->_config['mask'])) {
413:                 trigger_error(sprintf(
414:                     'Could not apply permission mask "%s" on cache file "%s"',
415:                     $this->_File->getPathname(),
416:                     $this->_config['mask']
417:                 ), E_USER_WARNING);
418:             }
419:         }
420: 
421:         return true;
422:     }
423: 
424:     /**
425:      * Determine if cache directory is writable
426:      *
427:      * @return bool
428:      */
429:     protected function _active()
430:     {
431:         $dir = new SplFileInfo($this->_config['path']);
432:         $path = $dir->getPathname();
433:         $success = true;
434:         if (!is_dir($path)) {
435:             //@codingStandardsIgnoreStart
436:             $success = @mkdir($path, 0775, true);
437:             //@codingStandardsIgnoreEnd
438:         }
439: 
440:         $isWritableDir = ($dir->isDir() && $dir->isWritable());
441:         if (!$success || ($this->_init && !$isWritableDir)) {
442:             $this->_init = false;
443:             trigger_error(sprintf(
444:                 '%s is not writable',
445:                 $this->_config['path']
446:             ), E_USER_WARNING);
447:         }
448: 
449:         return $success;
450:     }
451: 
452:     /**
453:      * Generates a safe key for use with cache engine storage engines.
454:      *
455:      * @param string $key the key passed over
456:      * @return mixed string $key or false
457:      */
458:     public function key($key)
459:     {
460:         if (empty($key)) {
461:             return false;
462:         }
463: 
464:         $key = Inflector::underscore(str_replace(
465:             [DIRECTORY_SEPARATOR, '/', '.', '<', '>', '?', ':', '|', '*', '"'],
466:             '_',
467:             (string)$key
468:         ));
469: 
470:         return $key;
471:     }
472: 
473:     /**
474:      * Recursively deletes all files under any directory named as $group
475:      *
476:      * @param string $group The group to clear.
477:      * @return bool success
478:      */
479:     public function clearGroup($group)
480:     {
481:         $this->_File = null;
482: 
483:         $prefix = (string)$this->_config['prefix'];
484: 
485:         $directoryIterator = new RecursiveDirectoryIterator($this->_config['path']);
486:         $contents = new RecursiveIteratorIterator(
487:             $directoryIterator,
488:             RecursiveIteratorIterator::CHILD_FIRST
489:         );
490:         $filtered = new CallbackFilterIterator(
491:             $contents,
492:             function (SplFileInfo $current) use ($group, $prefix) {
493:                 if (!$current->isFile()) {
494:                     return false;
495:                 }
496: 
497:                 $hasPrefix = $prefix === ''
498:                     || strpos($current->getBasename(), $prefix) === 0;
499:                 if ($hasPrefix === false) {
500:                     return false;
501:                 }
502: 
503:                 $pos = strpos(
504:                     $current->getPathname(),
505:                     DIRECTORY_SEPARATOR . $group . DIRECTORY_SEPARATOR
506:                 );
507: 
508:                 return $pos !== false;
509:             }
510:         );
511:         foreach ($filtered as $object) {
512:             $path = $object->getPathname();
513:             $object = null;
514:             // @codingStandardsIgnoreLine
515:             @unlink($path);
516:         }
517: 
518:         return true;
519:     }
520: }
521: 
Follow @CakePHP
#IRC
OpenHub
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Logos & Trademarks
  • Community
  • Team
  • Issues (Github)
  • YouTube Channel
  • Get Involved
  • Bakery
  • Featured Resources
  • Newsletter
  • Certification
  • My CakePHP
  • CakeFest
  • Facebook
  • Twitter
  • Help & Support
  • Forum
  • Stack Overflow
  • IRC
  • Slack
  • Paid Support

Generated using CakePHP API Docs