PageRenderTime 58ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/classes/cache/Cache.php

https://gitlab.com/staging06/myproject
PHP | 396 lines | 205 code | 43 blank | 148 comment | 31 complexity | 950182cb73c2a9e0b5f2c40266df3bae MD5 | raw file
  1. <?php
  2. /*
  3. * 2007-2015 PrestaShop
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@prestashop.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
  18. * versions in the future. If you wish to customize PrestaShop for your
  19. * needs please refer to http://www.prestashop.com for more information.
  20. *
  21. * @author PrestaShop SA <contact@prestashop.com>
  22. * @copyright 2007-2015 PrestaShop SA
  23. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  24. * International Registered Trademark & Property of PrestaShop SA
  25. */
  26. abstract class CacheCore
  27. {
  28. /**
  29. * Name of keys index
  30. */
  31. const KEYS_NAME = '__keys__';
  32. /**
  33. * Name of SQL cache index
  34. */
  35. const SQL_TABLES_NAME = 'tablesCached';
  36. /**
  37. * @var Cache
  38. */
  39. protected static $instance;
  40. /**
  41. * @var array List all keys of cached data and their associated ttl
  42. */
  43. protected $keys = array();
  44. /**
  45. * @var array Store list of tables and their associated keys for SQL cache (warning: this var must not be initialized here !)
  46. */
  47. protected $sql_tables_cached;
  48. /**
  49. * @var array List of blacklisted tables for SQL cache, these tables won't be indexed
  50. */
  51. protected $blacklist = array(
  52. 'cart',
  53. 'cart_cart_rule',
  54. 'cart_product',
  55. 'connections',
  56. 'connections_source',
  57. 'connections_page',
  58. 'customer',
  59. 'customer_group',
  60. 'customized_data',
  61. 'guest',
  62. 'pagenotfound',
  63. 'page_viewed',
  64. );
  65. /**
  66. * @var array Store local cache
  67. */
  68. protected static $local = array();
  69. /**
  70. * Cache a data
  71. *
  72. * @param string $key
  73. * @param mixed $value
  74. * @param int $ttl
  75. * @return bool
  76. */
  77. abstract protected function _set($key, $value, $ttl = 0);
  78. /**
  79. * Retrieve a cached data by key
  80. *
  81. * @param string $key
  82. * @return mixed
  83. */
  84. abstract protected function _get($key);
  85. /**
  86. * Check if a data is cached by key
  87. *
  88. * @param string $key
  89. * @return bool
  90. */
  91. abstract protected function _exists($key);
  92. /**
  93. * Delete a data from the cache by key
  94. *
  95. * @param string $key
  96. * @return bool
  97. */
  98. abstract protected function _delete($key);
  99. /**
  100. * Write keys index
  101. */
  102. abstract protected function _writeKeys();
  103. /**
  104. * Clean all cached data
  105. *
  106. * @return bool
  107. */
  108. abstract public function flush();
  109. /**
  110. * @return Cache
  111. */
  112. public static function getInstance()
  113. {
  114. if (!self::$instance)
  115. {
  116. $caching_system = _PS_CACHING_SYSTEM_;
  117. self::$instance = new $caching_system();
  118. }
  119. return self::$instance;
  120. }
  121. /**
  122. * Unit testing purpose only
  123. * @param $test_instance Cache
  124. */
  125. public static function setInstanceForTesting($test_instance)
  126. {
  127. self::$instance = $test_instance;
  128. }
  129. /**
  130. * Unit testing purpose only
  131. */
  132. public static function deleteTestingInstance()
  133. {
  134. self::$instance = null;
  135. }
  136. /**
  137. * Store a data in cache
  138. *
  139. * @param string $key
  140. * @param mixed $value
  141. * @param int $ttl
  142. * @return bool
  143. */
  144. public function set($key, $value, $ttl = 0)
  145. {
  146. if ($this->_set($key, $value, $ttl))
  147. {
  148. if ($ttl < 0)
  149. $ttl = 0;
  150. $this->keys[$key] = ($ttl == 0) ? 0 : time() + $ttl;
  151. $this->_writeKeys();
  152. return true;
  153. }
  154. return false;
  155. }
  156. /**
  157. * Retrieve a data from cache
  158. *
  159. * @param string $key
  160. * @return mixed
  161. */
  162. public function get($key)
  163. {
  164. if (!isset($this->keys[$key]))
  165. return false;
  166. return $this->_get($key);
  167. }
  168. /**
  169. * Check if a data is cached
  170. *
  171. * @param string $key
  172. * @return bool
  173. */
  174. public function exists($key)
  175. {
  176. if (!isset($this->keys[$key]))
  177. return false;
  178. return $this->_exists($key);
  179. }
  180. /**
  181. * Delete one or several data from cache (* joker can be used)
  182. * E.g.: delete('*'); delete('my_prefix_*'); delete('my_key_name');
  183. *
  184. * @param string $key
  185. * @return array List of deleted keys
  186. */
  187. public function delete($key)
  188. {
  189. // Get list of keys to delete
  190. $keys = array();
  191. if ($key == '*')
  192. $keys = $this->keys;
  193. elseif (strpos($key, '*') === false)
  194. $keys = array($key);
  195. else
  196. {
  197. $pattern = str_replace('\\*', '.*', preg_quote($key));
  198. foreach ($this->keys as $k => $ttl)
  199. if (preg_match('#^'.$pattern.'$#', $k))
  200. $keys[] = $k;
  201. }
  202. // Delete keys
  203. foreach ($keys as $key)
  204. {
  205. if (!isset($this->keys[$key]))
  206. continue;
  207. if ($this->_delete($key))
  208. unset($this->keys[$key]);
  209. }
  210. $this->_writeKeys();
  211. return $keys;
  212. }
  213. /**
  214. * Store a query in cache
  215. *
  216. * @param string $query
  217. * @param array $result
  218. */
  219. public function setQuery($query, $result)
  220. {
  221. if ($this->isBlacklist($query))
  222. return true;
  223. if (empty($result) || $result === false)
  224. $result = array();
  225. if (is_null($this->sql_tables_cached))
  226. {
  227. $this->sql_tables_cached = $this->get(Tools::encryptIV(self::SQL_TABLES_NAME));
  228. if (!is_array($this->sql_tables_cached))
  229. $this->sql_tables_cached = array();
  230. }
  231. // Store query results in cache
  232. $key = Tools::encryptIV($query);
  233. // no need to check the key existence before the set : if the query is already
  234. // in the cache, setQuery is not invoked
  235. $this->set($key, $result);
  236. // Get all table from the query and save them in cache
  237. if ($tables = $this->getTables($query))
  238. foreach ($tables as $table)
  239. {
  240. if (!isset($this->sql_tables_cached[$table][$key]))
  241. {
  242. $this->adjustTableCacheSize($table);
  243. $this->sql_tables_cached[$table][$key] = true;
  244. }
  245. }
  246. $this->set(Tools::encryptIV(self::SQL_TABLES_NAME), $this->sql_tables_cached);
  247. }
  248. /**
  249. * Autoadjust the table cache size to avoid storing too big elements in the cache
  250. *
  251. * @param $table
  252. */
  253. protected function adjustTableCacheSize($table)
  254. {
  255. if (isset($this->sql_tables_cached[$table])
  256. && count($this->sql_tables_cached[$table]) > 5000)
  257. {
  258. // make sure the cache doesn't contains too many elements : delete the first 1000
  259. $table_buffer = array_slice($this->sql_tables_cached[$table], 0, 1000, true);
  260. foreach($table_buffer as $fs_key => $value)
  261. {
  262. $this->delete($fs_key);
  263. $this->delete($fs_key.'_nrows');
  264. unset($this->sql_tables_cached[$table][$fs_key]);
  265. }
  266. }
  267. }
  268. protected function getTables($string)
  269. {
  270. if (preg_match_all('/(?:from|join|update|into)\s+`?('._DB_PREFIX_.'[0-9a-z_-]+)(?:`?\s{0,},\s{0,}`?('._DB_PREFIX_.'[0-9a-z_-]+)`?)?(?:`|\s+|\Z)(?!\s*,)/Umsi', $string, $res))
  271. {
  272. foreach ($res[2] as $table)
  273. if ($table != '')
  274. $res[1][] = $table;
  275. return array_unique($res[1]);
  276. }
  277. else
  278. return false;
  279. }
  280. /**
  281. * Delete a query from cache
  282. *
  283. * @param string $query
  284. */
  285. public function deleteQuery($query)
  286. {
  287. if (is_null($this->sql_tables_cached))
  288. {
  289. $this->sql_tables_cached = $this->get(Tools::encryptIV(self::SQL_TABLES_NAME));
  290. if (!is_array($this->sql_tables_cached))
  291. $this->sql_tables_cached = array();
  292. }
  293. if ($tables = $this->getTables($query))
  294. foreach ($tables as $table)
  295. if (isset($this->sql_tables_cached[$table]))
  296. {
  297. foreach (array_keys($this->sql_tables_cached[$table]) as $fs_key)
  298. {
  299. $this->delete($fs_key);
  300. $this->delete($fs_key.'_nrows');
  301. }
  302. unset($this->sql_tables_cached[$table]);
  303. }
  304. $this->set(Tools::encryptIV(self::SQL_TABLES_NAME), $this->sql_tables_cached);
  305. }
  306. /**
  307. * Check if a query contain blacklisted tables
  308. *
  309. * @param string $query
  310. * @return bool
  311. */
  312. protected function isBlacklist($query)
  313. {
  314. foreach ($this->blacklist as $find)
  315. if (false !== strpos($query, _DB_PREFIX_.$find))
  316. return true;
  317. return false;
  318. }
  319. public static function store($key, $value)
  320. {
  321. // PHP is not efficient at storing array
  322. // Better delete the whole cache if there are
  323. // more than 1000 elements in the array
  324. if (count(Cache::$local) > 1000) {
  325. Cache::$local = array();
  326. }
  327. Cache::$local[$key] = $value;
  328. }
  329. public static function retrieve($key)
  330. {
  331. return isset(Cache::$local[$key]) ? Cache::$local[$key] : null;
  332. }
  333. public static function retrieveAll()
  334. {
  335. return Cache::$local;
  336. }
  337. public static function isStored($key)
  338. {
  339. return isset(Cache::$local[$key]);
  340. }
  341. public static function clean($key)
  342. {
  343. if (strpos($key, '*') !== false)
  344. {
  345. $regexp = str_replace('\\*', '.*', preg_quote($key, '#'));
  346. foreach (array_keys(Cache::$local) as $key)
  347. if (preg_match('#^'.$regexp.'$#', $key))
  348. unset(Cache::$local[$key]);
  349. }
  350. else
  351. unset(Cache::$local[$key]);
  352. }
  353. }