| Drupal | PHP Cross Reference | Content Management Systems |
1 <?php 2 3 /** 4 * @file 5 * Functions and interfaces for cache handling. 6 */ 7 8 /** 9 * Gets the cache object for a cache bin. 10 * 11 * By default, this returns an instance of the DrupalDatabaseCache class. 12 * Classes implementing DrupalCacheInterface can register themselves both as a 13 * default implementation and for specific bins. 14 * 15 * @param $bin 16 * The cache bin for which the cache object should be returned. 17 * @return DrupalCacheInterface 18 * The cache object associated with the specified bin. 19 * 20 * @see DrupalCacheInterface 21 */ 22 function _cache_get_object($bin) { 23 // We do not use drupal_static() here because we do not want to change the 24 // storage of a cache bin mid-request. 25 static $cache_objects; 26 if (!isset($cache_objects[$bin])) { 27 $class = variable_get('cache_class_' . $bin); 28 if (!isset($class)) { 29 $class = variable_get('cache_default_class', 'DrupalDatabaseCache'); 30 } 31 $cache_objects[$bin] = new $class($bin); 32 } 33 return $cache_objects[$bin]; 34 } 35 36 /** 37 * Returns data from the persistent cache. 38 * 39 * Data may be stored as either plain text or as serialized data. cache_get 40 * will automatically return unserialized objects and arrays. 41 * 42 * @param $cid 43 * The cache ID of the data to retrieve. 44 * @param $bin 45 * The cache bin to store the data in. Valid core values are 'cache_block', 46 * 'cache_bootstrap', 'cache_field', 'cache_filter', 'cache_form', 47 * 'cache_menu', 'cache_page', 'cache_path', 'cache_update' or 'cache' for 48 * the default cache. 49 * 50 * @return 51 * The cache or FALSE on failure. 52 * 53 * @see cache_set() 54 */ 55 function cache_get($cid, $bin = 'cache') { 56 return _cache_get_object($bin)->get($cid); 57 } 58 59 /** 60 * Returns data from the persistent cache when given an array of cache IDs. 61 * 62 * @param $cids 63 * An array of cache IDs for the data to retrieve. This is passed by 64 * reference, and will have the IDs successfully returned from cache removed. 65 * @param $bin 66 * The cache bin where the data is stored. 67 * 68 * @return 69 * An array of the items successfully returned from cache indexed by cid. 70 */ 71 function cache_get_multiple(array &$cids, $bin = 'cache') { 72 return _cache_get_object($bin)->getMultiple($cids); 73 } 74 75 /** 76 * Stores data in the persistent cache. 77 * 78 * The persistent cache is split up into several cache bins. In the default 79 * cache implementation, each cache bin corresponds to a database table by the 80 * same name. Other implementations might want to store several bins in data 81 * structures that get flushed together. While it is not a problem for most 82 * cache bins if the entries in them are flushed before their expire time, some 83 * might break functionality or are extremely expensive to recalculate. These 84 * will be marked with a (*). The other bins expired automatically by core. 85 * Contributed modules can add additional bins and get them expired 86 * automatically by implementing hook_flush_caches(). 87 * 88 * - cache: Generic cache storage bin (used for variables, theme registry, 89 * locale date, list of simpletest tests etc). 90 * 91 * - cache_block: Stores the content of various blocks. 92 * 93 * - cache field: Stores the field data belonging to a given object. 94 * 95 * - cache_filter: Stores filtered pieces of content. 96 * 97 * - cache_form(*): Stores multistep forms. Flushing this bin means that some 98 * forms displayed to users lose their state and the data already submitted 99 * to them. 100 * 101 * - cache_menu: Stores the structure of visible navigation menus per page. 102 * 103 * - cache_page: Stores generated pages for anonymous users. It is flushed 104 * very often, whenever a page changes, at least for every ode and comment 105 * submission. This is the only bin affected by the page cache setting on 106 * the administrator panel. 107 * 108 * - cache path: Stores the system paths that have an alias. 109 * 110 * - cache update(*): Stores available releases. The update server (for 111 * example, drupal.org) needs to produce the relevant XML for every project 112 * installed on the current site. As this is different for (almost) every 113 * site, it's very expensive to recalculate for the update server. 114 * 115 * The reasons for having several bins are as follows: 116 * 117 * - smaller bins mean smaller database tables and allow for faster selects and 118 * inserts 119 * - we try to put fast changing cache items and rather static ones into 120 * different bins. The effect is that only the fast changing bins will need a 121 * lot of writes to disk. The more static bins will also be better cacheable 122 * with MySQL's query cache. 123 * 124 * @param $cid 125 * The cache ID of the data to store. 126 * @param $data 127 * The data to store in the cache. Complex data types will be automatically 128 * serialized before insertion. 129 * Strings will be stored as plain text and not serialized. 130 * @param $bin 131 * The cache bin to store the data in. Valid core values are 'cache_block', 132 * 'cache_bootstrap', 'cache_field', 'cache_filter', 'cache_form', 133 * 'cache_menu', 'cache_page', 'cache_update' or 'cache' for the default 134 * cache. 135 * @param $expire 136 * One of the following values: 137 * - CACHE_PERMANENT: Indicates that the item should never be removed unless 138 * explicitly told to using cache_clear_all() with a cache ID. 139 * - CACHE_TEMPORARY: Indicates that the item should be removed at the next 140 * general cache wipe. 141 * - A Unix timestamp: Indicates that the item should be kept at least until 142 * the given time, after which it behaves like CACHE_TEMPORARY. 143 * 144 * @see cache_get() 145 */ 146 function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT) { 147 return _cache_get_object($bin)->set($cid, $data, $expire); 148 } 149 150 /** 151 * Expires data from the cache. 152 * 153 * If called without arguments, expirable entries will be cleared from the 154 * cache_page and cache_block bins. 155 * 156 * @param $cid 157 * If set, the cache ID to delete. Otherwise, all cache entries that can 158 * expire are deleted. 159 * @param $bin 160 * If set, the cache bin to delete from. Mandatory argument if $cid is set. 161 * @param $wildcard 162 * If TRUE, cache IDs starting with $cid are deleted in addition to the 163 * exact cache ID specified by $cid. If $wildcard is TRUE and $cid is '*', 164 * the entire cache bin is emptied. 165 */ 166 function cache_clear_all($cid = NULL, $bin = NULL, $wildcard = FALSE) { 167 if (!isset($cid) && !isset($bin)) { 168 // Clear the block cache first, so stale data will 169 // not end up in the page cache. 170 if (module_exists('block')) { 171 cache_clear_all(NULL, 'cache_block'); 172 } 173 cache_clear_all(NULL, 'cache_page'); 174 return; 175 } 176 return _cache_get_object($bin)->clear($cid, $wildcard); 177 } 178 179 /** 180 * Checks if a cache bin is empty. 181 * 182 * A cache bin is considered empty if it does not contain any valid data for any 183 * cache ID. 184 * 185 * @param $bin 186 * The cache bin to check. 187 * 188 * @return 189 * TRUE if the cache bin specified is empty. 190 */ 191 function cache_is_empty($bin) { 192 return _cache_get_object($bin)->isEmpty(); 193 } 194 195 /** 196 * Defines an interface for cache implementations. 197 * 198 * All cache implementations have to implement this interface. 199 * DrupalDatabaseCache provides the default implementation, which can be 200 * consulted as an example. 201 * 202 * To make Drupal use your implementation for a certain cache bin, you have to 203 * set a variable with the name of the cache bin as its key and the name of 204 * your class as its value. For example, if your implementation of 205 * DrupalCacheInterface was called MyCustomCache, the following line would make 206 * Drupal use it for the 'cache_page' bin: 207 * @code 208 * variable_set('cache_class_cache_page', 'MyCustomCache'); 209 * @endcode 210 * 211 * Additionally, you can register your cache implementation to be used by 212 * default for all cache bins by setting the variable 'cache_default_class' to 213 * the name of your implementation of the DrupalCacheInterface, e.g. 214 * @code 215 * variable_set('cache_default_class', 'MyCustomCache'); 216 * @endcode 217 * 218 * To implement a completely custom cache bin, use the same variable format: 219 * @code 220 * variable_set('cache_class_custom_bin', 'MyCustomCache'); 221 * @endcode 222 * To access your custom cache bin, specify the name of the bin when storing 223 * or retrieving cached data: 224 * @code 225 * cache_set($cid, $data, 'custom_bin', $expire); 226 * cache_get($cid, 'custom_bin'); 227 * @endcode 228 * 229 * @see _cache_get_object() 230 * @see DrupalDatabaseCache 231 */ 232 interface DrupalCacheInterface { 233 /** 234 * Constructs a new cache interface. 235 * 236 * @param $bin 237 * The cache bin for which the object is created. 238 */ 239 function __construct($bin); 240 241 /** 242 * Returns data from the persistent cache. 243 * 244 * Data may be stored as either plain text or as serialized data. cache_get() 245 * will automatically return unserialized objects and arrays. 246 * 247 * @param $cid 248 * The cache ID of the data to retrieve. 249 * 250 * @return 251 * The cache or FALSE on failure. 252 */ 253 function get($cid); 254 255 /** 256 * Returns data from the persistent cache when given an array of cache IDs. 257 * 258 * @param $cids 259 * An array of cache IDs for the data to retrieve. This is passed by 260 * reference, and will have the IDs successfully returned from cache 261 * removed. 262 * 263 * @return 264 * An array of the items successfully returned from cache indexed by cid. 265 */ 266 function getMultiple(&$cids); 267 268 /** 269 * Stores data in the persistent cache. 270 * 271 * @param $cid 272 * The cache ID of the data to store. 273 * @param $data 274 * The data to store in the cache. Complex data types will be automatically 275 * serialized before insertion. 276 * Strings will be stored as plain text and not serialized. 277 * @param $expire 278 * One of the following values: 279 * - CACHE_PERMANENT: Indicates that the item should never be removed unless 280 * explicitly told to using cache_clear_all() with a cache ID. 281 * - CACHE_TEMPORARY: Indicates that the item should be removed at the next 282 * general cache wipe. 283 * - A Unix timestamp: Indicates that the item should be kept at least until 284 * the given time, after which it behaves like CACHE_TEMPORARY. 285 */ 286 function set($cid, $data, $expire = CACHE_PERMANENT); 287 288 289 /** 290 * Expires data from the cache. 291 * 292 * If called without arguments, expirable entries will be cleared from the 293 * cache_page and cache_block bins. 294 * 295 * @param $cid 296 * If set, the cache ID to delete. Otherwise, all cache entries that can 297 * expire are deleted. 298 * @param $wildcard 299 * If set to TRUE, the $cid is treated as a substring 300 * to match rather than a complete ID. The match is a right hand 301 * match. If '*' is given as $cid, the bin $bin will be emptied. 302 */ 303 function clear($cid = NULL, $wildcard = FALSE); 304 305 /** 306 * Checks if a cache bin is empty. 307 * 308 * A cache bin is considered empty if it does not contain any valid data for 309 * any cache ID. 310 * 311 * @return 312 * TRUE if the cache bin specified is empty. 313 */ 314 function isEmpty(); 315 } 316 317 /** 318 * Defines a default cache implementation. 319 * 320 * This is Drupal's default cache implementation. It uses the database to store 321 * cached data. Each cache bin corresponds to a database table by the same name. 322 */ 323 class DrupalDatabaseCache implements DrupalCacheInterface { 324 protected $bin; 325 326 /** 327 * Constructs a new DrupalDatabaseCache object. 328 */ 329 function __construct($bin) { 330 $this->bin = $bin; 331 } 332 333 /** 334 * Implements DrupalCacheInterface::get(). 335 */ 336 function get($cid) { 337 $cids = array($cid); 338 $cache = $this->getMultiple($cids); 339 return reset($cache); 340 } 341 342 /** 343 * Implements DrupalCacheInterface::getMultiple(). 344 */ 345 function getMultiple(&$cids) { 346 try { 347 // Garbage collection necessary when enforcing a minimum cache lifetime. 348 $this->garbageCollection($this->bin); 349 350 // When serving cached pages, the overhead of using db_select() was found 351 // to add around 30% overhead to the request. Since $this->bin is a 352 // variable, this means the call to db_query() here uses a concatenated 353 // string. This is highly discouraged under any other circumstances, and 354 // is used here only due to the performance overhead we would incur 355 // otherwise. When serving an uncached page, the overhead of using 356 // db_select() is a much smaller proportion of the request. 357 $result = db_query('SELECT cid, data, created, expire, serialized FROM {' . db_escape_table($this->bin) . '} WHERE cid IN (:cids)', array(':cids' => $cids)); 358 $cache = array(); 359 foreach ($result as $item) { 360 $item = $this->prepareItem($item); 361 if ($item) { 362 $cache[$item->cid] = $item; 363 } 364 } 365 $cids = array_diff($cids, array_keys($cache)); 366 return $cache; 367 } 368 catch (Exception $e) { 369 // If the database is never going to be available, cache requests should 370 // return FALSE in order to allow exception handling to occur. 371 return array(); 372 } 373 } 374 375 /** 376 * Garbage collection for get() and getMultiple(). 377 * 378 * @param $bin 379 * The bin being requested. 380 */ 381 protected function garbageCollection() { 382 $cache_lifetime = variable_get('cache_lifetime', 0); 383 384 // Clean-up the per-user cache expiration session data, so that the session 385 // handler can properly clean-up the session data for anonymous users. 386 if (isset($_SESSION['cache_expiration'])) { 387 $expire = REQUEST_TIME - $cache_lifetime; 388 foreach ($_SESSION['cache_expiration'] as $bin => $timestamp) { 389 if ($timestamp < $expire) { 390 unset($_SESSION['cache_expiration'][$bin]); 391 } 392 } 393 if (!$_SESSION['cache_expiration']) { 394 unset($_SESSION['cache_expiration']); 395 } 396 } 397 398 // Garbage collection of temporary items is only necessary when enforcing 399 // a minimum cache lifetime. 400 if (!$cache_lifetime) { 401 return; 402 } 403 // When cache lifetime is in force, avoid running garbage collection too 404 // often since this will remove temporary cache items indiscriminately. 405 $cache_flush = variable_get('cache_flush_' . $this->bin, 0); 406 if ($cache_flush && ($cache_flush + $cache_lifetime <= REQUEST_TIME)) { 407 // Reset the variable immediately to prevent a meltdown in heavy load situations. 408 variable_set('cache_flush_' . $this->bin, 0); 409 // Time to flush old cache data 410 db_delete($this->bin) 411 ->condition('expire', CACHE_PERMANENT, '<>') 412 ->condition('expire', $cache_flush, '<=') 413 ->execute(); 414 } 415 } 416 417 /** 418 * Prepares a cached item. 419 * 420 * Checks that items are either permanent or did not expire, and unserializes 421 * data as appropriate. 422 * 423 * @param $cache 424 * An item loaded from cache_get() or cache_get_multiple(). 425 * 426 * @return 427 * The item with data unserialized as appropriate or FALSE if there is no 428 * valid item to load. 429 */ 430 protected function prepareItem($cache) { 431 global $user; 432 433 if (!isset($cache->data)) { 434 return FALSE; 435 } 436 // If the cached data is temporary and subject to a per-user minimum 437 // lifetime, compare the cache entry timestamp with the user session 438 // cache_expiration timestamp. If the cache entry is too old, ignore it. 439 if ($cache->expire != CACHE_PERMANENT && variable_get('cache_lifetime', 0) && isset($_SESSION['cache_expiration'][$this->bin]) && $_SESSION['cache_expiration'][$this->bin] > $cache->created) { 440 // Ignore cache data that is too old and thus not valid for this user. 441 return FALSE; 442 } 443 444 // If the data is permanent or not subject to a minimum cache lifetime, 445 // unserialize and return the cached data. 446 if ($cache->serialized) { 447 $cache->data = unserialize($cache->data); 448 } 449 450 return $cache; 451 } 452 453 /** 454 * Implements DrupalCacheInterface::set(). 455 */ 456 function set($cid, $data, $expire = CACHE_PERMANENT) { 457 $fields = array( 458 'serialized' => 0, 459 'created' => REQUEST_TIME, 460 'expire' => $expire, 461 ); 462 if (!is_string($data)) { 463 $fields['data'] = serialize($data); 464 $fields['serialized'] = 1; 465 } 466 else { 467 $fields['data'] = $data; 468 $fields['serialized'] = 0; 469 } 470 471 try { 472 db_merge($this->bin) 473 ->key(array('cid' => $cid)) 474 ->fields($fields) 475 ->execute(); 476 } 477 catch (Exception $e) { 478 // The database may not be available, so we'll ignore cache_set requests. 479 } 480 } 481 482 /** 483 * Implements DrupalCacheInterface::clear(). 484 */ 485 function clear($cid = NULL, $wildcard = FALSE) { 486 global $user; 487 488 if (empty($cid)) { 489 if (variable_get('cache_lifetime', 0)) { 490 // We store the time in the current user's session. We then simulate 491 // that the cache was flushed for this user by not returning cached 492 // data that was cached before the timestamp. 493 $_SESSION['cache_expiration'][$this->bin] = REQUEST_TIME; 494 495 $cache_flush = variable_get('cache_flush_' . $this->bin, 0); 496 if ($cache_flush == 0) { 497 // This is the first request to clear the cache, start a timer. 498 variable_set('cache_flush_' . $this->bin, REQUEST_TIME); 499 } 500 elseif (REQUEST_TIME > ($cache_flush + variable_get('cache_lifetime', 0))) { 501 // Clear the cache for everyone, cache_lifetime seconds have 502 // passed since the first request to clear the cache. 503 db_delete($this->bin) 504 ->condition('expire', CACHE_PERMANENT, '<>') 505 ->condition('expire', REQUEST_TIME, '<') 506 ->execute(); 507 variable_set('cache_flush_' . $this->bin, 0); 508 } 509 } 510 else { 511 // No minimum cache lifetime, flush all temporary cache entries now. 512 db_delete($this->bin) 513 ->condition('expire', CACHE_PERMANENT, '<>') 514 ->condition('expire', REQUEST_TIME, '<') 515 ->execute(); 516 } 517 } 518 else { 519 if ($wildcard) { 520 if ($cid == '*') { 521 db_truncate($this->bin)->execute(); 522 } 523 else { 524 db_delete($this->bin) 525 ->condition('cid', db_like($cid) . '%', 'LIKE') 526 ->execute(); 527 } 528 } 529 elseif (is_array($cid)) { 530 // Delete in chunks when a large array is passed. 531 do { 532 db_delete($this->bin) 533 ->condition('cid', array_splice($cid, 0, 1000), 'IN') 534 ->execute(); 535 } 536 while (count($cid)); 537 } 538 else { 539 db_delete($this->bin) 540 ->condition('cid', $cid) 541 ->execute(); 542 } 543 } 544 } 545 546 /** 547 * Implements DrupalCacheInterface::isEmpty(). 548 */ 549 function isEmpty() { 550 $this->garbageCollection(); 551 $query = db_select($this->bin); 552 $query->addExpression('1'); 553 $result = $query->range(0, 1) 554 ->execute() 555 ->fetchField(); 556 return empty($result); 557 } 558 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
title