7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
17 * @subpackage Zend_Cache_Backend
18 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
19 * @license http://framework.zend.com/license/new-bsd New BSD License
20 * @version $Id: File.php 24844 2012-05-31 19:01:36Z rob $
24 * @see Zend_Cache_Backend_Interface
26 //require_once 'Zend/Cache/Backend/ExtendedInterface.php';
27 require_once dirname(__FILE__
).'/ExtendedInterface.php';
30 * @see Zend_Cache_Backend
32 //require_once 'Zend/Cache/Backend.php';
33 require_once realpath(dirname(__FILE__
).'/..').DIRECTORY_SEPARATOR
.'Backend.php';
39 * @subpackage Zend_Cache_Backend
40 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
41 * @license http://framework.zend.com/license/new-bsd New BSD License
43 class Zend_Cache_Backend_File
extends Zend_Cache_Backend
implements Zend_Cache_Backend_ExtendedInterface
48 * =====> (string) cache_dir :
49 * - Directory where to put the cache files
51 * =====> (boolean) file_locking :
52 * - Enable / disable file_locking
53 * - Can avoid cache corruption under bad circumstances but it doesn't work on multithread
54 * webservers and on NFS filesystems for example
56 * =====> (boolean) read_control :
57 * - Enable / disable read control
58 * - If enabled, a control key is embeded in cache file and this key is compared with the one
59 * calculated after the reading.
61 * =====> (string) read_control_type :
62 * - Type of read control (only if read control is enabled). Available values are :
63 * 'md5' for a md5 hash control (best but slowest)
64 * 'crc32' for a crc32 hash control (lightly less safe but faster, better choice)
65 * 'adler32' for an adler32 hash control (excellent choice too, faster than crc32)
66 * 'strlen' for a length only test (fastest)
68 * =====> (int) hashed_directory_level :
69 * - Hashed directory level
70 * - Set the hashed directory structure level. 0 means "no hashed directory
71 * structure", 1 means "one level of directory", 2 means "two levels"...
72 * This option can speed up the cache only when you have many thousands of
73 * cache file. Only specific benchs can help you to choose the perfect value
74 * for you. Maybe, 1 or 2 is a good start.
76 * =====> (int) hashed_directory_umask :
78 * - Permissions for hashed directory structure
80 * =====> (int) hashed_directory_perm :
81 * - Permissions for hashed directory structure
83 * =====> (string) file_name_prefix :
84 * - prefix for cache files
85 * - be really carefull with this option because a too generic value in a system cache dir
86 * (like /tmp) can cause disasters when cleaning the cache
88 * =====> (int) cache_file_umask :
90 * - Permissions for cache files
92 * =====> (int) cache_file_perm :
93 * - Permissions for cache files
95 * =====> (int) metatadatas_array_max_size :
96 * - max size for the metadatas array (don't change this value unless you
97 * know what you are doing)
99 * @var array available options
101 protected $_options = array(
103 'file_locking' => true,
104 'read_control' => true,
105 'read_control_type' => 'crc32',
106 'hashed_directory_level' => 0,
107 'hashed_directory_perm' => 0700,
108 'file_name_prefix' => 'zend_cache',
109 'cache_file_perm' => 0600,
110 'metadatas_array_max_size' => 100
114 * Array of metadatas (each item is an associative array)
118 protected $_metadatasArray = array();
124 * @param array $options associative array of options
125 * @throws Zend_Cache_Exception
128 public function __construct(array $options = array())
130 parent
::__construct($options);
131 if ($this->_options
['cache_dir'] !== null) { // particular case for this option
132 $this->setCacheDir($this->_options
['cache_dir']);
134 $this->setCacheDir(self
::getTmpDir() . DIRECTORY_SEPARATOR
, false);
136 if (isset($this->_options
['file_name_prefix'])) { // particular case for this option
137 if (!preg_match('~^[a-zA-Z0-9_]+$~D', $this->_options
['file_name_prefix'])) {
138 Zend_Cache
::throwException('Invalid file_name_prefix : must use only [a-zA-Z0-9_]');
141 if ($this->_options
['metadatas_array_max_size'] < 10) {
142 Zend_Cache
::throwException('Invalid metadatas_array_max_size, must be > 10');
145 if (isset($options['hashed_directory_umask'])) {
147 trigger_error("'hashed_directory_umask' is deprecated -> please use 'hashed_directory_perm' instead", E_USER_NOTICE
);
148 if (!isset($options['hashed_directory_perm'])) {
149 $options['hashed_directory_perm'] = $options['hashed_directory_umask'];
152 if (isset($options['hashed_directory_perm']) && is_string($options['hashed_directory_perm'])) {
154 $this->_options
['hashed_directory_perm'] = octdec($this->_options
['hashed_directory_perm']);
157 if (isset($options['cache_file_umask'])) {
159 trigger_error("'cache_file_umask' is deprecated -> please use 'cache_file_perm' instead", E_USER_NOTICE
);
160 if (!isset($options['cache_file_perm'])) {
161 $options['cache_file_perm'] = $options['cache_file_umask'];
164 if (isset($options['cache_file_perm']) && is_string($options['cache_file_perm'])) {
166 $this->_options
['cache_file_perm'] = octdec($this->_options
['cache_file_perm']);
171 * Set the cache_dir (particular case of setOption() method)
173 * @param string $value
174 * @param boolean $trailingSeparator If true, add a trailing separator is necessary
175 * @throws Zend_Cache_Exception
178 public function setCacheDir($value, $trailingSeparator = true)
180 if (!is_dir($value)) {
181 Zend_Cache
::throwException(sprintf('cache_dir "%s" must be a directory', $value));
183 if (!is_writable($value)) {
184 Zend_Cache
::throwException(sprintf('cache_dir "%s" is not writable', $value));
186 if ($trailingSeparator) {
187 // add a trailing DIRECTORY_SEPARATOR if necessary
188 $value = rtrim(realpath($value), '\\/') . DIRECTORY_SEPARATOR
;
190 $this->_options
['cache_dir'] = $value;
194 * Test if a cache is available for the given id and (if yes) return it (false else)
196 * @param string $id cache id
197 * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
198 * @return string|false cached datas
200 public function load($id, $doNotTestCacheValidity = false)
202 if (!($this->_test($id, $doNotTestCacheValidity))) {
203 // The cache is not hit !
206 $metadatas = $this->_getMetadatas($id);
207 $file = $this->_file($id);
208 $data = $this->_fileGetContents($file);
209 if ($this->_options
['read_control']) {
210 $hashData = $this->_hash($data, $this->_options
['read_control_type']);
211 $hashControl = $metadatas['hash'];
212 if ($hashData != $hashControl) {
213 // Problem detected by the read control !
214 $this->_log('Zend_Cache_Backend_File::load() / read_control : stored hash and computed hash do not match');
223 * Test if a cache is available or not (for the given id)
225 * @param string $id cache id
226 * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
228 public function test($id)
231 return $this->_test($id, false);
235 * Save some string datas into a cache record
237 * Note : $data is always "string" (serialization is done by the
238 * core not by the backend)
240 * @param string $data Datas to cache
241 * @param string $id Cache id
242 * @param array $tags Array of strings, the cache record will be tagged by each string entry
243 * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
244 * @return boolean true if no problem
246 public function save($data, $id, $tags = array(), $specificLifetime = false)
249 $file = $this->_file($id);
250 $path = $this->_path($id);
251 if ($this->_options
['hashed_directory_level'] > 0) {
252 if (!is_writable($path)) {
253 // maybe, we just have to build the directory structure
254 $this->_recursiveMkdirAndChmod($id);
256 if (!is_writable($path)) {
260 if ($this->_options
['read_control']) {
261 $hash = $this->_hash($data, $this->_options
['read_control_type']);
268 'expire' => $this->_expireTime($this->getLifetime($specificLifetime)),
271 $res = $this->_setMetadatas($id, $metadatas);
273 $this->_log('Zend_Cache_Backend_File::save() / error on saving metadata');
276 $res = $this->_filePutContents($file, $data);
281 * Remove a cache record
283 * @param string $id cache id
284 * @return boolean true if no problem
286 public function remove($id)
288 $file = $this->_file($id);
289 $boolRemove = $this->_remove($file);
290 $boolMetadata = $this->_delMetadatas($id);
291 return $boolMetadata && $boolRemove;
295 * Clean some cache records
297 * Available modes are :
299 * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
300 * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
301 * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
302 * ($tags can be an array of strings or a single string)
303 * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
304 * ($tags can be an array of strings or a single string)
305 * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
306 * ($tags can be an array of strings or a single string)
308 * @param string $mode clean mode
309 * @param tags array $tags array of tags
310 * @return boolean true if no problem
312 public function clean($mode = Zend_Cache
::CLEANING_MODE_ALL
, $tags = array())
314 // We use this protected method to hide the recursive stuff
316 return $this->_clean($this->_options
['cache_dir'], $mode, $tags);
320 * Return an array of stored cache ids
322 * @return array array of stored cache ids (string)
324 public function getIds()
326 return $this->_get($this->_options
['cache_dir'], 'ids', array());
330 * Return an array of stored tags
332 * @return array array of stored tags (string)
334 public function getTags()
336 return $this->_get($this->_options
['cache_dir'], 'tags', array());
340 * Return an array of stored cache ids which match given tags
342 * In case of multiple tags, a logical AND is made between tags
344 * @param array $tags array of tags
345 * @return array array of matching cache ids (string)
347 public function getIdsMatchingTags($tags = array())
349 return $this->_get($this->_options
['cache_dir'], 'matching', $tags);
353 * Return an array of stored cache ids which don't match given tags
355 * In case of multiple tags, a logical OR is made between tags
357 * @param array $tags array of tags
358 * @return array array of not matching cache ids (string)
360 public function getIdsNotMatchingTags($tags = array())
362 return $this->_get($this->_options
['cache_dir'], 'notMatching', $tags);
366 * Return an array of stored cache ids which match any given tags
368 * In case of multiple tags, a logical AND is made between tags
370 * @param array $tags array of tags
371 * @return array array of any matching cache ids (string)
373 public function getIdsMatchingAnyTags($tags = array())
375 return $this->_get($this->_options
['cache_dir'], 'matchingAny', $tags);
379 * Return the filling percentage of the backend storage
381 * @throws Zend_Cache_Exception
382 * @return int integer between 0 and 100
384 public function getFillingPercentage()
386 $free = disk_free_space($this->_options
['cache_dir']);
387 $total = disk_total_space($this->_options
['cache_dir']);
389 Zend_Cache
::throwException('can\'t get disk_total_space');
391 if ($free >= $total) {
394 return ((int) (100. * ($total - $free) / $total));
399 * Return an array of metadatas for the given cache id
401 * The array must include these keys :
402 * - expire : the expire timestamp
403 * - tags : a string array of tags
404 * - mtime : timestamp of last modification time
406 * @param string $id cache id
407 * @return array array of metadatas (false if the cache id is not found)
409 public function getMetadatas($id)
411 $metadatas = $this->_getMetadatas($id);
415 if (time() > $metadatas['expire']) {
419 'expire' => $metadatas['expire'],
420 'tags' => $metadatas['tags'],
421 'mtime' => $metadatas['mtime']
426 * Give (if possible) an extra lifetime to the given cache id
428 * @param string $id cache id
429 * @param int $extraLifetime
430 * @return boolean true if ok
432 public function touch($id, $extraLifetime)
434 $metadatas = $this->_getMetadatas($id);
438 if (time() > $metadatas['expire']) {
441 $newMetadatas = array(
442 'hash' => $metadatas['hash'],
444 'expire' => $metadatas['expire'] +
$extraLifetime,
445 'tags' => $metadatas['tags']
447 $res = $this->_setMetadatas($id, $newMetadatas);
455 * Return an associative array of capabilities (booleans) of the backend
457 * The array must include these keys :
458 * - automatic_cleaning (is automating cleaning necessary)
459 * - tags (are tags supported)
460 * - expired_read (is it possible to read expired cache records
461 * (for doNotTestCacheValidity option for example))
462 * - priority does the backend deal with priority when saving
463 * - infinite_lifetime (is infinite lifetime can work with this backend)
464 * - get_list (is it possible to get the list of cache ids and the complete list of tags)
466 * @return array associative of with capabilities
468 public function getCapabilities()
471 'automatic_cleaning' => true,
473 'expired_read' => true,
475 'infinite_lifetime' => true,
481 * PUBLIC METHOD FOR UNIT TESTING ONLY !
483 * Force a cache record to expire
485 * @param string $id cache id
487 public function ___expire($id)
489 $metadatas = $this->_getMetadatas($id);
491 $metadatas['expire'] = 1;
492 $this->_setMetadatas($id, $metadatas);
497 * Get a metadatas record
499 * @param string $id Cache id
500 * @return array|false Associative array of metadatas
502 protected function _getMetadatas($id)
504 if (isset($this->_metadatasArray
[$id])) {
505 return $this->_metadatasArray
[$id];
507 $metadatas = $this->_loadMetadatas($id);
511 $this->_setMetadatas($id, $metadatas, false);
517 * Set a metadatas record
519 * @param string $id Cache id
520 * @param array $metadatas Associative array of metadatas
521 * @param boolean $save optional pass false to disable saving to file
522 * @return boolean True if no problem
524 protected function _setMetadatas($id, $metadatas, $save = true)
526 if (count($this->_metadatasArray
) >= $this->_options
['metadatas_array_max_size']) {
527 $n = (int) ($this->_options
['metadatas_array_max_size'] / 10);
528 $this->_metadatasArray
= array_slice($this->_metadatasArray
, $n);
531 $result = $this->_saveMetadatas($id, $metadatas);
536 $this->_metadatasArray
[$id] = $metadatas;
541 * Drop a metadata record
543 * @param string $id Cache id
544 * @return boolean True if no problem
546 protected function _delMetadatas($id)
548 if (isset($this->_metadatasArray
[$id])) {
549 unset($this->_metadatasArray
[$id]);
551 $file = $this->_metadatasFile($id);
552 return $this->_remove($file);
556 * Clear the metadatas array
560 protected function _cleanMetadatas()
562 $this->_metadatasArray
= array();
566 * Load metadatas from disk
568 * @param string $id Cache id
569 * @return array|false Metadatas associative array
571 protected function _loadMetadatas($id)
573 $file = $this->_metadatasFile($id);
574 $result = $this->_fileGetContents($file);
578 $tmp = @unserialize($result);
583 * Save metadatas to disk
585 * @param string $id Cache id
586 * @param array $metadatas Associative array
587 * @return boolean True if no problem
589 protected function _saveMetadatas($id, $metadatas)
591 $file = $this->_metadatasFile($id);
592 $result = $this->_filePutContents($file, serialize($metadatas));
600 * Make and return a file name (with path) for metadatas
602 * @param string $id Cache id
603 * @return string Metadatas file name (with path)
605 protected function _metadatasFile($id)
607 $path = $this->_path($id);
608 $fileName = $this->_idToFileName('internal-metadatas---' . $id);
609 return $path . $fileName;
613 * Check if the given filename is a metadatas one
615 * @param string $fileName File name
616 * @return boolean True if it's a metadatas one
618 protected function _isMetadatasFile($fileName)
620 $id = $this->_fileNameToId($fileName);
621 if (substr($id, 0, 21) == 'internal-metadatas---') {
631 * If we can't remove the file (because of locks or any problem), we will touch
632 * the file to invalidate it
634 * @param string $file Complete file path
635 * @return boolean True if ok
637 protected function _remove($file)
639 if (!is_file($file)) {
642 if (!@unlink($file)) {
643 # we can't remove the file (because of locks or any problem)
644 $this->_log("Zend_Cache_Backend_File::_remove() : we can't remove $file");
651 * Clean some cache records (protected method used for recursive stuff)
653 * Available modes are :
654 * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
655 * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
656 * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
657 * ($tags can be an array of strings or a single string)
658 * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
659 * ($tags can be an array of strings or a single string)
660 * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
661 * ($tags can be an array of strings or a single string)
663 * @param string $dir Directory to clean
664 * @param string $mode Clean mode
665 * @param array $tags Array of tags
666 * @throws Zend_Cache_Exception
667 * @return boolean True if no problem
669 protected function _clean($dir, $mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
675 $prefix = $this->_options['file_name_prefix'];
676 $glob = @glob($dir . $prefix . '--*');
677 if ($glob === false) {
678 // On some systems it is impossible to distinguish between empty match and an error.
681 foreach ($glob as $file) {
682 if (is_file($file)) {
683 $fileName = basename($file);
684 if ($this->_isMetadatasFile($fileName)) {
685 // in CLEANING_MODE_ALL, we drop anything, even remainings old metadatas files
686 if ($mode != Zend_Cache::CLEANING_MODE_ALL) {
690 $id = $this->_fileNameToId($fileName);
691 $metadatas = $this->_getMetadatas($id);
692 if ($metadatas === FALSE) {
693 $metadatas = array('expire' => 1, 'tags' => array());
696 case Zend_Cache::CLEANING_MODE_ALL:
697 $res = $this->remove($id);
699 // in this case only, we accept a problem with the metadatas file drop
700 $res = $this->_remove($file);
702 $result = $result && $res;
704 case Zend_Cache::CLEANING_MODE_OLD:
705 if (time() > $metadatas['expire']) {
706 $result = $this->remove($id) && $result;
709 case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
711 foreach ($tags as $tag) {
712 if (!in_array($tag, $metadatas['tags'])) {
718 $result = $this->remove($id) && $result;
721 case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
723 foreach ($tags as $tag) {
724 if (in_array($tag, $metadatas['tags'])) {
730 $result = $this->remove($id) && $result;
733 case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
735 foreach ($tags as $tag) {
736 if (in_array($tag, $metadatas['tags'])) {
742 $result = $this->remove($id) && $result;
746 Zend_Cache::throwException('Invalid mode for clean() method');
750 if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
752 $result = $this->_clean($file . DIRECTORY_SEPARATOR, $mode, $tags) && $result;
753 if ($mode == Zend_Cache::CLEANING_MODE_ALL) {
754 // we try to drop the structure too
762 protected function _get($dir, $mode, $tags = array())
768 $prefix = $this->_options['file_name_prefix'];
769 $glob = @glob($dir . $prefix . '--*');
770 if ($glob === false) {
771 // On some systems it is impossible to distinguish between empty match and an error.
774 foreach ($glob as $file) {
775 if (is_file($file)) {
776 $fileName = basename($file);
777 $id = $this->_fileNameToId($fileName);
778 $metadatas = $this->_getMetadatas($id);
779 if ($metadatas === FALSE) {
782 if (time() > $metadatas['expire']) {
790 $result = array_unique(array_merge($result, $metadatas['tags']));
794 foreach ($tags as $tag) {
795 if (!in_array($tag, $metadatas['tags'])) {
806 foreach ($tags as $tag) {
807 if (in_array($tag, $metadatas['tags'])) {
818 foreach ($tags as $tag) {
819 if (in_array($tag, $metadatas['tags'])) {
829 Zend_Cache::throwException('Invalid mode for _get() method');
833 if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
835 $recursiveRs = $this->_get($file . DIRECTORY_SEPARATOR, $mode, $tags);
836 if ($recursiveRs === false) {
837 $this->_log('Zend_Cache_Backend_File::_get() / recursive call : can\'t list entries of "'.$file.'"');
839 $result = array_unique(array_merge($result, $recursiveRs));
843 return array_unique($result);
847 * Compute & return the expire time
849 * @return int expire time (unix timestamp)
851 protected function _expireTime($lifetime)
853 if ($lifetime === null) {
856 return time() + $lifetime;
860 * Make a control key with the string containing datas
862 * @param string $data Data
863 * @param string $controlType Type of control 'md5', 'crc32' or 'strlen'
864 * @throws Zend_Cache_Exception
865 * @return string Control key
867 protected function _hash($data, $controlType)
869 switch ($controlType) {
875 return strlen($data);
877 return hash('adler32', $data);
879 Zend_Cache::throwException("Incorrect hash
function : $controlType");
884 * Transform a cache id into a file name and return it
886 * @param string $id Cache id
887 * @return string File name
889 protected function _idToFileName($id)
891 $prefix = $this->_options
['file_name_prefix'];
892 $result = $prefix . '---' . $id;
897 * Make and return a file name (with path)
899 * @param string $id Cache id
900 * @return string File name (with path)
902 protected function _file($id)
904 $path = $this->_path($id);
905 $fileName = $this->_idToFileName($id);
906 return $path . $fileName;
910 * Return the complete directory path of a filename (including hashedDirectoryStructure)
912 * @param string $id Cache id
913 * @param boolean $parts if true, returns array of directory parts instead of single string
914 * @return string Complete directory path
916 protected function _path($id, $parts = false)
918 $partsArray = array();
919 $root = $this->_options
['cache_dir'];
920 $prefix = $this->_options
['file_name_prefix'];
921 if ($this->_options
['hashed_directory_level']>0) {
922 $hash = hash('adler32', $id);
923 for ($i=0 ; $i < $this->_options
['hashed_directory_level'] ; $i++
) {
924 $root = $root . $prefix . '--' . substr($hash, 0, $i +
1) . DIRECTORY_SEPARATOR
;
925 $partsArray[] = $root;
936 * Make the directory strucuture for the given id
938 * @param string $id cache id
939 * @return boolean true
941 protected function _recursiveMkdirAndChmod($id)
943 if ($this->_options
['hashed_directory_level'] <=0) {
946 $partsArray = $this->_path($id, true);
947 foreach ($partsArray as $part) {
948 if (!is_dir($part)) {
949 @mkdir($part, $this->_options
['hashed_directory_perm']);
950 @chmod($part, $this->_options
['hashed_directory_perm']); // see #ZF-320 (this line is required in some configurations)
957 * Test if the given cache id is available (and still valid as a cache record)
959 * @param string $id Cache id
960 * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
961 * @return boolean|mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
963 protected function _test($id, $doNotTestCacheValidity)
965 $metadatas = $this->_getMetadatas($id);
969 if ($doNotTestCacheValidity || (time() <= $metadatas['expire'])) {
970 return $metadatas['mtime'];
976 * Return the file content of the given file
978 * @param string $file File complete path
979 * @return string File content (or false if problem)
981 protected function _fileGetContents($file)
984 if (!is_file($file)) {
987 $f = @fopen($file, 'rb');
989 if ($this->_options
['file_locking']) @flock($f, LOCK_SH
);
990 $result = stream_get_contents($f);
991 if ($this->_options
['file_locking']) @flock($f, LOCK_UN
);
998 * Put the given string into the given file
1000 * @param string $file File complete path
1001 * @param string $string String to put in file
1002 * @return boolean true if no problem
1004 protected function _filePutContents($file, $string)
1007 $f = @fopen($file, 'ab+');
1009 if ($this->_options
['file_locking']) @flock($f, LOCK_EX
);
1012 $tmp = @fwrite($f, $string);
1013 if (!($tmp === FALSE)) {
1018 @chmod($file, $this->_options
['cache_file_perm']);
1023 * Transform a file name into cache id and return it
1025 * @param string $fileName File name
1026 * @return string Cache id
1028 protected function _fileNameToId($fileName)
1030 $prefix = $this->_options
['file_name_prefix'];
1031 return preg_replace('~^' . $prefix . '---(.*)$~', '$1', $fileName);