00001 <?php
00028 class Zend_Cache_Core
00029 {
00035 protected $_backend = null;
00036
00077 protected $_options = array(
00078 'write_control' => true,
00079 'caching' => true,
00080 'cache_id_prefix' => null,
00081 'automatic_serialization' => false,
00082 'automatic_cleaning_factor' => 10,
00083 'lifetime' => 3600,
00084 'logging' => false,
00085 'logger' => null,
00086 'ignore_user_abort' => false
00087 );
00088
00094 protected static $_directivesList = array('lifetime', 'logging', 'logger');
00095
00101 protected $_specificOptions = array();
00102
00108 private $_lastId = null;
00109
00115 protected $_extendedBackend = false;
00116
00122 protected $_backendCapabilities = array();
00123
00131 public function __construct($options = array())
00132 {
00133 if ($options instanceof Zend_Config) {
00134 $options = $options->toArray();
00135 }
00136 if (!is_array($options)) {
00137 Zend_Cache::throwException("Options passed were not an array"
00138 . " or Zend_Config instance.");
00139 }
00140 while (list($name, $value) = each($options)) {
00141 $this->setOption($name, $value);
00142 }
00143 $this->_loggerSanity();
00144 }
00145
00152 public function setConfig(Zend_Config $config)
00153 {
00154 $options = $config->toArray();
00155 while (list($name, $value) = each($options)) {
00156 $this->setOption($name, $value);
00157 }
00158 return $this;
00159 }
00160
00168 public function setBackend(Zend_Cache_Backend $backendObject)
00169 {
00170 $this->_backend= $backendObject;
00171
00172
00173 $directives = array();
00174 foreach (Zend_Cache_Core::$_directivesList as $directive) {
00175 $directives[$directive] = $this->_options[$directive];
00176 }
00177 $this->_backend->setDirectives($directives);
00178 if (in_array('Zend_Cache_Backend_ExtendedInterface', class_implements($this->_backend))) {
00179 $this->_extendedBackend = true;
00180 $this->_backendCapabilities = $this->_backend->getCapabilities();
00181 }
00182
00183 }
00184
00190 public function getBackend()
00191 {
00192 return $this->_backend;
00193 }
00194
00205 public function setOption($name, $value)
00206 {
00207 if (!is_string($name)) {
00208 Zend_Cache::throwException("Incorrect option name : $name");
00209 }
00210 $name = strtolower($name);
00211 if (array_key_exists($name, $this->_options)) {
00212
00213 $this->_setOption($name, $value);
00214 return;
00215 }
00216 if (array_key_exists($name, $this->_specificOptions)) {
00217
00218 $this->_specificOptions[$name] = $value;
00219 return;
00220 }
00221 }
00222
00230 public function getOption($name)
00231 {
00232 if (is_string($name)) {
00233 $name = strtolower($name);
00234 if (array_key_exists($name, $this->_options)) {
00235
00236 return $this->_options[$name];
00237 }
00238 if (array_key_exists($name, $this->_specificOptions)) {
00239
00240 return $this->_specificOptions[$name];
00241 }
00242 }
00243 Zend_Cache::throwException("Incorrect option name : $name");
00244 }
00245
00254 private function _setOption($name, $value)
00255 {
00256 if (!is_string($name) || !array_key_exists($name, $this->_options)) {
00257 Zend_Cache::throwException("Incorrect option name : $name");
00258 }
00259 $this->_options[$name] = $value;
00260 }
00261
00270 public function setLifetime($newLifetime)
00271 {
00272 $this->_options['lifetime'] = $newLifetime;
00273 $this->_backend->setDirectives(array(
00274 'lifetime' => $newLifetime
00275 ));
00276 }
00277
00286 public function load($id, $doNotTestCacheValidity = false, $doNotUnserialize = false)
00287 {
00288 if (!$this->_options['caching']) {
00289 return false;
00290 }
00291 $id = $this->_id($id);
00292 $this->_lastId = $id;
00293 self::_validateIdOrTag($id);
00294 $data = $this->_backend->load($id, $doNotTestCacheValidity);
00295 if ($data===false) {
00296
00297 return false;
00298 }
00299 if ((!$doNotUnserialize) && $this->_options['automatic_serialization']) {
00300
00301 return unserialize($data);
00302 }
00303 return $data;
00304 }
00305
00312 public function test($id)
00313 {
00314 if (!$this->_options['caching']) {
00315 return false;
00316 }
00317 $id = $this->_id($id);
00318 self::_validateIdOrTag($id);
00319 $this->_lastId = $id;
00320 return $this->_backend->test($id);
00321 }
00322
00334 public function save($data, $id = null, $tags = array(), $specificLifetime = false, $priority = 8)
00335 {
00336 if (!$this->_options['caching']) {
00337 return true;
00338 }
00339 if ($id === null) {
00340 $id = $this->_lastId;
00341 } else {
00342 $id = $this->_id($id);
00343 }
00344 self::_validateIdOrTag($id);
00345 self::_validateTagsArray($tags);
00346 if ($this->_options['automatic_serialization']) {
00347
00348 $data = serialize($data);
00349 } else {
00350 if (!is_string($data)) {
00351 Zend_Cache::throwException("Datas must be string or set automatic_serialization = true");
00352 }
00353 }
00354
00355 if ($this->_options['automatic_cleaning_factor'] > 0) {
00356 $rand = rand(1, $this->_options['automatic_cleaning_factor']);
00357 if ($rand==1) {
00358 if ($this->_extendedBackend) {
00359
00360 if ($this->_backendCapabilities['automatic_cleaning']) {
00361 $this->clean(Zend_Cache::CLEANING_MODE_OLD);
00362 } else {
00363 $this->_log('Zend_Cache_Core::save() / automatic cleaning is not available/necessary with this backend');
00364 }
00365 } else {
00366
00367 if (method_exists($this->_backend, 'isAutomaticCleaningAvailable') && ($this->_backend->isAutomaticCleaningAvailable())) {
00368 $this->clean(Zend_Cache::CLEANING_MODE_OLD);
00369 } else {
00370 $this->_log('Zend_Cache_Core::save() / automatic cleaning is not available/necessary with this backend');
00371 }
00372 }
00373 }
00374 }
00375 if ($this->_options['ignore_user_abort']) {
00376 $abort = ignore_user_abort(true);
00377 }
00378 if (($this->_extendedBackend) && ($this->_backendCapabilities['priority'])) {
00379 $result = $this->_backend->save($data, $id, $tags, $specificLifetime, $priority);
00380 } else {
00381 $result = $this->_backend->save($data, $id, $tags, $specificLifetime);
00382 }
00383 if ($this->_options['ignore_user_abort']) {
00384 ignore_user_abort($abort);
00385 }
00386 if (!$result) {
00387
00388 if ($this->_options['logging']) {
00389 $this->_log("Zend_Cache_Core::save() : impossible to save cache (id=$id)");
00390 }
00391 $this->remove($id);
00392 return false;
00393 }
00394 if ($this->_options['write_control']) {
00395 $data2 = $this->_backend->load($id, true);
00396 if ($data!=$data2) {
00397 $this->_log('Zend_Cache_Core::save() / write_control : written and read data do not match');
00398 $this->_backend->remove($id);
00399 return false;
00400 }
00401 }
00402 return true;
00403 }
00404
00411 public function remove($id)
00412 {
00413 if (!$this->_options['caching']) {
00414 return true;
00415 }
00416 $id = $this->_id($id);
00417 self::_validateIdOrTag($id);
00418 return $this->_backend->remove($id);
00419 }
00420
00439 public function clean($mode = 'all', $tags = array())
00440 {
00441 if (!$this->_options['caching']) {
00442 return true;
00443 }
00444 if (!in_array($mode, array(Zend_Cache::CLEANING_MODE_ALL,
00445 Zend_Cache::CLEANING_MODE_OLD,
00446 Zend_Cache::CLEANING_MODE_MATCHING_TAG,
00447 Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG,
00448 Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG))) {
00449 Zend_Cache::throwException('Invalid cleaning mode');
00450 }
00451 self::_validateTagsArray($tags);
00452 return $this->_backend->clean($mode, $tags);
00453 }
00454
00463 public function getIdsMatchingTags($tags = array())
00464 {
00465 if (!$this->_extendedBackend) {
00466 Zend_Cache::throwException('Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available');
00467 }
00468 if (!($this->_backendCapabilities['tags'])) {
00469 Zend_Cache::throwException('tags are not supported by the current backend');
00470 }
00471 return $this->_backend->getIdsMatchingTags($tags);
00472 }
00473
00482 public function getIdsNotMatchingTags($tags = array())
00483 {
00484 if (!$this->_extendedBackend) {
00485 Zend_Cache::throwException('Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available');
00486 }
00487 if (!($this->_backendCapabilities['tags'])) {
00488 Zend_Cache::throwException('tags are not supported by the current backend');
00489 }
00490 return $this->_backend->getIdsNotMatchingTags($tags);
00491 }
00492
00498 public function getIds()
00499 {
00500 if (!$this->_extendedBackend) {
00501 Zend_Cache::throwException('Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available');
00502 }
00503 $array = $this->_backend->getIds();
00504 if ((!isset($this->_options['cache_id_prefix'])) || ($this->_options['cache_id_prefix'] == '')) return $array;
00505
00506 $res = array();
00507 while (list(,$id) = each($array)) {
00508 if (strpos($id, $this->_options['cache_id_prefix']) === 0) {
00509 $res[] = preg_replace("~^{$this->_options['cache_id_prefix']}~", '', $id);
00510 } else {
00511 $res[] = $id;
00512 }
00513 }
00514 return $res;
00515 }
00516
00522 public function getTags()
00523 {
00524 if (!$this->_extendedBackend) {
00525 Zend_Cache::throwException('Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available');
00526 }
00527 if (!($this->_backendCapabilities['tags'])) {
00528 Zend_Cache::throwException('tags are not supported by the current backend');
00529 }
00530 return $this->_backend->getTags();
00531 }
00532
00538 public function getFillingPercentage()
00539 {
00540 if (!$this->_extendedBackend) {
00541 Zend_Cache::throwException('Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available');
00542 }
00543 return $this->_backend->getFillingPercentage();
00544 }
00545
00557 public function getMetadatas($id)
00558 {
00559 if (!$this->_extendedBackend) {
00560 Zend_Cache::throwException('Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available');
00561 }
00562 $id = $this->_id($id);
00563 return $this->_backend->getMetadatas($id);
00564 }
00565
00573 public function touch($id, $extraLifetime)
00574 {
00575 if (!$this->_extendedBackend) {
00576 Zend_Cache::throwException('Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available');
00577 }
00578 $id = $this->_id($id);
00579 return $this->_backend->touch($id, $extraLifetime);
00580 }
00581
00591 protected static function _validateIdOrTag($string)
00592 {
00593 if (!is_string($string)) {
00594 Zend_Cache::throwException('Invalid id or tag : must be a string');
00595 }
00596 if (substr($string, 0, 9) == 'internal-') {
00597 Zend_Cache::throwException('"internal-*" ids or tags are reserved');
00598 }
00599 if (!preg_match('~^[\w]+$~D', $string)) {
00600 Zend_Cache::throwException("Invalid id or tag '$string' : must use only [a-zA-Z0-9_]");
00601 }
00602 }
00603
00613 protected static function _validateTagsArray($tags)
00614 {
00615 if (!is_array($tags)) {
00616 Zend_Cache::throwException('Invalid tags array : must be an array');
00617 }
00618 foreach($tags as $tag) {
00619 self::_validateIdOrTag($tag);
00620 }
00621 reset($tags);
00622 }
00623
00632 protected function _loggerSanity()
00633 {
00634 if (!isset($this->_options['logging']) || !$this->_options['logging']) {
00635 return;
00636 }
00637
00638 if (isset($this->_options['logger']) && $this->_options['logger'] instanceof Zend_Log) {
00639 return;
00640 }
00641
00642
00643 require_once 'Zend/Log/Writer/Stream.php';
00644 $logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output'));
00645 $this->_options['logger'] = $logger;
00646 }
00647
00655 protected function _log($message, $priority = 4)
00656 {
00657 if (!$this->_options['logging']) {
00658 return;
00659 }
00660 if (!(isset($this->_options['logger']) || $this->_options['logger'] instanceof Zend_Log)) {
00661 Zend_Cache::throwException('Logging is enabled but logger is not set');
00662 }
00663 $logger = $this->_options['logger'];
00664 $logger->log($message, $priority);
00665 }
00666
00675 protected function _id($id)
00676 {
00677 if (($id !== null) && isset($this->_options['cache_id_prefix'])) {
00678 return $this->_options['cache_id_prefix'] . $id;
00679 }
00680 return $id;
00681 }
00682
00683 }