PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/joomla/cache/cache.php

https://bitbucket.org/izubizarreta/https-bitbucket.org-bityvip
PHP | 695 lines | 360 code | 86 blank | 249 comment | 72 complexity | ff4cf5ce5e78401a0bde0206bce04801 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.0, JSON, GPL-2.0, BSD-3-Clause, LGPL-2.1, MIT
  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage Cache
  5. *
  6. * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('JPATH_PLATFORM') or die;
  10. //Register the storage class with the loader
  11. JLoader::register('JCacheStorage', dirname(__FILE__) . '/storage.php');
  12. //Register the controller class with the loader
  13. JLoader::register('JCacheController', dirname(__FILE__) . '/controller.php');
  14. // Almost everything must be public here to allow overloading.
  15. /**
  16. * Joomla! Cache base object
  17. *
  18. * @package Joomla.Platform
  19. * @subpackage Cache
  20. * @since 11.1
  21. */
  22. class JCache extends JObject
  23. {
  24. /**
  25. * @var object Storage handler
  26. * @since 11.1
  27. */
  28. public static $_handler = array();
  29. /**
  30. * @var array Options
  31. * @since 11.1
  32. */
  33. public $_options;
  34. /**
  35. * Constructor
  36. *
  37. * @param array $options options
  38. *
  39. * @since 11.1
  40. */
  41. public function __construct($options)
  42. {
  43. $conf = JFactory::getConfig();
  44. $this->_options = array(
  45. 'cachebase' => $conf->get('cache_path', JPATH_CACHE),
  46. 'lifetime' => (int) $conf->get('cachetime'),
  47. 'language' => $conf->get('language', 'en-GB'),
  48. 'storage' => $conf->get('cache_handler', ''),
  49. 'defaultgroup' => 'default',
  50. 'locking' => true,
  51. 'locktime' => 15,
  52. 'checkTime' => true,
  53. 'caching' => ($conf->get('caching') >= 1) ? true : false);
  54. // Overwrite default options with given options
  55. foreach ($options as $option => $value)
  56. {
  57. if (isset($options[$option]) && $options[$option] !== '')
  58. {
  59. $this->_options[$option] = $options[$option];
  60. }
  61. }
  62. if (empty($this->_options['storage']))
  63. {
  64. $this->_options['caching'] = false;
  65. }
  66. }
  67. /**
  68. * Returns a reference to a cache adapter object, always creating it
  69. *
  70. * @param string $type The cache object type to instantiate
  71. * @param array $options The array of options
  72. *
  73. * @return JCache A JCache object
  74. *
  75. * @since 11.1
  76. */
  77. public static function getInstance($type = 'output', $options = array())
  78. {
  79. return JCacheController::getInstance($type, $options);
  80. }
  81. /**
  82. * Get the storage handlers
  83. *
  84. * @return array An array of available storage handlers
  85. *
  86. * @since 11.1
  87. */
  88. public static function getStores()
  89. {
  90. jimport('joomla.filesystem.folder');
  91. $handlers = JFolder::files(dirname(__FILE__) . '/storage', '.php');
  92. $names = array();
  93. foreach ($handlers as $handler)
  94. {
  95. $name = substr($handler, 0, strrpos($handler, '.'));
  96. $class = 'JCacheStorage' . $name;
  97. if (!class_exists($class))
  98. {
  99. include_once dirname(__FILE__) . '/storage/' . $name . '.php';
  100. }
  101. if (call_user_func_array(array(trim($class), 'test'), array()))
  102. {
  103. $names[] = $name;
  104. }
  105. }
  106. return $names;
  107. }
  108. /**
  109. * Set caching enabled state
  110. *
  111. * @param boolean $enabled True to enable caching
  112. *
  113. * @return void
  114. *
  115. * @since 11.1
  116. */
  117. public function setCaching($enabled)
  118. {
  119. $this->_options['caching'] = $enabled;
  120. }
  121. /**
  122. * Get caching state
  123. *
  124. * @return boolean Caching state
  125. *
  126. * @since 11.1
  127. */
  128. public function getCaching()
  129. {
  130. return $this->_options['caching'];
  131. }
  132. /**
  133. * Set cache lifetime
  134. *
  135. * @param integer $lt Cache lifetime
  136. *
  137. * @return void
  138. *
  139. * @since 11.1
  140. */
  141. public function setLifeTime($lt)
  142. {
  143. $this->_options['lifetime'] = $lt;
  144. }
  145. /**
  146. * Get cached data by id and group
  147. *
  148. * @param string $id The cache data id
  149. * @param string $group The cache data group
  150. *
  151. * @return mixed boolean False on failure or a cached data string
  152. *
  153. * @since 11.1
  154. */
  155. public function get($id, $group = null)
  156. {
  157. // Get the default group
  158. $group = ($group) ? $group : $this->_options['defaultgroup'];
  159. // Get the storage
  160. $handler = $this->_getStorage();
  161. if (!($handler instanceof Exception) && $this->_options['caching'])
  162. {
  163. return $handler->get($id, $group, $this->_options['checkTime']);
  164. }
  165. return false;
  166. }
  167. /**
  168. * Get a list of all cached data
  169. *
  170. * @return mixed Boolean false on failure or an object with a list of cache groups and data
  171. *
  172. * @since 11.1
  173. */
  174. public function getAll()
  175. {
  176. // Get the storage
  177. $handler = $this->_getStorage();
  178. if (!($handler instanceof Exception) && $this->_options['caching'])
  179. {
  180. return $handler->getAll();
  181. }
  182. return false;
  183. }
  184. /**
  185. * Store the cached data by id and group
  186. *
  187. * @param mixed $data The data to store
  188. * @param string $id The cache data id
  189. * @param string $group The cache data group
  190. *
  191. * @return boolean True if cache stored
  192. *
  193. * @since 11.1
  194. */
  195. public function store($data, $id, $group = null)
  196. {
  197. // Get the default group
  198. $group = ($group) ? $group : $this->_options['defaultgroup'];
  199. // Get the storage and store the cached data
  200. $handler = $this->_getStorage();
  201. if (!($handler instanceof Exception) && $this->_options['caching'])
  202. {
  203. $handler->_lifetime = $this->_options['lifetime'];
  204. return $handler->store($id, $group, $data);
  205. }
  206. return false;
  207. }
  208. /**
  209. * Remove a cached data entry by id and group
  210. *
  211. * @param string $id The cache data id
  212. * @param string $group The cache data group
  213. *
  214. * @return boolean True on success, false otherwise
  215. *
  216. * @since 11.1
  217. */
  218. public function remove($id, $group = null)
  219. {
  220. // Get the default group
  221. $group = ($group) ? $group : $this->_options['defaultgroup'];
  222. // Get the storage
  223. $handler = $this->_getStorage();
  224. if (!($handler instanceof Exception))
  225. {
  226. return $handler->remove($id, $group);
  227. }
  228. return false;
  229. }
  230. /**
  231. * Clean cache for a group given a mode.
  232. *
  233. * group mode : cleans all cache in the group
  234. * notgroup mode : cleans all cache not in the group
  235. *
  236. * @param string $group The cache data group
  237. * @param string $mode The mode for cleaning cache [group|notgroup]
  238. *
  239. * @return boolean True on success, false otherwise
  240. *
  241. * @since 11.1
  242. */
  243. public function clean($group = null, $mode = 'group')
  244. {
  245. // Get the default group
  246. $group = ($group) ? $group : $this->_options['defaultgroup'];
  247. // Get the storage handler
  248. $handler = $this->_getStorage();
  249. if (!($handler instanceof Exception))
  250. {
  251. return $handler->clean($group, $mode);
  252. }
  253. return false;
  254. }
  255. /**
  256. * Garbage collect expired cache data
  257. *
  258. * @return boolean True on success, false otherwise.
  259. *
  260. * @since 11.1
  261. */
  262. public function gc()
  263. {
  264. // Get the storage handler
  265. $handler = $this->_getStorage();
  266. if (!($handler instanceof Exception))
  267. {
  268. return $handler->gc();
  269. }
  270. return false;
  271. }
  272. /**
  273. * Set lock flag on cached item
  274. *
  275. * @param string $id The cache data id
  276. * @param string $group The cache data group
  277. * @param string $locktime The default locktime for locking the cache.
  278. *
  279. * @return object Properties are lock and locklooped
  280. *
  281. * @since 11.1
  282. */
  283. public function lock($id, $group = null, $locktime = null)
  284. {
  285. $returning = new stdClass;
  286. $returning->locklooped = false;
  287. // Get the default group
  288. $group = ($group) ? $group : $this->_options['defaultgroup'];
  289. // Get the default locktime
  290. $locktime = ($locktime) ? $locktime : $this->_options['locktime'];
  291. // Allow storage handlers to perform locking on their own
  292. // NOTE drivers with lock need also unlock or unlocking will fail because of false $id
  293. $handler = $this->_getStorage();
  294. if (!($handler instanceof Exception) && $this->_options['locking'] == true && $this->_options['caching'] == true)
  295. {
  296. $locked = $handler->lock($id, $group, $locktime);
  297. if ($locked !== false)
  298. {
  299. return $locked;
  300. }
  301. }
  302. // Fallback
  303. $curentlifetime = $this->_options['lifetime'];
  304. // Set lifetime to locktime for storing in children
  305. $this->_options['lifetime'] = $locktime;
  306. $looptime = $locktime * 10;
  307. $id2 = $id . '_lock';
  308. if ($this->_options['locking'] == true && $this->_options['caching'] == true)
  309. {
  310. $data_lock = $this->get($id2, $group);
  311. }
  312. else
  313. {
  314. $data_lock = false;
  315. $returning->locked = false;
  316. }
  317. if ($data_lock !== false)
  318. {
  319. $lock_counter = 0;
  320. // Loop until you find that the lock has been released.
  321. // That implies that data get from other thread has finished
  322. while ($data_lock !== false)
  323. {
  324. if ($lock_counter > $looptime)
  325. {
  326. $returning->locked = false;
  327. $returning->locklooped = true;
  328. break;
  329. }
  330. usleep(100);
  331. $data_lock = $this->get($id2, $group);
  332. $lock_counter++;
  333. }
  334. }
  335. if ($this->_options['locking'] == true && $this->_options['caching'] == true)
  336. {
  337. $returning->locked = $this->store(1, $id2, $group);
  338. }
  339. // Revert lifetime to previous one
  340. $this->_options['lifetime'] = $curentlifetime;
  341. return $returning;
  342. }
  343. /**
  344. * Unset lock flag on cached item
  345. *
  346. * @param string $id The cache data id
  347. * @param string $group The cache data group
  348. *
  349. * @return boolean True on success, false otherwise.
  350. *
  351. * @since 11.1
  352. */
  353. public function unlock($id, $group = null)
  354. {
  355. $unlock = false;
  356. // Get the default group
  357. $group = ($group) ? $group : $this->_options['defaultgroup'];
  358. // Allow handlers to perform unlocking on their own
  359. $handler = $this->_getStorage();
  360. if (!($handler instanceof Exception) && $this->_options['caching'])
  361. {
  362. $unlocked = $handler->unlock($id, $group);
  363. if ($unlocked !== false)
  364. {
  365. return $unlocked;
  366. }
  367. }
  368. // Fallback
  369. if ($this->_options['caching'])
  370. {
  371. $unlock = $this->remove($id . '_lock', $group);
  372. }
  373. return $unlock;
  374. }
  375. /**
  376. * Get the cache storage handler
  377. *
  378. * @return JCacheStorage A JCacheStorage object
  379. *
  380. * @since 11.1
  381. */
  382. public function &_getStorage()
  383. {
  384. $hash = md5(serialize($this->_options));
  385. if (isset(self::$_handler[$hash]))
  386. {
  387. return self::$_handler[$hash];
  388. }
  389. self::$_handler[$hash] = JCacheStorage::getInstance($this->_options['storage'], $this->_options);
  390. return self::$_handler[$hash];
  391. }
  392. /**
  393. * Perform workarounds on retrieved cached data
  394. *
  395. * @param string $data Cached data
  396. * @param array $options Array of options
  397. *
  398. * @return string Body of cached data
  399. *
  400. * @since 11.1
  401. */
  402. public static function getWorkarounds($data, $options = array())
  403. {
  404. // Initialise variables.
  405. $app = JFactory::getApplication();
  406. $document = JFactory::getDocument();
  407. $body = null;
  408. // Get the document head out of the cache.
  409. if (isset($options['mergehead']) && $options['mergehead'] == 1 && isset($data['head']) && !empty($data['head']))
  410. {
  411. $document->mergeHeadData($data['head']);
  412. }
  413. elseif (isset($data['head']) && method_exists($document, 'setHeadData'))
  414. {
  415. $document->setHeadData($data['head']);
  416. }
  417. // If the pathway buffer is set in the cache data, get it.
  418. if (isset($data['pathway']) && is_array($data['pathway']))
  419. {
  420. // Push the pathway data into the pathway object.
  421. $pathway = $app->getPathWay();
  422. $pathway->setPathway($data['pathway']);
  423. }
  424. // @todo check if the following is needed, seems like it should be in page cache
  425. // If a module buffer is set in the cache data, get it.
  426. if (isset($data['module']) && is_array($data['module']))
  427. {
  428. // Iterate through the module positions and push them into the document buffer.
  429. foreach ($data['module'] as $name => $contents)
  430. {
  431. $document->setBuffer($contents, 'module', $name);
  432. }
  433. }
  434. if (isset($data['body']))
  435. {
  436. // The following code searches for a token in the cached page and replaces it with the
  437. // proper token.
  438. $token = JSession::getFormToken();
  439. $search = '#<input type="hidden" name="[0-9a-f]{32}" value="1" />#';
  440. $replacement = '<input type="hidden" name="' . $token . '" value="1" />';
  441. $data['body'] = preg_replace($search, $replacement, $data['body']);
  442. $body = $data['body'];
  443. }
  444. // Get the document body out of the cache.
  445. return $body;
  446. }
  447. /**
  448. * Create workarounded data to be cached
  449. *
  450. * @param string $data Cached data
  451. * @param array $options Array of options
  452. *
  453. * @return string Data to be cached
  454. *
  455. * @since 11.1
  456. */
  457. public static function setWorkarounds($data, $options = array())
  458. {
  459. $loptions = array();
  460. $loptions['nopathway'] = 0;
  461. $loptions['nohead'] = 0;
  462. $loptions['nomodules'] = 0;
  463. $loptions['modulemode'] = 0;
  464. if (isset($options['nopathway']))
  465. {
  466. $loptions['nopathway'] = $options['nopathway'];
  467. }
  468. if (isset($options['nohead']))
  469. {
  470. $loptions['nohead'] = $options['nohead'];
  471. }
  472. if (isset($options['nomodules']))
  473. {
  474. $loptions['nomodules'] = $options['nomodules'];
  475. }
  476. if (isset($options['modulemode']))
  477. {
  478. $loptions['modulemode'] = $options['modulemode'];
  479. }
  480. // Initialise variables.
  481. $app = JFactory::getApplication();
  482. $document = JFactory::getDocument();
  483. // Get the modules buffer before component execution.
  484. $buffer1 = $document->getBuffer();
  485. if (!is_array($buffer1))
  486. {
  487. $buffer1 = array();
  488. }
  489. // Make sure the module buffer is an array.
  490. if (!isset($buffer1['module']) || !is_array($buffer1['module']))
  491. {
  492. $buffer1['module'] = array();
  493. }
  494. // View body data
  495. $cached['body'] = $data;
  496. // Document head data
  497. if ($loptions['nohead'] != 1 && method_exists($document, 'getHeadData'))
  498. {
  499. if ($loptions['modulemode'] == 1)
  500. {
  501. $headnow = $document->getHeadData();
  502. $unset = array('title', 'description', 'link', 'links', 'metaTags');
  503. foreach ($unset as $un)
  504. {
  505. unset($headnow[$un]);
  506. unset($options['headerbefore'][$un]);
  507. }
  508. $cached['head'] = array();
  509. // Only store what this module has added
  510. foreach ($headnow as $now => $value)
  511. {
  512. $newvalue = array_diff_assoc($headnow[$now], isset($options['headerbefore'][$now]) ? $options['headerbefore'][$now] : array());
  513. if (!empty($newvalue))
  514. {
  515. $cached['head'][$now] = $newvalue;
  516. }
  517. }
  518. }
  519. else
  520. {
  521. $cached['head'] = $document->getHeadData();
  522. }
  523. }
  524. // Pathway data
  525. if ($app->isSite() && $loptions['nopathway'] != 1)
  526. {
  527. $pathway = $app->getPathWay();
  528. $cached['pathway'] = isset($data['pathway']) ? $data['pathway'] : $pathway->getPathway();
  529. }
  530. if ($loptions['nomodules'] != 1)
  531. {
  532. // @todo Check if the following is needed, seems like it should be in page cache
  533. // Get the module buffer after component execution.
  534. $buffer2 = $document->getBuffer();
  535. if (!is_array($buffer2))
  536. {
  537. $buffer2 = array();
  538. }
  539. // Make sure the module buffer is an array.
  540. if (!isset($buffer2['module']) || !is_array($buffer2['module']))
  541. {
  542. $buffer2['module'] = array();
  543. }
  544. // Compare the second module buffer against the first buffer.
  545. $cached['module'] = array_diff_assoc($buffer2['module'], $buffer1['module']);
  546. }
  547. return $cached;
  548. }
  549. /**
  550. * Create safe id for cached data from url parameters set by plugins and framework
  551. *
  552. * @return string md5 encoded cacheid
  553. *
  554. * @since 11.1
  555. */
  556. public static function makeId()
  557. {
  558. $app = JFactory::getApplication();
  559. // Get url parameters set by plugins
  560. $registeredurlparams = $app->registeredurlparams;
  561. if (empty($registeredurlparams))
  562. {
  563. /*
  564. $registeredurlparams = new stdClass;
  565. $registeredurlparams->Itemid = 'INT';
  566. $registeredurlparams->catid = 'INT';
  567. $registeredurlparams->id = 'INT';
  568. */
  569. return md5(serialize(JRequest::getURI())); // provided for backwards compatibility - THIS IS NOT SAFE!!!!
  570. }
  571. // Platform defaults
  572. $registeredurlparams->format = 'WORD';
  573. $registeredurlparams->option = 'WORD';
  574. $registeredurlparams->view = 'WORD';
  575. $registeredurlparams->layout = 'WORD';
  576. $registeredurlparams->tpl = 'CMD';
  577. $registeredurlparams->id = 'INT';
  578. $safeuriaddon = new stdClass;
  579. foreach ($registeredurlparams as $key => $value)
  580. {
  581. $safeuriaddon->$key = JRequest::getVar($key, null, 'default', $value);
  582. }
  583. return md5(serialize($safeuriaddon));
  584. }
  585. /**
  586. * Add a directory where JCache should search for handlers. You may
  587. * either pass a string or an array of directories.
  588. *
  589. * @param string $path A path to search.
  590. *
  591. * @return array An array with directory elements
  592. *
  593. * @since 11.1
  594. */
  595. public static function addIncludePath($path = '')
  596. {
  597. static $paths;
  598. if (!isset($paths))
  599. {
  600. $paths = array();
  601. }
  602. if (!empty($path) && !in_array($path, $paths))
  603. {
  604. jimport('joomla.filesystem.path');
  605. array_unshift($paths, JPath::clean($path));
  606. }
  607. return $paths;
  608. }
  609. }