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.8 Red Velvet API

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