source: branches/version-2_13-dev/data/module/Cache/Lite.php @ 23600

Revision 23600, 27.8 KB checked in by kimoto, 10 years ago (diff)

#2609 モジュールのバグfix

XML_Util 1.2.3
Mobile_Detect 2.8.3
Cache_Lite 1.7.16
Archive_Tar 1.3.12

Line 
1<?php
2
3/**
4* Fast, light and safe Cache Class
5*
6* Cache_Lite is a fast, light and safe cache system. It's optimized
7* for file containers. It is fast and safe (because it uses file
8* locking and/or anti-corruption tests).
9*
10* There are some examples in the 'docs/examples' file
11* Technical choices are described in the 'docs/technical' file
12*
13* Memory Caching is from an original idea of
14* Mike BENOIT <ipso@snappymail.ca>
15*
16* Nota : A chinese documentation (thanks to RainX <china_1982@163.com>) is
17* available at :
18* http://rainx.phpmore.com/manual/cache_lite.html
19*
20* @package Cache_Lite
21* @category Caching
22* @author Fabien MARTY <fab@php.net>
23* @author Markus Tacker <tacker@php.net>
24*/
25
26define('CACHE_LITE_ERROR_RETURN', 1);
27define('CACHE_LITE_ERROR_DIE', 8);
28
29class Cache_Lite
30{
31
32    // --- Private properties ---
33
34    /**
35    * Directory where to put the cache files
36    * (make sure to add a trailing slash)
37    *
38    * @var string $_cacheDir
39    */
40    var $_cacheDir = '/tmp/';
41
42    /**
43    * Enable / disable caching
44    *
45    * (can be very usefull for the debug of cached scripts)
46    *
47    * @var boolean $_caching
48    */
49    var $_caching = true;
50
51    /**
52    * Cache lifetime (in seconds)
53    *
54    * If null, the cache is valid forever.
55    *
56    * @var int $_lifeTime
57    */
58    var $_lifeTime = 3600;
59
60    /**
61    * Enable / disable fileLocking
62    *
63    * (can avoid cache corruption under bad circumstances)
64    *
65    * @var boolean $_fileLocking
66    */
67    var $_fileLocking = true;
68
69    /**
70    * Timestamp of the last valid cache
71    *
72    * @var int $_refreshTime
73    */
74    var $_refreshTime;
75
76    /**
77    * File name (with path)
78    *
79    * @var string $_file
80    */
81    var $_file;
82   
83    /**
84    * File name (without path)
85    *
86    * @var string $_fileName
87    */
88    var $_fileName;
89
90    /**
91    * Enable / disable write control (the cache is read just after writing to detect corrupt entries)
92    *
93    * Enable write control will lightly slow the cache writing but not the cache reading
94    * Write control can detect some corrupt cache files but maybe it's not a perfect control
95    *
96    * @var boolean $_writeControl
97    */
98    var $_writeControl = true;
99
100    /**
101    * Enable / disable read control
102    *
103    * If enabled, a control key is embeded in cache file and this key is compared with the one
104    * calculated after the reading.
105    *
106    * @var boolean $_writeControl
107    */
108    var $_readControl = true;
109
110    /**
111    * Type of read control (only if read control is enabled)
112    *
113    * Available values are :
114    * 'md5' for a md5 hash control (best but slowest)
115    * 'crc32' for a crc32 hash control (lightly less safe but faster, better choice)
116    * 'strlen' for a length only test (fastest)
117    *
118    * @var boolean $_readControlType
119    */
120    var $_readControlType = 'crc32';
121
122    /**
123    * Pear error mode (when raiseError is called)
124    *
125    * (see PEAR doc)
126    *
127    * @see setToDebug()
128    * @var int $_pearErrorMode
129    */
130    var $_pearErrorMode = CACHE_LITE_ERROR_RETURN;
131   
132    /**
133    * Current cache id
134    *
135    * @var string $_id
136    */
137    var $_id;
138
139    /**
140    * Current cache group
141    *
142    * @var string $_group
143    */
144    var $_group;
145
146    /**
147    * Enable / Disable "Memory Caching"
148    *
149    * NB : There is no lifetime for memory caching !
150    *
151    * @var boolean $_memoryCaching
152    */
153    var $_memoryCaching = false;
154
155    /**
156    * Enable / Disable "Only Memory Caching"
157    * (be carefull, memory caching is "beta quality")
158    *
159    * @var boolean $_onlyMemoryCaching
160    */
161    var $_onlyMemoryCaching = false;
162
163    /**
164    * Memory caching array
165    *
166    * @var array $_memoryCachingArray
167    */
168    var $_memoryCachingArray = array();
169
170    /**
171    * Memory caching counter
172    *
173    * @var int $memoryCachingCounter
174    */
175    var $_memoryCachingCounter = 0;
176
177    /**
178    * Memory caching limit
179    *
180    * @var int $memoryCachingLimit
181    */
182    var $_memoryCachingLimit = 1000;
183   
184    /**
185    * File Name protection
186    *
187    * if set to true, you can use any cache id or group name
188    * if set to false, it can be faster but cache ids and group names
189    * will be used directly in cache file names so be carefull with
190    * special characters...
191    *
192    * @var boolean $fileNameProtection
193    */
194    var $_fileNameProtection = true;
195   
196    /**
197    * Enable / disable automatic serialization
198    *
199    * it can be used to save directly datas which aren't strings
200    * (but it's slower)   
201    *
202    * @var boolean $_serialize
203    */
204    var $_automaticSerialization = false;
205   
206    /**
207    * Disable / Tune the automatic cleaning process
208    *
209    * The automatic cleaning process destroy too old (for the given life time)
210    * cache files when a new cache file is written.
211    * 0               => no automatic cache cleaning
212    * 1               => systematic cache cleaning
213    * x (integer) > 1 => automatic cleaning randomly 1 times on x cache write
214    *
215    * @var int $_automaticCleaning
216    */
217    var $_automaticCleaningFactor = 0;
218   
219    /**
220    * Nested directory level
221    *
222    * Set the hashed directory structure level. 0 means "no hashed directory
223    * structure", 1 means "one level of directory", 2 means "two levels"...
224    * This option can speed up Cache_Lite only when you have many thousands of
225    * cache file. Only specific benchs can help you to choose the perfect value
226    * for you. Maybe, 1 or 2 is a good start.
227    *
228    * @var int $_hashedDirectoryLevel
229    */
230    var $_hashedDirectoryLevel = 0;
231   
232    /**
233    * Umask for hashed directory structure
234    *
235    * @var int $_hashedDirectoryUmask
236    */
237    var $_hashedDirectoryUmask = 0700;
238   
239    /**
240     * API break for error handling in CACHE_LITE_ERROR_RETURN mode
241     *
242     * In CACHE_LITE_ERROR_RETURN mode, error handling was not good because
243     * for example save() method always returned a boolean (a PEAR_Error object
244     * would be better in CACHE_LITE_ERROR_RETURN mode). To correct this without
245     * breaking the API, this option (false by default) can change this handling.
246     *
247     * @var boolean
248     */
249    var $_errorHandlingAPIBreak = false;
250   
251    var $_hashedDirectoryGroup = NULL;
252   
253    var $_cacheFileMode = NULL;
254   
255    var $_cacheFileGroup = NULL;
256   
257    // --- Public methods ---
258
259    /**
260    * Constructor
261    *
262    * $options is an assoc. Available options are :
263    * $options = array(
264    *     'cacheDir' => directory where to put the cache files (string),
265    *     'caching' => enable / disable caching (boolean),
266    *     'lifeTime' => cache lifetime in seconds (int),
267    *     'fileLocking' => enable / disable fileLocking (boolean),
268    *     'writeControl' => enable / disable write control (boolean),
269    *     'readControl' => enable / disable read control (boolean),
270    *     'readControlType' => type of read control 'crc32', 'md5', 'strlen' (string),
271    *     'pearErrorMode' => pear error mode (when raiseError is called) (cf PEAR doc) (int),
272    *     'memoryCaching' => enable / disable memory caching (boolean),
273    *     'onlyMemoryCaching' => enable / disable only memory caching (boolean),
274    *     'memoryCachingLimit' => max nbr of records to store into memory caching (int),
275    *     'fileNameProtection' => enable / disable automatic file name protection (boolean),
276    *     'automaticSerialization' => enable / disable automatic serialization (boolean),
277    *     'automaticCleaningFactor' => distable / tune automatic cleaning process (int),
278    *     'hashedDirectoryLevel' => level of the hashed directory system (int),
279    *     'hashedDirectoryUmask' => umask for hashed directory structure (int),
280    *     'errorHandlingAPIBreak' => API break for better error handling ? (boolean)
281    *     'hashedDirectoryGroup' => group of hashed directory structure (int | string) (see function chgrp)
282    *     'cacheFileMode' => filesystem mode of newly created cache files (int)
283    *     'cacheFileGroup' => group of newly created cache files (int | string) (see function chgrp)
284    * );
285    *
286    * If sys_get_temp_dir() is available and the
287    * 'cacheDir' option is not provided in the
288    * constructor options array its output is used
289    * to determine the suitable temporary directory.
290    *
291    * @see http://de.php.net/sys_get_temp_dir
292    * @see http://pear.php.net/bugs/bug.php?id=18328
293    *
294    * @param array $options options
295    * @access public
296    */
297    function Cache_Lite($options = array(NULL))
298    {
299        foreach($options as $key => $value) {
300            $this->setOption($key, $value);
301        }
302        if (!isset($options['cacheDir']) && function_exists('sys_get_temp_dir')) {
303            $this->setOption('cacheDir', sys_get_temp_dir() . DIRECTORY_SEPARATOR);
304        }
305    }
306   
307    /**
308    * Generic way to set a Cache_Lite option
309    *
310    * see Cache_Lite constructor for available options
311    *
312    * @var string $name name of the option
313    * @var mixed $value value of the option
314    * @access public
315    */
316    function setOption($name, $value)
317    {
318        $availableOptions = array('errorHandlingAPIBreak', 'hashedDirectoryUmask', 'hashedDirectoryLevel', 'automaticCleaningFactor', 'automaticSerialization', 'fileNameProtection', 'memoryCaching', 'onlyMemoryCaching', 'memoryCachingLimit', 'cacheDir', 'caching', 'lifeTime', 'fileLocking', 'writeControl', 'readControl', 'readControlType', 'pearErrorMode', 'hashedDirectoryGroup', 'cacheFileMode', 'cacheFileGroup');
319        if (in_array($name, $availableOptions)) {
320            $property = '_'.$name;
321            $this->$property = $value;
322        }
323    }
324   
325    /**
326    * Test if a cache is available and (if yes) return it
327    *
328    * @param string $id cache id
329    * @param string $group name of the cache group
330    * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
331    * @return string data of the cache (else : false)
332    * @access public
333    */
334    function get($id, $group = 'default', $doNotTestCacheValidity = false)
335    {
336        $this->_id = $id;
337        $this->_group = $group;
338        $data = false;
339        if ($this->_caching) {
340            $this->_setRefreshTime();
341            $this->_setFileName($id, $group);
342            clearstatcache();
343            if ($this->_memoryCaching) {
344                if (isset($this->_memoryCachingArray[$this->_file])) {
345                    if ($this->_automaticSerialization) {
346                        return unserialize($this->_memoryCachingArray[$this->_file]);
347                    }
348                    return $this->_memoryCachingArray[$this->_file];
349                }
350                if ($this->_onlyMemoryCaching) {
351                    return false;
352                }               
353            }
354            if (($doNotTestCacheValidity) || (is_null($this->_refreshTime))) {
355                if (file_exists($this->_file)) {
356                    $data = $this->_read();
357                }
358            } else {
359                if ((file_exists($this->_file)) && (@filemtime($this->_file) > $this->_refreshTime)) {
360                    $data = $this->_read();
361                }
362            }
363            if (($data) and ($this->_memoryCaching)) {
364                $this->_memoryCacheAdd($data);
365            }
366            if (($this->_automaticSerialization) and (is_string($data))) {
367                $data = unserialize($data);
368            }
369            return $data;
370        }
371        return false;
372    }
373   
374    /**
375    * Save some data in a cache file
376    *
377    * @param string $data data to put in cache (can be another type than strings if automaticSerialization is on)
378    * @param string $id cache id
379    * @param string $group name of the cache group
380    * @return boolean true if no problem (else : false or a PEAR_Error object)
381    * @access public
382    */
383    function save($data, $id = NULL, $group = 'default')
384    {
385        if ($this->_caching) {
386            if ($this->_automaticSerialization) {
387                $data = serialize($data);
388            }
389            if (isset($id)) {
390                $this->_setFileName($id, $group);
391            }
392            if ($this->_memoryCaching) {
393                $this->_memoryCacheAdd($data);
394                if ($this->_onlyMemoryCaching) {
395                    return true;
396                }
397            }
398            if ($this->_automaticCleaningFactor>0 && ($this->_automaticCleaningFactor==1 || mt_rand(1, $this->_automaticCleaningFactor)==1)) {
399                $this->clean(false, 'old');         
400            }
401            if ($this->_writeControl) {
402                $res = $this->_writeAndControl($data);
403                if (is_bool($res)) {
404                    if ($res) {
405                        return true; 
406                    }
407                    // if $res if false, we need to invalidate the cache
408                    @touch($this->_file, time() - 2*abs($this->_lifeTime));
409                    return false;
410                }           
411            } else {
412                $res = $this->_write($data);
413            }
414            if (is_object($res)) {
415                // $res is a PEAR_Error object
416                if (!($this->_errorHandlingAPIBreak)) {   
417                    return false; // we return false (old API)
418                }
419            }
420            return $res;
421        }
422        return false;
423    }
424
425    /**
426    * Remove a cache file
427    *
428    * @param string $id cache id
429    * @param string $group name of the cache group
430    * @param boolean $checkbeforeunlink check if file exists before removing it
431    * @return boolean true if no problem
432    * @access public
433    */
434    function remove($id, $group = 'default', $checkbeforeunlink = false)
435    {
436        $this->_setFileName($id, $group);
437        if ($this->_memoryCaching) {
438            if (isset($this->_memoryCachingArray[$this->_file])) {
439                unset($this->_memoryCachingArray[$this->_file]);
440                $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1;
441            }
442            if ($this->_onlyMemoryCaching) {
443                return true;
444            }
445        }
446        if ( $checkbeforeunlink ) {
447            if (!file_exists($this->_file)) return true;
448        }
449        return $this->_unlink($this->_file);
450    }
451
452    /**
453    * Clean the cache
454    *
455    * if no group is specified all cache files will be destroyed
456    * else only cache files of the specified group will be destroyed
457    *
458    * @param string $group name of the cache group
459    * @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup',
460    *                                        'callback_myFunction'
461    * @return boolean true if no problem
462    * @access public
463    */
464    function clean($group = false, $mode = 'ingroup')
465    {
466        return $this->_cleanDir($this->_cacheDir, $group, $mode);
467    }
468       
469    /**
470    * Set to debug mode
471    *
472    * When an error is found, the script will stop and the message will be displayed
473    * (in debug mode only).
474    *
475    * @access public
476    */
477    function setToDebug()
478    {
479        $this->setOption('pearErrorMode', CACHE_LITE_ERROR_DIE);
480    }
481
482    /**
483    * Set a new life time
484    *
485    * @param int $newLifeTime new life time (in seconds)
486    * @access public
487    */
488    function setLifeTime($newLifeTime)
489    {
490        $this->_lifeTime = $newLifeTime;
491        $this->_setRefreshTime();
492    }
493
494    /**
495    * Save the state of the caching memory array into a cache file cache
496    *
497    * @param string $id cache id
498    * @param string $group name of the cache group
499    * @access public
500    */
501    function saveMemoryCachingState($id, $group = 'default')
502    {
503        if ($this->_caching) {
504            $array = array(
505                'counter' => $this->_memoryCachingCounter,
506                'array' => $this->_memoryCachingArray
507            );
508            $data = serialize($array);
509            $this->save($data, $id, $group);
510        }
511    }
512
513    /**
514    * Load the state of the caching memory array from a given cache file cache
515    *
516    * @param string $id cache id
517    * @param string $group name of the cache group
518    * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
519    * @access public
520    */
521    function getMemoryCachingState($id, $group = 'default', $doNotTestCacheValidity = false)
522    {
523        if ($this->_caching) {
524            if ($data = $this->get($id, $group, $doNotTestCacheValidity)) {
525                $array = unserialize($data);
526                $this->_memoryCachingCounter = $array['counter'];
527                $this->_memoryCachingArray = $array['array'];
528            }
529        }
530    }
531   
532    /**
533    * Return the cache last modification time
534    *
535    * BE CAREFUL : THIS METHOD IS FOR HACKING ONLY !
536    *
537    * @return int last modification time
538    */
539    function lastModified()
540    {
541        return @filemtime($this->_file);
542    }
543   
544    /**
545    * Trigger a PEAR error
546    *
547    * To improve performances, the PEAR.php file is included dynamically.
548    * The file is so included only when an error is triggered. So, in most
549    * cases, the file isn't included and perfs are much better.
550    *
551    * @param string $msg error message
552    * @param int $code error code
553    * @access public
554    */
555    function raiseError($msg, $code)
556    {
557        include_once('PEAR.php');
558        return PEAR::raiseError($msg, $code, $this->_pearErrorMode);
559    }
560   
561    /**
562     * Extend the life of a valid cache file
563     *
564     * see http://pear.php.net/bugs/bug.php?id=6681
565     *
566     * @access public
567     */
568    function extendLife()
569    {
570        @touch($this->_file);
571    }
572   
573    // --- Private methods ---
574   
575    /**
576    * Compute & set the refresh time
577    *
578    * @access private
579    */
580    function _setRefreshTime()
581    {
582        if (is_null($this->_lifeTime)) {
583            $this->_refreshTime = null;
584        } else {
585            $this->_refreshTime = time() - $this->_lifeTime;
586        }
587    }
588   
589    /**
590    * Remove a file
591    *
592    * @param string $file complete file path and name
593    * @return boolean true if no problem
594    * @access private
595    */
596    function _unlink($file)
597    {
598        if (!@unlink($file)) {
599            return $this->raiseError('Cache_Lite : Unable to remove cache !', -3);
600        }
601        return true;       
602    }
603
604    /**
605    * Recursive function for cleaning cache file in the given directory
606    *
607    * @param string $dir directory complete path (with a trailing slash)
608    * @param string $group name of the cache group
609    * @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup',
610                                             'callback_myFunction'
611    * @return boolean true if no problem
612    * @access private
613    */
614    function _cleanDir($dir, $group = false, $mode = 'ingroup')     
615    {
616        if ($this->_fileNameProtection) {
617            $motif = ($group) ? 'cache_'.md5($group).'_' : 'cache_';
618        } else {
619            $motif = ($group) ? 'cache_'.$group.'_' : 'cache_';
620        }
621        if ($this->_memoryCaching) {
622        foreach($this->_memoryCachingArray as $key => $v) {
623                if (strpos($key, $motif) !== false) {
624                    unset($this->_memoryCachingArray[$key]);
625                    $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1;
626                }
627            }
628            if ($this->_onlyMemoryCaching) {
629                return true;
630            }
631        }
632        if (!($dh = opendir($dir))) {
633            return $this->raiseError('Cache_Lite : Unable to open cache directory !', -4);
634        }
635        $result = true;
636        while (($file = readdir($dh)) !== false) {
637            if (($file != '.') && ($file != '..')) {
638                if (substr($file, 0, 6)=='cache_') {
639                    $file2 = $dir . $file;
640                    if (is_file($file2)) {
641                        switch (substr($mode, 0, 9)) {
642                            case 'old':
643                                // files older than lifeTime get deleted from cache
644                                if (!is_null($this->_lifeTime)) {
645                                    if ((time() - @filemtime($file2)) > $this->_lifeTime) {
646                                        $result = ($result and ($this->_unlink($file2)));
647                                    }
648                                }
649                                break;
650                            case 'notingrou':
651                                if (strpos($file2, $motif) === false) {
652                                    $result = ($result and ($this->_unlink($file2)));
653                                }
654                                break;
655                            case 'callback_':
656                                $func = substr($mode, 9, strlen($mode) - 9);
657                                if ($func($file2, $group)) {
658                                    $result = ($result and ($this->_unlink($file2)));
659                                }
660                                break;
661                            case 'ingroup':
662                            default:
663                                if (strpos($file2, $motif) !== false) {
664                                    $result = ($result and ($this->_unlink($file2)));
665                                }
666                                break;
667                        }
668                    }
669                    if ((is_dir($file2)) and ($this->_hashedDirectoryLevel>0)) {
670                        $result = ($result and ($this->_cleanDir($file2 . '/', $group, $mode)));
671                    }
672                }
673            }
674        }
675        return $result;
676    }
677
678    /**
679    * Touch the cache file while are recreating it to avoid
680    * launch this task more then once when necessary
681    * When the cache recreated and Added in Cache Memory
682    * @return void
683    * @access private
684    */
685    function _touchCacheFile(){
686        if (file_exists($this->_file)) {
687            @touch($this->_file);
688        }
689    }
690    /**
691    * Add some date in the memory caching array
692    *
693    * @param string $data data to cache
694    * @access private
695    */
696    function _memoryCacheAdd($data)
697    {
698        $this->_touchCacheFile();
699        $this->_memoryCachingArray[$this->_file] = $data;
700        if ($this->_memoryCachingCounter >= $this->_memoryCachingLimit) {
701            list($key, ) = each($this->_memoryCachingArray);
702            unset($this->_memoryCachingArray[$key]);
703        } else {
704            $this->_memoryCachingCounter = $this->_memoryCachingCounter + 1;
705        }
706    }
707
708    /**
709    * Make a file name (with path)
710    *
711    * @param string $id cache id
712    * @param string $group name of the group
713    * @access private
714    */
715    function _setFileName($id, $group)
716    {
717       
718        if ($this->_fileNameProtection) {
719            $suffix = 'cache_'.md5($group).'_'.md5($id);
720        } else {
721            $suffix = 'cache_'.$group.'_'.$id;
722        }
723        $root = $this->_cacheDir;
724        if ($this->_hashedDirectoryLevel>0) {
725            $hash = md5($suffix);
726            for ($i=0 ; $i<$this->_hashedDirectoryLevel ; $i++) {
727                $root = $root . 'cache_' . substr($hash, 0, $i + 1) . '/';
728            }   
729        }
730        $this->_fileName = $suffix;
731        $this->_file = $root.$suffix;
732    }
733   
734    /**
735    * Read the cache file and return the content
736    *
737    * @return string content of the cache file (else : false or a PEAR_Error object)
738    * @access private
739    */
740    function _read()
741    {
742        $fp = @fopen($this->_file, "rb");
743        if ($fp) {
744        if ($this->_fileLocking) @flock($fp, LOCK_SH);
745            clearstatcache();
746            $length = @filesize($this->_file);
747            $mqr = get_magic_quotes_runtime();
748            if ($mqr) {
749                set_magic_quotes_runtime(0);
750            }
751            if ($this->_readControl) {
752                $hashControl = @fread($fp, 32);
753                $length = $length - 32;
754            }
755
756            if ($length) {
757                $data = '';
758                // See https://bugs.php.net/bug.php?id=30936
759                // The 8192 magic number is the chunk size used internally by PHP.
760                while(!feof($fp)) $data .= fread($fp, 8192);
761            } else {
762                $data = '';
763            }
764            if ($mqr) {
765                set_magic_quotes_runtime($mqr);
766            }
767            if ($this->_fileLocking) @flock($fp, LOCK_UN);
768            @fclose($fp);
769            if ($this->_readControl) {
770                $hashData = $this->_hash($data, $this->_readControlType);
771                if ($hashData != $hashControl) {
772                    if (!(is_null($this->_lifeTime))) {
773                        @touch($this->_file, time() - 2*abs($this->_lifeTime));
774                    } else {
775                        @unlink($this->_file);
776                    }
777                    return false;
778                }
779            }
780            return $data;
781        }
782        return $this->raiseError('Cache_Lite : Unable to read cache !', -2);
783    }
784   
785    /**
786    * Write the given data in the cache file
787    *
788    * @param string $data data to put in cache
789    * @return boolean true if ok (a PEAR_Error object else)
790    * @access private
791    */
792    function _write($data)
793    {
794        if ($this->_hashedDirectoryLevel > 0) {
795            $hash = md5($this->_fileName);
796            $root = $this->_cacheDir;
797            for ($i=0 ; $i<$this->_hashedDirectoryLevel ; $i++) {
798                $root = $root . 'cache_' . substr($hash, 0, $i + 1) . '/';
799                if (!(@is_dir($root))) {
800                    if (@mkdir($root))
801                    {
802                        @chmod($root, $this->_hashedDirectoryUmask);
803                        if (! is_null($this->_hashedDirectoryGroup))
804                            @chgrp($root, $this->_hashedDirectoryGroup);
805                    }
806                }
807            }
808        }
809        // if both _cacheFileMode and _cacheFileGroup is null, then we don't need to call
810        // file_exists (see below: if ($is_newfile) ...)
811        $is_newfile = (! is_null($this->_cacheFileMode) || !is_null($this->_cacheFileGroup))
812            && ! @file_exists($this->_file);
813        $fp = @fopen($this->_file, "wb");
814        if ($fp) {
815            if ($this->_fileLocking) @flock($fp, LOCK_EX);
816            if ($is_newfile)
817            {
818                if (! is_null($this->_cacheFileMode))
819                    @chmod($this->_file, $this->_cacheFileMode);
820                if (! is_null($this->_cacheFileGroup))
821                    @chgrp($this->_file, $this->_cacheFileGroup);
822            }
823            if ($this->_readControl) {
824                @fwrite($fp, $this->_hash($data, $this->_readControlType), 32);
825            }
826            $mqr = get_magic_quotes_runtime();
827            if ($mqr) {
828                set_magic_quotes_runtime(0);
829            }
830            @fwrite($fp, $data);
831            if ($mqr) {
832                set_magic_quotes_runtime($mqr);
833            }
834            if ($this->_fileLocking) @flock($fp, LOCK_UN);
835            @fclose($fp);
836            return true;
837        }     
838        return $this->raiseError('Cache_Lite : Unable to write cache file : '.$this->_file, -1);
839    }
840       
841    /**
842    * Write the given data in the cache file and control it just after to avoir corrupted cache entries
843    *
844    * @param string $data data to put in cache
845    * @return boolean true if the test is ok (else : false or a PEAR_Error object)
846    * @access private
847    */
848    function _writeAndControl($data)
849    {
850        $result = $this->_write($data);
851        if (is_object($result)) {
852            return $result; # We return the PEAR_Error object
853        }
854        $dataRead = $this->_read();
855        if (is_object($dataRead)) {
856            return $dataRead; # We return the PEAR_Error object
857        }
858        if ((is_bool($dataRead)) && (!$dataRead)) {
859            return false;
860        }
861        return ($dataRead==$data);
862    }
863   
864    /**
865    * Make a control key with the string containing datas
866    *
867    * @param string $data data
868    * @param string $controlType type of control 'md5', 'crc32' or 'strlen'
869    * @return string control key
870    * @access private
871    */
872    function _hash($data, $controlType)
873    {
874        switch ($controlType) {
875        case 'md5':
876            return md5($data);
877        case 'crc32':
878            return sprintf('% 32d', crc32($data));
879        case 'strlen':
880            return sprintf('% 32d', strlen($data));
881        default:
882            return $this->raiseError('Unknown controlType ! (available values are only \'md5\', \'crc32\', \'strlen\')', -5);
883        }
884    }
885   
886}
Note: See TracBrowser for help on using the repository browser.