Après la mise à jour Squeeze, bug php :
[auf_bulletin.git] / lodel-0.9 / scripts / Cache / Lite.php
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 * @version $Id: Lite.php,v 1.51 2008/06/08 08:46:22 tacker Exp $
23 * @author Fabien MARTY <fab@php.net>
24 */
25
26 define('CACHE_LITE_ERROR_RETURN', 1);
27 define('CACHE_LITE_ERROR_DIE', 8);
28
29 class 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 // --- Public methods ---
252
253 /**
254 * Constructor
255 *
256 * $options is an assoc. Available options are :
257 * $options = array(
258 * 'cacheDir' => directory where to put the cache files (string),
259 * 'caching' => enable / disable caching (boolean),
260 * 'lifeTime' => cache lifetime in seconds (int),
261 * 'fileLocking' => enable / disable fileLocking (boolean),
262 * 'writeControl' => enable / disable write control (boolean),
263 * 'readControl' => enable / disable read control (boolean),
264 * 'readControlType' => type of read control 'crc32', 'md5', 'strlen' (string),
265 * 'pearErrorMode' => pear error mode (when raiseError is called) (cf PEAR doc) (int),
266 * 'memoryCaching' => enable / disable memory caching (boolean),
267 * 'onlyMemoryCaching' => enable / disable only memory caching (boolean),
268 * 'memoryCachingLimit' => max nbr of records to store into memory caching (int),
269 * 'fileNameProtection' => enable / disable automatic file name protection (boolean),
270 * 'automaticSerialization' => enable / disable automatic serialization (boolean),
271 * 'automaticCleaningFactor' => distable / tune automatic cleaning process (int),
272 * 'hashedDirectoryLevel' => level of the hashed directory system (int),
273 * 'hashedDirectoryUmask' => umask for hashed directory structure (int),
274 * 'errorHandlingAPIBreak' => API break for better error handling ? (boolean)
275 * );
276 *
277 * @param array $options options
278 * @access public
279 */
280 function Cache_Lite($options = array(NULL))
281 {
282 foreach($options as $key => $value) {
283 $this->setOption($key, $value);
284 }
285 }
286
287 /**
288 * Generic way to set a Cache_Lite option
289 *
290 * see Cache_Lite constructor for available options
291 *
292 * @var string $name name of the option
293 * @var mixed $value value of the option
294 * @access public
295 */
296 function setOption($name, $value)
297 {
298 $availableOptions = array('errorHandlingAPIBreak', 'hashedDirectoryUmask', 'hashedDirectoryLevel', 'automaticCleaningFactor', 'automaticSerialization', 'fileNameProtection', 'memoryCaching', 'onlyMemoryCaching', 'memoryCachingLimit', 'cacheDir', 'caching', 'lifeTime', 'fileLocking', 'writeControl', 'readControl', 'readControlType', 'pearErrorMode');
299 if (in_array($name, $availableOptions)) {
300 $property = '_'.$name;
301 $this->$property = $value;
302 }
303 }
304
305 /**
306 * Test if a cache is available and (if yes) return it
307 *
308 * @param string $id cache id
309 * @param string $group name of the cache group
310 * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
311 * @return string data of the cache (else : false)
312 * @access public
313 */
314 function get($id, $group = 'default', $doNotTestCacheValidity = false)
315 {
316 $this->_id = $id;
317 $this->_group = $group;
318 $data = false;
319 if ($this->_caching) {
320 $this->_setRefreshTime();
321 $this->_setFileName($id, $group);
322 clearstatcache();
323 if ($this->_memoryCaching) {
324 if (isset($this->_memoryCachingArray[$this->_file])) {
325 if ($this->_automaticSerialization) {
326 return unserialize($this->_memoryCachingArray[$this->_file]);
327 }
328 return $this->_memoryCachingArray[$this->_file];
329 }
330 if ($this->_onlyMemoryCaching) {
331 return false;
332 }
333 }
334 if (($doNotTestCacheValidity) || (is_null($this->_refreshTime))) {
335 if (file_exists($this->_file)) {
336 $data = $this->_read();
337 }
338 } else {
339 if ((file_exists($this->_file)) && (@filemtime($this->_file) > $this->_refreshTime)) {
340 $data = $this->_read();
341 }
342 }
343 if (($data) and ($this->_memoryCaching)) {
344 $this->_memoryCacheAdd($data);
345 }
346 if (($this->_automaticSerialization) and (is_string($data))) {
347 $data = unserialize($data);
348 }
349 return $data;
350 }
351 return false;
352 }
353
354 /**
355 * Save some data in a cache file
356 *
357 * @param string $data data to put in cache (can be another type than strings if automaticSerialization is on)
358 * @param string $id cache id
359 * @param string $group name of the cache group
360 * @return boolean true if no problem (else : false or a PEAR_Error object)
361 * @access public
362 */
363 function save($data, $id = NULL, $group = 'default')
364 {
365 if ($this->_caching) {
366 if ($this->_automaticSerialization) {
367 $data = serialize($data);
368 }
369 if (isset($id)) {
370 $this->_setFileName($id, $group);
371 }
372 if ($this->_memoryCaching) {
373 $this->_memoryCacheAdd($data);
374 if ($this->_onlyMemoryCaching) {
375 return true;
376 }
377 }
378 if ($this->_automaticCleaningFactor>0) {
379 $rand = rand(1, $this->_automaticCleaningFactor);
380 if ($rand==1) {
381 $this->clean(false, 'old');
382 }
383 }
384 if ($this->_writeControl) {
385 $res = $this->_writeAndControl($data);
386 if (is_bool($res)) {
387 if ($res) {
388 return true;
389 }
390 // if $res if false, we need to invalidate the cache
391 @touch($this->_file, time() - 2*abs($this->_lifeTime));
392 return false;
393 }
394 } else {
395 $res = $this->_write($data);
396 }
397 if (is_object($res)) {
398 // $res is a PEAR_Error object
399 if (!($this->_errorHandlingAPIBreak)) {
400 return false; // we return false (old API)
401 }
402 }
403 return $res;
404 }
405 return false;
406 }
407
408 /**
409 * Remove a cache file
410 *
411 * @param string $id cache id
412 * @param string $group name of the cache group
413 * @param boolean $checkbeforeunlink check if file exists before removing it
414 * @return boolean true if no problem
415 * @access public
416 */
417 function remove($id, $group = 'default', $checkbeforeunlink = false)
418 {
419 $this->_setFileName($id, $group);
420 if ($this->_memoryCaching) {
421 if (isset($this->_memoryCachingArray[$this->_file])) {
422 unset($this->_memoryCachingArray[$this->_file]);
423 $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1;
424 }
425 if ($this->_onlyMemoryCaching) {
426 return true;
427 }
428 }
429 if ( $checkbeforeunlink ) {
430 if (!file_exists($this->_file)) return true;
431 }
432 return $this->_unlink($this->_file);
433 }
434
435 /**
436 * Clean the cache
437 *
438 * if no group is specified all cache files will be destroyed
439 * else only cache files of the specified group will be destroyed
440 *
441 * @param string $group name of the cache group
442 * @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup',
443 * 'callback_myFunction'
444 * @return boolean true if no problem
445 * @access public
446 */
447 function clean($group = false, $mode = 'ingroup')
448 {
449 return $this->_cleanDir($this->_cacheDir, $group, $mode);
450 }
451
452 /**
453 * Set to debug mode
454 *
455 * When an error is found, the script will stop and the message will be displayed
456 * (in debug mode only).
457 *
458 * @access public
459 */
460 function setToDebug()
461 {
462 $this->setOption('pearErrorMode', CACHE_LITE_ERROR_DIE);
463 }
464
465 /**
466 * Set a new life time
467 *
468 * @param int $newLifeTime new life time (in seconds)
469 * @access public
470 */
471 function setLifeTime($newLifeTime)
472 {
473 $this->_lifeTime = $newLifeTime;
474 $this->_setRefreshTime();
475 }
476
477 /**
478 * Save the state of the caching memory array into a cache file cache
479 *
480 * @param string $id cache id
481 * @param string $group name of the cache group
482 * @access public
483 */
484 function saveMemoryCachingState($id, $group = 'default')
485 {
486 if ($this->_caching) {
487 $array = array(
488 'counter' => $this->_memoryCachingCounter,
489 'array' => $this->_memoryCachingArray
490 );
491 $data = serialize($array);
492 $this->save($data, $id, $group);
493 }
494 }
495
496 /**
497 * Load the state of the caching memory array from a given cache file cache
498 *
499 * @param string $id cache id
500 * @param string $group name of the cache group
501 * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
502 * @access public
503 */
504 function getMemoryCachingState($id, $group = 'default', $doNotTestCacheValidity = false)
505 {
506 if ($this->_caching) {
507 if ($data = $this->get($id, $group, $doNotTestCacheValidity)) {
508 $array = unserialize($data);
509 $this->_memoryCachingCounter = $array['counter'];
510 $this->_memoryCachingArray = $array['array'];
511 }
512 }
513 }
514
515 /**
516 * Return the cache last modification time
517 *
518 * BE CAREFUL : THIS METHOD IS FOR HACKING ONLY !
519 *
520 * @return int last modification time
521 */
522 function lastModified()
523 {
524 return @filemtime($this->_file);
525 }
526
527 /**
528 * Trigger a PEAR error
529 *
530 * To improve performances, the PEAR.php file is included dynamically.
531 * The file is so included only when an error is triggered. So, in most
532 * cases, the file isn't included and perfs are much better.
533 *
534 * @param string $msg error message
535 * @param int $code error code
536 * @access public
537 */
538 function raiseError($msg, $code)
539 {
540 include_once('PEAR/PEAR.php');
541 /*return PEAR::raiseError($msg, $code, $this->_pearErrorMode);*/
542 }
543
544 /**
545 * Extend the life of a valid cache file
546 *
547 * see http://pear.php.net/bugs/bug.php?id=6681
548 *
549 * @access public
550 */
551 function extendLife()
552 {
553 @touch($this->_file);
554 }
555
556 // --- Private methods ---
557
558 /**
559 * Compute & set the refresh time
560 *
561 * @access private
562 */
563 function _setRefreshTime()
564 {
565 if (is_null($this->_lifeTime)) {
566 $this->_refreshTime = null;
567 } else {
568 $this->_refreshTime = time() - $this->_lifeTime;
569 }
570 }
571
572 /**
573 * Remove a file
574 *
575 * @param string $file complete file path and name
576 * @return boolean true if no problem
577 * @access private
578 */
579 function _unlink($file)
580 {
581 if (!@unlink($file)) {
582 return $this->raiseError('Cache_Lite : Unable to remove cache !', -3);
583 }
584 return true;
585 }
586
587 /**
588 * Recursive function for cleaning cache file in the given directory
589 *
590 * @param string $dir directory complete path (with a trailing slash)
591 * @param string $group name of the cache group
592 * @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup',
593 'callback_myFunction'
594 * @return boolean true if no problem
595 * @access private
596 */
597 function _cleanDir($dir, $group = false, $mode = 'ingroup')
598 {
599 if ($this->_fileNameProtection) {
600 $motif = ($group) ? 'cache_'.md5($group).'_' : 'cache_';
601 } else {
602 $motif = ($group) ? 'cache_'.$group.'_' : 'cache_';
603 }
604 if ($this->_memoryCaching) {
605 foreach($this->_memoryCachingArray as $key => $v) {
606 if (strpos($key, $motif) !== false) {
607 unset($this->_memoryCachingArray[$key]);
608 $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1;
609 }
610 }
611 if ($this->_onlyMemoryCaching) {
612 return true;
613 }
614 }
615 if (!($dh = opendir($dir))) {
616 return $this->raiseError('Cache_Lite : Unable to open cache directory !', -4);
617 }
618 $result = true;
619 while ($file = readdir($dh)) {
620 if (($file != '.') && ($file != '..')) {
621 if (substr($file, 0, 6)=='cache_') {
622 $file2 = $dir . $file;
623 if (is_file($file2)) {
624 switch (substr($mode, 0, 9)) {
625 case 'old':
626 // files older than lifeTime get deleted from cache
627 if (!is_null($this->_lifeTime)) {
628 if ((mktime() - @filemtime($file2)) > $this->_lifeTime) {
629 $result = ($result and ($this->_unlink($file2)));
630 }
631 }
632 break;
633 case 'notingrou':
634 if (strpos($file2, $motif) === false) {
635 $result = ($result and ($this->_unlink($file2)));
636 }
637 break;
638 case 'callback_':
639 $func = substr($mode, 9, strlen($mode) - 9);
640 if ($func($file2, $group)) {
641 $result = ($result and ($this->_unlink($file2)));
642 }
643 break;
644 case 'ingroup':
645 default:
646 if (strpos($file2, $motif) !== false) {
647 $result = ($result and ($this->_unlink($file2)));
648 }
649 break;
650 }
651 }
652 if ((is_dir($file2)) and ($this->_hashedDirectoryLevel>0)) {
653 $result = ($result and ($this->_cleanDir($file2 . '/', $group, $mode)));
654 }
655 }
656 }
657 }
658 return $result;
659 }
660
661 /**
662 * Add some date in the memory caching array
663 *
664 * @param string $data data to cache
665 * @access private
666 */
667 function _memoryCacheAdd($data)
668 {
669 $this->_memoryCachingArray[$this->_file] = $data;
670 if ($this->_memoryCachingCounter >= $this->_memoryCachingLimit) {
671 list($key, ) = each($this->_memoryCachingArray);
672 unset($this->_memoryCachingArray[$key]);
673 } else {
674 $this->_memoryCachingCounter = $this->_memoryCachingCounter + 1;
675 }
676 }
677
678 /**
679 * Make a file name (with path)
680 *
681 * @param string $id cache id
682 * @param string $group name of the group
683 * @access private
684 */
685 function _setFileName($id, $group)
686 {
687
688 if ($this->_fileNameProtection) {
689 $suffix = 'cache_'.md5($group).'_'.md5($id);
690 } else {
691 $suffix = 'cache_'.$group.'_'.$id;
692 }
693 $root = $this->_cacheDir;
694 if ($this->_hashedDirectoryLevel>0) {
695 $hash = md5($suffix);
696 for ($i=0 ; $i<$this->_hashedDirectoryLevel ; $i++) {
697 $root = $root . 'cache_' . substr($hash, 0, $i + 1) . '/';
698 }
699 }
700 $this->_fileName = $suffix;
701 $this->_file = $root.$suffix;
702 }
703
704 /**
705 * Read the cache file and return the content
706 *
707 * @return string content of the cache file (else : false or a PEAR_Error object)
708 * @access private
709 */
710 function _read()
711 {
712 $fp = @fopen($this->_file, "rb");
713 if ($this->_fileLocking) @flock($fp, LOCK_SH);
714 if ($fp) {
715 clearstatcache();
716 $length = @filesize($this->_file);
717 $mqr = get_magic_quotes_runtime();
718 set_magic_quotes_runtime(0);
719 if ($this->_readControl) {
720 $hashControl = @fread($fp, 32);
721 $length = $length - 32;
722 }
723 if ($length) {
724 $data = @fread($fp, $length);
725 } else {
726 $data = '';
727 }
728 set_magic_quotes_runtime($mqr);
729 if ($this->_fileLocking) @flock($fp, LOCK_UN);
730 @fclose($fp);
731 if ($this->_readControl) {
732 $hashData = $this->_hash($data, $this->_readControlType);
733 if ($hashData != $hashControl) {
734 if (!(is_null($this->_lifeTime))) {
735 @touch($this->_file, time() - 2*abs($this->_lifeTime));
736 } else {
737 @unlink($this->_file);
738 }
739 return false;
740 }
741 }
742 return $data;
743 }
744 return $this->raiseError('Cache_Lite : Unable to read cache !', -2);
745 }
746
747 /**
748 * Write the given data in the cache file
749 *
750 * @param string $data data to put in cache
751 * @return boolean true if ok (a PEAR_Error object else)
752 * @access private
753 */
754 function _write($data)
755 {
756 if ($this->_hashedDirectoryLevel > 0) {
757 $hash = md5($this->_fileName);
758 $root = $this->_cacheDir;
759 for ($i=0 ; $i<$this->_hashedDirectoryLevel ; $i++) {
760 $root = $root . 'cache_' . substr($hash, 0, $i + 1) . '/';
761 if (!(@is_dir($root))) {
762 @mkdir($root, $this->_hashedDirectoryUmask);
763 }
764 }
765 }
766 $fp = @fopen($this->_file, "wb");
767 if ($fp) {
768 if ($this->_fileLocking) @flock($fp, LOCK_EX);
769 if ($this->_readControl) {
770 @fwrite($fp, $this->_hash($data, $this->_readControlType), 32);
771 }
772 $mqr = get_magic_quotes_runtime();
773 set_magic_quotes_runtime(0);
774 @fwrite($fp, $data);
775 set_magic_quotes_runtime($mqr);
776 if ($this->_fileLocking) @flock($fp, LOCK_UN);
777 @fclose($fp);
778 return true;
779 }
780 return $this->raiseError('Cache_Lite : Unable to write cache file : '.$this->_file, -1);
781 }
782
783 /**
784 * Write the given data in the cache file and control it just after to avoir corrupted cache entries
785 *
786 * @param string $data data to put in cache
787 * @return boolean true if the test is ok (else : false or a PEAR_Error object)
788 * @access private
789 */
790 function _writeAndControl($data)
791 {
792 $result = $this->_write($data);
793 if (is_object($result)) {
794 return $result; # We return the PEAR_Error object
795 }
796 $dataRead = $this->_read();
797 if (is_object($dataRead)) {
798 return $dataRead; # We return the PEAR_Error object
799 }
800 if ((is_bool($dataRead)) && (!$dataRead)) {
801 return false;
802 }
803 return ($dataRead==$data);
804 }
805
806 /**
807 * Make a control key with the string containing datas
808 *
809 * @param string $data data
810 * @param string $controlType type of control 'md5', 'crc32' or 'strlen'
811 * @return string control key
812 * @access private
813 */
814 function _hash($data, $controlType)
815 {
816 switch ($controlType) {
817 case 'md5':
818 return md5($data);
819 case 'crc32':
820 return sprintf('% 32d', crc32($data));
821 case 'strlen':
822 return sprintf('% 32d', strlen($data));
823 default:
824 return $this->raiseError('Unknown controlType ! (available values are only \'md5\', \'crc32\', \'strlen\')', -5);
825 }
826 }
827
828 }
829
830 ?>