PageRenderTime 37ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/libs/php/cache_engine.php

http://web-optimizator.googlecode.com/
PHP | 1318 lines | 1263 code | 28 blank | 27 comment | 113 complexity | d6f44eab852f0b8ca2a857258c8205c3 MD5 | raw file
  1. <?php
  2. /**
  3. * File from WEBO Site SpeedUp, WEBO Software (http://www.webogroup.com/)
  4. * Classes for storing html cache
  5. * License agreement: http://www.webogroup.com/about/EULA.txt
  6. *
  7. **/
  8. /* Abstract class that defines basic methods and contains several methods for SQL caching*/
  9. class webo_cache_engine {
  10. /* Class constructor. Expects options array. */
  11. function webo_cache_engine($options) {
  12. if(strtolower(__CLASS__)=='baseclass'){
  13. trigger_error('This class is abstract!',E_USER_ERROR);
  14. exit();
  15. }
  16. }
  17. /* Adds or updates entry. Expects key string and value to cache. */
  18. function put_entry($key, $value, $time) {
  19. if(strtolower(__CLASS__)=='baseclass'){
  20. trigger_error('This class is abstract!',E_USER_ERROR);
  21. exit();
  22. }
  23. }
  24. /* Get cache entry by key. Expects key string. */
  25. function get_entry($key) {
  26. if(strtolower(__CLASS__)=='baseclass'){
  27. trigger_error('This class is abstract!',E_USER_ERROR);
  28. exit();
  29. }
  30. }
  31. /* Clean cache entries by timestamp. Expects timestamp and time interval (in minutes). */
  32. function delete_entries_by_time ($time, $interval) {
  33. if(strtolower(__CLASS__)=='baseclass'){
  34. trigger_error('This class is abstract!',E_USER_ERROR);
  35. exit();
  36. }
  37. }
  38. /* Clean cache entries by pattern(s). Expects pattern or array of patterns. */
  39. function delete_entries($patterns) {
  40. if(strtolower(__CLASS__)=='baseclass'){
  41. trigger_error('This class is abstract!',E_USER_ERROR);
  42. exit();
  43. }
  44. }
  45. /* Gets creation time of cache entry. Expects key string. */
  46. function get_mtime($key) {
  47. if(strtolower(__CLASS__)=='baseclass'){
  48. trigger_error('This class is abstract!',E_USER_ERROR);
  49. exit();
  50. }
  51. }
  52. /* Sets creation time of cache entry. Expects key string and time to set. */
  53. function set_mtime($key, $time) {
  54. if(strtolower(__CLASS__)=='baseclass'){
  55. trigger_error('This class is abstract!',E_USER_ERROR);
  56. exit();
  57. }
  58. }
  59. function get_cache_size($mask, $number = false) {
  60. if(strtolower(__CLASS__)=='baseclass'){
  61. trigger_error('This class is abstract!',E_USER_ERROR);
  62. exit();
  63. }
  64. }
  65. /* Returns array with information about given query. */
  66. function get_query_info($sql) {
  67. $sql = ltrim($sql);
  68. $quote = 0;
  69. $slash = 0;
  70. $table_stage = false;
  71. $table_now = false;
  72. $word = false;
  73. $table = array();
  74. $change = false;
  75. $select = false;
  76. $alias_now = false;
  77. $cur_word = '';
  78. $words = explode(' ', $sql, 2);
  79. $first_word = strtolower($words[0]);
  80. if ($first_word == 'select') {
  81. $sql = $words[1];
  82. $select = true;
  83. }
  84. elseif ($first_word == 'delete') {
  85. $sql = $words[1];
  86. $sql = ltrim($sql);
  87. $words = explode(' ', $sql, 2);
  88. $second_word = strtolower($words[0]);
  89. if ($second_word == 'from') {
  90. $sql = $words[1];
  91. $change = true;
  92. $table_stage = true;
  93. } else {
  94. return array('select' => $select, 'table' => $table, 'change' => $change);
  95. }
  96. } elseif ($first_word == 'insert') {
  97. $sql = $words[1];
  98. $sql = ltrim($sql);
  99. $words = explode(' ', $sql, 2);
  100. $second_word = strtolower($words[0]);
  101. if ($second_word == 'into') {
  102. $sql = $words[1];
  103. $change = true;
  104. $table_stage = true;
  105. } else {
  106. return array('select' => $select, 'table' => $table, 'change' => $change);
  107. }
  108. } elseif ($first_word == 'update') {
  109. $sql = $words[1];
  110. $change = true;
  111. $table_stage = true;
  112. } else {
  113. return array('select' => $select, 'table' => $table, 'change' => $change);
  114. }
  115. $table_now = $change;
  116. for ($i = 0; $i < strlen($sql); $i++) {
  117. if ($table_stage == true) {
  118. if ($quote == 0) {
  119. if ($sql[$i] == '`') {
  120. $word = true;
  121. $quote = 1;
  122. } elseif ($sql[$i] == '\'') {
  123. $word = true;
  124. $quote = 2;
  125. } elseif ($sql[$i] == '"') {
  126. $word = true;
  127. $quote = 3;
  128. } elseif (($sql[$i] != ' ') && ($sql[$i] != ',') && ($sql[$i] != "\n") && ($word === false)) {
  129. $word = true;
  130. $cur_word = $sql[$i];
  131. } elseif ((($sql[$i] == ' ') || ($sql[$i] == ',') || ($sql[$i] == "\n")) && ($word === true)) {
  132. $cur_word = strtolower($cur_word);
  133. if (($cur_word == 'from') || ($cur_word == 'join')) {
  134. $table_now = true;
  135. } elseif (in_array($cur_word, array('where', 'group', 'having', 'order', 'limit', 'procedure', 'into'))) {
  136. $i = strlen($sql);
  137. } elseif ($table_now == true) {
  138. $cur_word = str_replace($this->sql_prefix, '', $cur_word);
  139. $table[$cur_word] = true;
  140. if ($change == true) {
  141. $i = strlen($sql);
  142. } elseif ($sql[$i] == ',') {
  143. $table_now = true;
  144. } else {
  145. $alias_now = true;
  146. $table_now = false;
  147. }
  148. } elseif (($alias_now == true) && ($cur_word != 'as')) {
  149. $alias_now = false;
  150. if ($sql[$i] == ',') {
  151. $table_now = true;
  152. }
  153. }
  154. $word = false;
  155. $cur_word = '';
  156. } elseif ($word == true) {
  157. $cur_word .= $sql[$i];
  158. }
  159. } elseif ((($quote == 1) && ($sql[$i] == '`')) || (($quote == 2) && ($sql[$i] == '\'')) || (($quote == 3) && ($sql[$i] == '"'))) {
  160. if ($slash == 0) {
  161. $quote = 0;
  162. } else {
  163. $cur_word .= $sql[$i];
  164. $slash = 0;
  165. }
  166. } elseif ($sql[$i] == '\\') {
  167. $slash = 1 - $slash;
  168. } else {
  169. $cur_word .= $sql[$i];
  170. }
  171. } else {
  172. if ($quote == 0) {
  173. if ($sql[$i] == '`') {
  174. $quote = 1;
  175. } elseif ($sql[$i] == '\'') {
  176. $quote = 2;
  177. } elseif ($sql[$i] == '"') {
  178. $quote = 3;
  179. } elseif (($sql[$i] != ' ') && ($sql[$i] != ',') && ($sql[$i] != "\n") && ($word === false)) {
  180. $word = true;
  181. $cur_word = $sql[$i];
  182. } elseif ((($sql[$i] == ' ') || ($sql[$i] == ',') || ($sql[$i] == "\n")) && ($word === true)) {
  183. if (strtolower($cur_word) == 'from') {
  184. $table_stage = true;
  185. $table_now = true;
  186. }
  187. $word = false;
  188. $cur_word = '';
  189. } elseif ($word == true) {
  190. $cur_word .= $sql[$i];
  191. }
  192. } elseif ((($quote == 1) && ($sql[$i] == '`')) || (($quote == 2) && ($sql[$i] == '\'')) || (($quote == 3) && ($sql[$i] == '"'))) {
  193. if ($slash == 0) {
  194. $quote = 0;
  195. } else {
  196. $slash = 1;
  197. }
  198. } elseif ($sql[$i] == '\\') {
  199. $slash = 1 - $slash;
  200. }
  201. }
  202. }
  203. return array('select' => $select, 'table' => $table, 'change' => $change);
  204. }
  205. function start_sql_cache ($compress_options, $prefix = '') {
  206. $queries = $this->get_entry('cached_queries.sql');
  207. if ($queries) {
  208. $this->sql_cached_queries = unserialize($queries);
  209. } else {
  210. $this->sql_cached_queries = array();
  211. }
  212. $info = $this->get_entry('info.sql');
  213. if ($info) {
  214. $info = unserialize($info);
  215. $this->sql_tables = $info['tables'];
  216. $this->sql_table_queries = $info['table_queries'];
  217. $this->sql_last_ids = $info['last_ids'];
  218. } else {
  219. $this->sql_tables = array();
  220. $this->sql_table_queries = array();
  221. $this->sql_last_ids = array('table' => 0, 'query' => 0);
  222. }
  223. $this->sql_cache_time = $compress_options['sql_cache']['time'];
  224. $this->sql_exclude_tables = explode(' ', $compress_options['sql_cache']['tables_exclude']);
  225. $this->sql_cache_timeout = $compress_options['sql_cache']['timeout'];
  226. $this->sql_cache_enabled = true;
  227. $this->current_time = time();
  228. $this->sql_cached_result = false;
  229. $this->sql_cached_rows = 0;
  230. $this->sql_cache_changed = false;
  231. $this->sql_prefix = $prefix;
  232. $this->clear_expired_sql();
  233. }
  234. function save_sql_cache() {
  235. if (!empty($this->sql_cache_enabled) && ($this->sql_cache_changed)) {
  236. $this->put_entry('info.sql', serialize(array('tables' => $this->sql_tables, 'table_queries' => $this->sql_table_queries, 'last_ids' => $this->sql_last_ids)), $this->current_time);
  237. $this->put_entry('cached_queries.sql', serialize($this->sql_cached_queries), $this->current_time);
  238. }
  239. }
  240. function get_query_options($sql) {
  241. $change = false;
  242. $cache_me = false;
  243. $cache_hit = false;
  244. $start = 0;
  245. $tables = array();
  246. $key = $sql;
  247. if ($this->sql_cache_timeout >= 3600) {
  248. $key = preg_replace('/(\d\d\d\d-\d\d-\d\d \d\d:)\d\d:\d\d/', '${1}00:00', $key);
  249. } elseif ($this->sql_cache_timeout >= 600) {
  250. $key = preg_replace('/(\d\d\d\d-\d\d-\d\d \d\d:\d)\d:\d\d/', '${1}0:00', $key);
  251. } elseif ($this->sql_cache_timeout >= 60) {
  252. $key = preg_replace('/(\d\d\d\d-\d\d-\d\d \d\d:\d\d:)\d\d/', '${1}00', $key);
  253. } elseif ($this->sql_cache_timeout >= 10) {
  254. $key = preg_replace('/(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d)\d/', '${1}0', $key);
  255. }
  256. if (!empty($this->sql_cache_enabled)) {
  257. $query_info = $this->get_query_info($sql);
  258. $tables = $query_info['table'];
  259. foreach ($tables as $table => $value) {
  260. if (in_array($table, $this->sql_exclude_tables)) {
  261. $query_info['select'] = false;
  262. $query_info['change'] = false;
  263. }
  264. }
  265. $change = $query_info['change'];
  266. }
  267. if (!empty($this->sql_cache_enabled) && ($query_info['select'])) {
  268. if (!empty($this->sql_cached_queries[$key])) {
  269. $query = $this->sql_cached_queries[$key];
  270. if (($this->current_time - $query['time'] < $this->sql_cache_timeout)) {
  271. $this->sql_cached_result = $query['result'];
  272. $this->sql_cached_rows = $query['num_rows'];
  273. $cache_hit = true;
  274. }
  275. }
  276. $start = explode(' ', microtime());
  277. $start = $start[1] + $start[0];
  278. $cache_me = true;
  279. }
  280. return(array($cache_me, $change, $cache_hit, $tables, $start, $key));
  281. }
  282. function add_to_sql_cache($mysql_result, $start, $query_tables, $sql) {
  283. if (!is_resource($mysql_result) || (stripos(get_resource_type($mysql_result), 'mysql') === false)) {
  284. return false;
  285. }
  286. $end = explode(' ', microtime());
  287. $end = $end[1] + $end[0];
  288. if (((($end - $start) * 1000) > $this->sql_cache_time)) {
  289. $this->sql_cache_changed = true;
  290. $query_id = $this->sql_last_ids['query'];
  291. $this->sql_last_ids['query']++;
  292. foreach ($this->sql_tables as $table => $id) {
  293. if (!empty($query_tables[$table])) {
  294. unset($query_tables[$table]);
  295. $this->sql_table_queries[$id][$query_id] = true;
  296. }
  297. }
  298. foreach ($query_tables as $table => $value) {
  299. $id = $this->sql_last_ids['table'];
  300. $this->sql_tables[$table] = $id;
  301. $this->sql_table_queries[$id][$query_id] = true;
  302. $this->sql_last_ids['table']++;
  303. }
  304. $this->sql_cached_queries[$sql] = array('time' => $this->current_time, 'id' => $query_id);
  305. $result_array = array();
  306. $num_rows = 0;
  307. while ($row = mysql_fetch_assoc($mysql_result)) {
  308. $num_rows++;
  309. $result_array[] = $row;
  310. }
  311. $this->sql_cached_result = $result_array;
  312. $this->sql_cached_rows = $num_rows;
  313. $this->sql_cached_queries[$sql]['result'] = $result_array;
  314. $this->sql_cached_queries[$sql]['num_rows'] = $num_rows;
  315. return true;
  316. } else {
  317. return false;
  318. }
  319. }
  320. function clear_expired_sql() {
  321. if (empty($this->sql_cached_queries) || !is_array($this->sql_cached_queries)) {
  322. return;
  323. }
  324. foreach ($this->sql_cached_queries as $query => $info) {
  325. if ($this->current_time - $info['time'] > $this->sql_cache_timeout) {
  326. $this->sql_cache_changed = true;
  327. unset($this->sql_cached_queries[$query]);
  328. foreach ($this->sql_table_queries as $id => $queries) {
  329. unset($this->sql_table_queries[$id][$info['id']]);
  330. }
  331. }
  332. }
  333. }
  334. function update_sql_cache($tables) {
  335. foreach ($tables as $table => $value) {
  336. break;
  337. }
  338. if (isset($this->sql_tables[$table])) {
  339. $this->sql_cache_changed = true;
  340. $table_id = $this->sql_tables[$table];
  341. $drop_queries = $this->sql_table_queries[$table_id];
  342. $this->sql_table_queries[$table_id] = array();
  343. foreach ($this->sql_table_queries as $table_id => $queries) {
  344. if (count($this->sql_table_queries[$table_id]) != 0) {
  345. foreach ($drop_queries as $query_id => $value) {
  346. if (!empty($queries[$query_id])) {
  347. unset($this->sql_table_queries[$table_id][$query_id]);
  348. }
  349. }
  350. }
  351. }
  352. $max_id = 0;
  353. foreach ($this->sql_cached_queries as $query => $info) {
  354. foreach ($drop_queries as $query_id => $value) {
  355. if ($info['id'] == $query_id) {
  356. unset($this->sql_cached_queries[$query]);
  357. } elseif ($info['id'] > $max_id) {
  358. $max_id = $info['id'];
  359. }
  360. }
  361. }
  362. $this->sql_last_ids['query'] = $max_id + 1;
  363. }
  364. }
  365. function clear_sql_cache() {
  366. if (!$this->enabled) {
  367. $this->enabled = true;
  368. $result = $this->delete_entries(array('cached_queries.sql', 'info.sql'));
  369. $this->enabled = false;
  370. } else {
  371. $result = $this->delete_entries(array('cached_queries.sql', 'info.sql'));
  372. }
  373. return $result;
  374. }
  375. }
  376. /* Here starts the section with different implementations of cache_engine abstract class. Every class name should start with 'cache_' and use some specific name for particular engine. For example, cache_files (stores cache items on filesystem) or cache_memcached (uses memcached to store cache items).
  377. /* Default implementation that stores cache entries on filesystem */
  378. class webo_cache_files extends webo_cache_engine
  379. {
  380. /* Class constructor. Expects cache directory as option and checks if it's writable. */
  381. function webo_cache_files($options) {
  382. /**
  383. * A better "fnmatch" alternative for windows that converts a fnmatch
  384. * pattern into a preg one. It should work on PHP >= 4.0.0.
  385. * @author soywiz at php dot net
  386. * @since 17-Jul-2006 10:12
  387. */
  388. if (!function_exists('fnmatch')) {
  389. function fnmatch($pattern, $string) {
  390. return @preg_match('/^' . strtr(addcslashes($pattern, '\\.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $string);
  391. }
  392. }
  393. $this->_host = strtolower(empty($options['host']) ? '' : preg_replace('/\\.+\\/+/','', str_replace(array('+',"'",'^','%','"','<','>','$'), array('/','','','','','','',''), $options['host'])));
  394. $this->_host_wo_www = preg_replace("!^www\.!i", "", $this->_host);
  395. $this->_host_w_www = 'www.' . $this->_host_wo_www;
  396. if(!empty($options['cache_dir'])) {
  397. $this->enabled = true;
  398. $this->cache_dir = $options['cache_dir'];
  399. } else {
  400. $this->enabled = false;
  401. }
  402. $this->all_files = false;
  403. /* large files list can cause 500 error */
  404. if (round(str_replace("M", "000000", str_replace("K", "000", @ini_get('memory_limit')))) < 128000000) {
  405. @ini_set('memory_limit', '128M');
  406. }
  407. }
  408. /* Read wo.files.php to all_files array */
  409. function __get_files_list() {
  410. global $webo_files_list_var, $webo_files_list_ok;
  411. $webo_files_list_var = $this->cache_dir . 'wo.files.php';
  412. if ($this->all_files === false) {
  413. try {
  414. @include($webo_files_list_var);
  415. } catch (Exception $e) {}
  416. if (isset($webo_cache_files_list) && is_array($webo_cache_files_list)) {
  417. $this->all_files = $webo_cache_files_list;
  418. } else {
  419. $this->all_files = array();
  420. }
  421. if (!defined('WSS_CACHE_FILE')) {
  422. $this->__put_files_list();
  423. }
  424. }
  425. }
  426. /* Write all files' array to wo.files.php */
  427. function __put_files_list() {
  428. global $webo_files_list_var, $webo_files_list_ok;
  429. $str = "<?php\nif(!defined('WSS_CACHE_FILE')){define('WSS_CACHE_FILE','1');}\n";
  430. foreach ($this->all_files as $k => $v) {
  431. if (!is_array($v)) {
  432. $v = array($v, time());
  433. }
  434. $str .= '$webo_cache_files_list[\'' . addcslashes($k, "\0'\\") . '\'] = array(' . $v[0] . ',' . $v[1] . ");\n";
  435. }
  436. $str .= '?>';
  437. $length = strlen($str);
  438. $i = 0;
  439. $written = 0;
  440. $tmp = '.tmp.' . (time()+microtime());
  441. @file_put_contents($webo_files_list_var . $tmp, "<?php\nif(!defined('WSS_CACHE_FILE')){define('WSS_CACHE_FILE','1');}\n?>");
  442. while (($i < 3) && ($written != $length)) {
  443. $written = @file_put_contents($webo_files_list_var . $tmp, $str);
  444. $i++;
  445. }
  446. if (@is_file($webo_files_list_var . $tmp)) {
  447. if (@is_file($webo_files_list_var)) {
  448. /* need for APS.NET environments, why? */
  449. @unlink($webo_files_list_var);
  450. }
  451. @rename($webo_files_list_var . $tmp, $webo_files_list_var);
  452. @unlink($webo_files_list_var . $tmp);
  453. }
  454. }
  455. /* Adds or updates entry. Expects key string and value to cache. */
  456. function put_entry($key, $value, $time) {
  457. if (!$this->enabled) {
  458. return;
  459. }
  460. $path = $this->__get_path($key);
  461. if (!@is_dir(dirname($path))) {
  462. $this->__make_path($path);
  463. }
  464. $path .= @is_dir($path) ? '/index.html' : '';
  465. @file_put_contents($path . '.tmp', $value);
  466. if (!@is_dir($path)) {
  467. @rename($path . '.tmp', $path);
  468. @touch($path);
  469. if (@is_writable($path)) {
  470. @chmod($path, octdec("0644"));
  471. }
  472. $this->__get_files_list();
  473. $this->all_files[$path] = array(strlen($value), $time);
  474. $this->__put_files_list();
  475. }
  476. }
  477. /* Get cache entry by key. Expects key string. */
  478. function get_entry($key) {
  479. if (!$this->enabled) {
  480. return false;
  481. }
  482. $content = @is_file($this->__get_path($key)) ? @file_get_contents($this->__get_path($key)) : '';
  483. if (get_magic_quotes_runtime()) {
  484. $content = stripslashes($content);
  485. }
  486. return $content;
  487. }
  488. /* Clean cache entries by pattern(s). Expects pattern or array of patterns. */
  489. function delete_entries($patterns) {
  490. if (!$this->enabled) {
  491. return false;
  492. }
  493. $this->__get_files_list();
  494. if (!empty($patterns)) {
  495. if (is_array($patterns)) {
  496. foreach($patterns as $pattern) {
  497. $files = $this->__recurse_glob($this->__get_path($pattern));
  498. foreach($files as $file) {
  499. if (@is_file($file)) {
  500. @unlink($file);
  501. unset($this->all_files[$file]);
  502. } elseif (@is_dir($file)) {
  503. $this->__recurse_rm($file);
  504. }
  505. }
  506. }
  507. } else {
  508. if ($patterns == '*') {
  509. /* try to call shell_exec */
  510. if (strpos(@ini_get('disable_functions') . ' ' . @ini_get('suhosin.executor.func.blacklist'), 'shell_exec') === false && !@ini_get('safe_mode')) {
  511. try {
  512. @shell_exec('rm -rf ' . $this->cache_dir . $this->_host_w_www);
  513. @shell_exec('rm -rf ' . $this->cache_dir . $this->_host_wo_www);
  514. } catch (Expression $e) {}
  515. }
  516. $this->__recurse_rm($this->cache_dir . $this->_host_w_www);
  517. $this->__recurse_rm($this->cache_dir . $this->_host_wo_www);
  518. } else {
  519. $files = $this->__recurse_glob($this->__get_path($patterns));
  520. foreach($files as $file) {
  521. if (@is_file($file)) {
  522. @unlink($file);
  523. unset($this->all_files[$file]);
  524. } elseif (@is_dir($file)) {
  525. $this->__recurse_rm($file);
  526. }
  527. }
  528. }
  529. }
  530. $this->__put_files_list();
  531. }
  532. }
  533. /* Clean cache entries by timestamp. Expects timestamp and time interval (in minutes). */
  534. function delete_entries_by_time ($time, $interval) {
  535. if (!$this->enabled) {
  536. return false;
  537. }
  538. $this->__get_files_list();
  539. if (!empty($time)) {
  540. $changed = 0;
  541. foreach($this->all_files as $path => $entry) {
  542. if (!is_array($entry)) {
  543. $entry = array($entry, @filemtime($path));
  544. }
  545. if ($entry[1] + $interval < $time) {
  546. if (@is_file($path)) {
  547. @unlink($path);
  548. }
  549. unset($this->all_files[$path]);
  550. $changed = 1;
  551. }
  552. }
  553. if ($changed) {
  554. $this->__put_files_list();
  555. }
  556. }
  557. }
  558. /* Gets creation time of cache entry. Expects key string. */
  559. function get_mtime($key) {
  560. if (!$this->enabled) {
  561. return 0;
  562. }
  563. $this->__get_files_list();
  564. $path = $this->__get_path($key);
  565. if (!empty($this->all_files[$path])) {
  566. $entry = $this->all_files[$path];
  567. if (!is_array($entry)) {
  568. $entry = array($entry, @filemtime($path));
  569. }
  570. return $entry[1];
  571. } else {
  572. return 0;
  573. }
  574. }
  575. /* Sets creation time of cache entry. Expects key string and time to set. */
  576. function set_mtime($key, $time) {
  577. if (!$this->enabled) {
  578. return false;
  579. }
  580. $this->__get_files_list();
  581. $path = $this->__get_path($key);
  582. $this->all_files[$path][1] = $time;
  583. $this->__put_files_list();
  584. @touch($path, $time);
  585. }
  586. /* Gets path to file from cache entry key */
  587. function __get_path($key, $host = '') {
  588. $cur_host = strtolower($_SERVER['HTTP_HOST']);
  589. $set_host = strtolower($host);
  590. if (empty($host)) {
  591. $key = $cur_host . '/' . $key;
  592. } elseif ($cur_host == $set_host) {
  593. return ''; //thx to peterbowey
  594. } else {
  595. $key = $set_host . '/' . $key;
  596. }
  597. $key = preg_replace("!/+!", "/", preg_replace('/\\.+\\/+/','',$this->cache_dir . str_replace(array('+',"'",'^','%','"','<','>','$'), array('/','','','','','','',''), $key)));
  598. while (@is_dir($key)) {
  599. @chmod($key, octdec("0755"));
  600. $key .= '/index.html';
  601. }
  602. return $key;
  603. }
  604. /* Creates directory structure to store the file */
  605. function __make_path($path) {
  606. $dirs = explode('/', dirname($path));
  607. $cur_dir = $path{0} == '/' ? '/' : '';
  608. $basedirs = explode(":", @ini_get('open_basedir'));
  609. $allow_basedirs = !count($basedirs) || empty($basedirs[0]);
  610. if (!$allow_basedirs) {
  611. foreach ($basedirs as $basedir) {
  612. if (strpos($path, $basedir) === 0) {
  613. $cur_dir = dirname($basedir) . '/';
  614. $dirs = explode('/', str_replace($cur_dir, '', $path));
  615. $allow_basedirs = 1;
  616. continue;
  617. }
  618. }
  619. }
  620. if ($allow_basedirs) {
  621. foreach ($dirs as $dir) {
  622. if (!empty($dir)) {
  623. $cur_dir .= $dir . '/';
  624. if (!@is_dir($cur_dir)) {
  625. @mkdir($cur_dir, octdec("0755"));
  626. }
  627. }
  628. }
  629. }
  630. }
  631. /* Internal method that returns all keys that match given pattern. Expects pattern. */
  632. function __recurse_glob($pattern, $size = false, $number = false) {
  633. if ($pattern == '') {
  634. return array();
  635. }
  636. $split = explode('/', str_replace('\\', '/', $pattern));
  637. $mask = array_pop($split);
  638. $path = implode('/', $split);
  639. $this->__get_files_list();
  640. $path = str_replace('.', '\\.', $path);
  641. $path = str_replace('*', '.*', $path);
  642. if ($size === false) {
  643. $glob = array();
  644. } else {
  645. if ($number === false) {
  646. $glob = 0;
  647. } else {
  648. $glob = array(0, 0);
  649. }
  650. }
  651. foreach ($this->all_files as $key => $value) {
  652. if (preg_match('!' . $path . '!', $key)) {
  653. if ($size === false) {
  654. $glob[] = $key;
  655. } else {
  656. if ($number === false) {
  657. $glob += $value;
  658. } else {
  659. $glob[0] += $value;
  660. $glob[1]++;
  661. }
  662. }
  663. }
  664. }
  665. return $glob;
  666. }
  667. function __recurse_rm($path) {
  668. if (@is_dir($path)) {
  669. if (substr($path, strlen($path) - 1) != '/') {
  670. $path .= '/';
  671. }
  672. $dh = @opendir($path);
  673. while (($file = @readdir($dh)) !== false) {
  674. if (($file == '.') || ($file == '..')) {
  675. //do nothing
  676. } elseif (is_dir($path . $file)) {
  677. $this->__recurse_rm($path . $file);
  678. }
  679. else {
  680. if (isset($this->all_files[$path . $file])) {
  681. unset($this->all_files[$path . $file]);
  682. }
  683. @unlink($path . $file);
  684. }
  685. }
  686. @closedir($dh);
  687. @rmdir($path);
  688. } else {
  689. @unlink($path);
  690. }
  691. }
  692. /* Gets total size and number of cache files defined by mask */
  693. function get_cache_size($mask, $number = false) {
  694. $this->__get_files_list();
  695. if (!$this->enabled) {
  696. if ($number === false) {
  697. return 0;
  698. } else {
  699. return array(0,0);
  700. }
  701. }
  702. $mask = str_replace('.', '\\.', $mask);
  703. $mask = str_replace('*', '.*', $mask);
  704. $size = 0;
  705. $num = 0;
  706. foreach ($this->all_files as $key => $value) {
  707. if (preg_match('/' . $mask . '/', $key)) {
  708. if (!is_array($value)) {
  709. $value = array($value);
  710. }
  711. $size += $value[0];
  712. $num++;
  713. }
  714. }
  715. if ($number === false) {
  716. return $size;
  717. } else {
  718. return array($size, $num);
  719. }
  720. }
  721. }
  722. class webo_cache_memcached extends webo_cache_engine {
  723. /* Class constructor. Expects options array. */
  724. function webo_cache_memcached($options) {
  725. $this->enabled = false;
  726. $this->cached = array();
  727. $this->prefix = 'webo_cache_'; //maybe memcached stores data from other applications
  728. if(!empty($options['server'])) {
  729. $server = explode(':', $options['server']); //get server and port
  730. if(!empty($server[1])) {
  731. if (@class_exists('Memcached')) {
  732. $this->connection = new Memcached();
  733. } elseif (@class_exists('Memcache')) {
  734. $this->connection = new Memcache();
  735. }
  736. if($this->connection) {
  737. if ($this->connection->addServer($server[0], $server[1])) { //add server to store files
  738. $this->enabled = true;
  739. }
  740. }
  741. }
  742. }
  743. }
  744. /* Adds or updates entry. Expects key string and value to cache. */
  745. function put_entry($key, $value, $time) {
  746. if (!$this->enabled) {
  747. return;
  748. }
  749. $entries = $this->connection->get('webo_files_list');
  750. if(($entries === false) || !is_array($entries)) { //filelist is broken or removed from server so we need to clear cache
  751. $this->connection->flush(); //this removes all other applications data but is only way to do it
  752. $entries = array();
  753. }
  754. $this->connection->set($this->prefix . $key, array('value' => $value, 'time' => $time));
  755. $entries[$key] = 1;
  756. $this->connection->set('webo_files_list', $entries);
  757. }
  758. /* Get cache entry by key. Expects key string. */
  759. function get_entry($key) {
  760. if (!$this->enabled) {
  761. return false;
  762. }
  763. if (!empty($this->cached[$key]['value'])) {
  764. return $this->cached[$key]['value'];
  765. }
  766. $item = $this->connection->get($this->prefix . $key);
  767. if(empty($item['value'])) {
  768. return false;
  769. } else {
  770. $this->cached[$key] = $item;
  771. return $item['value'];
  772. }
  773. }
  774. /* Clean cache entries by timestamp. Expects timestamp and time interval (in minutes). */
  775. function delete_entries_by_time ($time, $interval) {
  776. if (!$this->enabled) {
  777. return false;
  778. }
  779. if (!empty($time)) {
  780. $all_files = $this->connection->get('webo_files_list');
  781. if(($all_files === false) || !is_array($all_files)) {
  782. $this->connection->flush();
  783. $this->connection->set('webo_files_list', array());
  784. return;
  785. }
  786. $changed = 0;
  787. foreach($all_files as $key => $value) {
  788. $t = $this->get_mtime($key);
  789. if ($t + $interval < $time) {
  790. $this->connection->delete($this->prefix . $key);
  791. unset($all_files[$key]);
  792. $changed = 1;
  793. }
  794. }
  795. if ($changed) {
  796. $this->connection->set('webo_files_list', $all_files);
  797. }
  798. }
  799. }
  800. /* Clean cache entries by pattern(s). Expects pattern or array of patterns. */
  801. function delete_entries($patterns) {
  802. if (!$this->enabled) {
  803. return false;
  804. }
  805. if (!empty($patterns)) {
  806. $all_files = $this->connection->get('webo_files_list');
  807. if (($all_files === false) || !is_array($all_files)) {
  808. $this->connection->flush();
  809. $this->connection->set('webo_files_list', array());
  810. return;
  811. }
  812. if (is_array($patterns)) {
  813. foreach($patterns as $pattern) {
  814. foreach($all_files as $key => $value) {
  815. if(@preg_match('/^' . strtr(addcslashes($pattern, '\\.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $key)) {
  816. $this->connection->delete($this->prefix . $key);
  817. unset($all_files[$key]);
  818. }
  819. }
  820. }
  821. $this->connection->set('webo_files_list', $all_files);
  822. } else {
  823. foreach($all_files as $key => $value) {
  824. if(@preg_match('/^' . strtr(addcslashes($patterns, '\\.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $key)) {
  825. $this->connection->delete($this->prefix . $key);
  826. unset($all_files[$key]);
  827. }
  828. }
  829. $this->connection->set('webo_files_list', $all_files);
  830. }
  831. }
  832. }
  833. /* Gets creation time of cache entry. Expects key string. */
  834. function get_mtime($key) {
  835. if (!$this->enabled) {
  836. return 0;
  837. }
  838. if (!empty($this->cached[$key]['time'])) {
  839. return $this->cached[$key]['time'];
  840. }
  841. $item = $this->connection->get($this->prefix . $key);
  842. if (empty($item['time'])) {
  843. return 0;
  844. } else {
  845. $this->cached[$key] = $item;
  846. return $item['time'];
  847. }
  848. }
  849. /* Sets creation time of cache entry. Expects key string and time to set. */
  850. function set_mtime($key, $time) {
  851. if (!$this->enabled) {
  852. return false;
  853. }
  854. $item = $this->connection->get($this->prefix . $key);
  855. if (empty($item['time'])) {
  856. return false;
  857. } else {
  858. $item['time'] = $time;
  859. $this->connection->set($this->prefix . $key, $item);
  860. }
  861. }
  862. function get_cache_size($mask, $number = false) {
  863. if (!$this->enabled) {
  864. if ($number === false) {
  865. return 0;
  866. } else {
  867. return array(0,0);
  868. }
  869. }
  870. $size = 0;
  871. $count = 0;
  872. $all_files = $this->connection->get('webo_files_list');
  873. if(($all_files === false) || !is_array($all_files)) {
  874. $this->connection->flush();
  875. $this->connection->set('webo_files_list', array());
  876. } else {
  877. foreach($all_files as $key => $value) {
  878. if(@preg_match('/^' . strtr(addcslashes($mask, '\\.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $key)) {
  879. $item = $this->connection->get($this->prefix . $key);
  880. if ($item !== false) {
  881. $count++;
  882. $size += strlen(serialize($item));
  883. }
  884. }
  885. }
  886. }
  887. if ($number === false) {
  888. return $size;
  889. } else {
  890. return array($size, $count);
  891. }
  892. }
  893. }
  894. class webo_cache_apc extends webo_cache_engine {
  895. /* Class constructor. Expects options array. */
  896. function webo_cache_apc($options) {
  897. if(function_exists('apc_add')) {
  898. ini_set('apc.slam_defense','Off');
  899. $this->enabled = true;
  900. } else {
  901. $this->enabled = false;
  902. }
  903. $this->cached = array();
  904. $this->prefix = 'webo_cache_';
  905. }
  906. /* Adds or updates entry. Expects key string and value to cache. */
  907. function put_entry($key, $value, $time) {
  908. if (!$this->enabled) {
  909. return;
  910. }
  911. $entries = apc_fetch('webo_files_list');
  912. if(($entries === false) || !is_array($entries)) { //filelist is broken or removed from server so we need to clear cache
  913. apc_clear_cache('user');
  914. $entries = array();
  915. }
  916. apc_store($this->prefix . $key, array('value' => $value, 'time' => $time));
  917. $entries[$key] = 1;
  918. apc_store('webo_files_list', $entries);
  919. }
  920. /* Get cache entry by key. Expects key string. */
  921. function get_entry($key) {
  922. if (!$this->enabled) {
  923. return false;
  924. }
  925. if (!empty($this->cached[$key]['value'])) {
  926. return $this->cached[$key]['value'];
  927. }
  928. $item = apc_fetch($this->prefix . $key);
  929. if(empty($item['value'])) {
  930. return false;
  931. } else {
  932. $this->cached[$key] = $item;
  933. return $item['value'];
  934. }
  935. }
  936. /* Clean cache entries by timestamp. Expects timestamp and time interval (in minutes). */
  937. function delete_entries_by_time ($time, $interval) {
  938. if (!$this->enabled) {
  939. return false;
  940. }
  941. if (!empty($time)) {
  942. $all_files = apc_fetch('webo_files_list');
  943. if(($all_files === false) || !is_array($all_files)) {
  944. apc_clear_cache('user');
  945. apc_store('webo_files_list', array());
  946. return;
  947. }
  948. $changed = 0;
  949. foreach($all_files as $key => $value) {
  950. $t = $this->get_mtime($key);
  951. if ($t + $interval < $time) {
  952. apc_delete($this->prefix . $key);
  953. unset($all_files[$key]);
  954. $changed = 1;
  955. }
  956. }
  957. if ($changed) {
  958. apc_store('webo_files_list', $all_files);
  959. }
  960. }
  961. }
  962. /* Clean cache entries by pattern(s). Expects pattern or array of patterns. */
  963. function delete_entries($patterns) {
  964. if (!$this->enabled) {
  965. return false;
  966. }
  967. if (!empty($patterns)) {
  968. $all_files = apc_fetch('webo_files_list');
  969. if(($all_files === false) || !is_array($all_files)) {
  970. apc_clear_cache('user');
  971. apc_store('webo_files_list', array());
  972. return;
  973. }
  974. if (is_array($patterns)) {
  975. foreach($patterns as $pattern) {
  976. foreach($all_files as $key => $value) {
  977. if(@preg_match('/^' . strtr(addcslashes($pattern, '\\.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $key)) {
  978. apc_delete($this->prefix . $key);
  979. unset($all_files[$key]);
  980. }
  981. }
  982. }
  983. apc_store('webo_files_list', $all_files);
  984. } else {
  985. foreach($all_files as $key => $value) {
  986. if(@preg_match('/^' . strtr(addcslashes($patterns, '\\.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $key))
  987. {
  988. apc_delete($this->prefix . $key);
  989. unset($all_files[$key]);
  990. }
  991. }
  992. apc_store('webo_files_list', $all_files);
  993. }
  994. }
  995. }
  996. /* Gets creation time of cache entry. Expects key string. */
  997. function get_mtime($key) {
  998. if (!$this->enabled) {
  999. return 0;
  1000. }
  1001. if(!empty($this->cached[$key]['time'])) {
  1002. return $this->cached[$key]['time'];
  1003. }
  1004. $item = apc_fetch($this->prefix . $key);
  1005. if (empty($item['time'])) {
  1006. return 0;
  1007. } else {
  1008. $this->cached[$key] = $item;
  1009. return $item['time'];
  1010. }
  1011. }
  1012. /* Sets creation time of cache entry. Expects key string and time to set. */
  1013. function set_mtime($key, $time) {
  1014. if (!$this->enabled) {
  1015. return false;
  1016. }
  1017. $item = apc_fetch($this->prefix . $key);
  1018. if (empty($item['time'])) {
  1019. return false;
  1020. } else {
  1021. $item['time'] = $time;
  1022. apc_store($key, $item);
  1023. }
  1024. }
  1025. function get_cache_size($mask, $number = false) {
  1026. if (!$this->enabled) {
  1027. if ($number === false) {
  1028. return 0;
  1029. } else {
  1030. return array(0,0);
  1031. }
  1032. }
  1033. $size = 0;
  1034. $count = 0;
  1035. $all_files = apc_fetch('webo_files_list');
  1036. if(($all_files === false) || !is_array($all_files)) {
  1037. apc_clear_cache();
  1038. apc_store('webo_files_list', array());
  1039. } else {
  1040. foreach($all_files as $key => $value) {
  1041. if (@preg_match('/^' . strtr(addcslashes($mask, '\\.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $key)) {
  1042. $item = apc_fetch($this->prefix . $key);
  1043. if ($item !== false) {
  1044. $count++;
  1045. $size += strlen(serialize($item));
  1046. }
  1047. }
  1048. }
  1049. }
  1050. if ($number === false) {
  1051. return $size;
  1052. } else {
  1053. return array($size, $count);
  1054. }
  1055. }
  1056. }
  1057. class webo_cache_xcache extends webo_cache_engine {
  1058. /* Class constructor. Expects options array. */
  1059. function webo_cache_xcache($options) {
  1060. if (function_exists('xcache_set')) {
  1061. $this->enabled = true;
  1062. } else {
  1063. $this->enabled = false;
  1064. }
  1065. $this->cached = array();
  1066. $this->prefix = 'webo_cache_';
  1067. }
  1068. /* Adds or updates entry. Expects key string and value to cache. */
  1069. function put_entry($key, $value, $time) {
  1070. if (!$this->enabled) {
  1071. return;
  1072. }
  1073. $entries = @xcache_get('webo_files_list');
  1074. if(($entries === NULL) || !is_array($entries)) { //filelist is broken or removed from server so we need to clear cache
  1075. @xcache_unset('user');
  1076. $entries = array();
  1077. }
  1078. @xcache_set($this->prefix . $key, array('value' => $value, 'time' => $time));
  1079. $entries[$key] = 1;
  1080. @xcache_set('webo_files_list', $entries);
  1081. }
  1082. /* Get cache entry by key. Expects key string. */
  1083. function get_entry($key) {
  1084. if (!$this->enabled) {
  1085. return false;
  1086. }
  1087. if (!empty($this->cached[$key]['value'])) {
  1088. return $this->cached[$key]['value'];
  1089. }
  1090. $item = @xcache_get($this->prefix . $key);
  1091. if(empty($item['value'])) {
  1092. return false;
  1093. } else {
  1094. $this->cached[$key] = $item;
  1095. return $item['value'];
  1096. }
  1097. }
  1098. /* Clean cache entries by timestamp. Expects timestamp and time interval (in minutes). */
  1099. function delete_entries_by_time ($time, $interval) {
  1100. if (!$this->enabled) {
  1101. return false;
  1102. }
  1103. if (!empty($time)) {
  1104. $all_files = @xcache_get('webo_files_list');
  1105. if (($all_files === NULL) || !is_array($all_files)) {
  1106. @xcache_unset('user');
  1107. @xcache_set('webo_files_list', array());
  1108. return;
  1109. }
  1110. $changed = 0;
  1111. foreach($all_files as $key => $value) {
  1112. $t = $this->get_mtime($key);
  1113. if ($t + $interval < $time) {
  1114. @xcache_unset($this->prefix . $key);
  1115. unset($all_files[$key]);
  1116. $changed = 1;
  1117. }
  1118. }
  1119. if ($changed) {
  1120. @xcache_set('webo_files_list', $all_files);
  1121. }
  1122. }
  1123. }
  1124. /* Clean cache entries by pattern(s). Expects pattern or array of patterns. */
  1125. function delete_entries($patterns) {
  1126. if (!$this->enabled) {
  1127. return false;
  1128. }
  1129. if (!empty($patterns)) {
  1130. $all_files = @xcache_get('webo_files_list');
  1131. if(($all_files === NULL) || !is_array($all_files)) {
  1132. @xcache_unset('user');
  1133. @xcache_set('webo_files_list', array());
  1134. return;
  1135. }
  1136. if (is_array($patterns)) {
  1137. foreach($patterns as $pattern) {
  1138. foreach($all_files as $key => $value) {
  1139. if (@preg_match('/^' . strtr(addcslashes($pattern, '\\.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $key)) {
  1140. @xcache_unset($this->prefix . $key);
  1141. unset($all_files[$key]);
  1142. }
  1143. }
  1144. }
  1145. @xcache_set('webo_files_list', $all_files);
  1146. } else {
  1147. foreach($all_files as $key => $value) {
  1148. if (@preg_match('/^' . strtr(addcslashes($patterns, '\\.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $key)) {
  1149. @xcache_unset($this->prefix . $key);
  1150. unset($all_files[$key]);
  1151. }
  1152. }
  1153. @xcache_set('webo_files_list', $all_files);
  1154. }
  1155. }
  1156. }
  1157. /* Gets creation time of cache entry. Expects key string. */
  1158. function get_mtime ($key) {
  1159. if (!$this->enabled) {
  1160. return 0;
  1161. }
  1162. if(!empty($this->cached[$key]['time'])) {
  1163. return $this->cached[$key]['time'];
  1164. }
  1165. $item = @xcache_get($this->prefix . $key);
  1166. if (empty($item['time'])) {
  1167. return 0;
  1168. } else {
  1169. $this->cached[$key] = $item;
  1170. return $item['time'];
  1171. }
  1172. }
  1173. /* Sets creation time of cache entry. Expects key string and time to set. */
  1174. function set_mtime($key, $time) {
  1175. if (!$this->enabled) {
  1176. return false;
  1177. }
  1178. $item = @xcache_get($this->prefix . $key);
  1179. if (empty($item['time'])) {
  1180. return false;
  1181. } else {
  1182. $item['time'] = $time;
  1183. @xcache_set($key, $item);
  1184. }
  1185. }
  1186. function get_cache_size($mask, $number = false) {
  1187. if (!$this->enabled) {
  1188. if ($number === false) {
  1189. return 0;
  1190. } else {
  1191. return array(0,0);
  1192. }
  1193. }
  1194. $size = 0;
  1195. $count = 0;
  1196. $all_files = @xcache_get('webo_files_list');
  1197. if (($all_files === NULL) || !is_array($all_files)) {
  1198. @xcache_set('webo_files_list', array());
  1199. } else {
  1200. foreach($all_files as $key => $value) {
  1201. if(@preg_match('/^' . strtr(addcslashes($mask, '\\.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $key)) {
  1202. $item = @xcache_get($this->prefix . $key);
  1203. if ($item !== NULL) {
  1204. $count++;
  1205. $size += strlen(serialize($item));
  1206. }
  1207. }
  1208. }
  1209. }
  1210. if ($number === false) {
  1211. return $size;
  1212. } else {
  1213. return array($size, $count);
  1214. }
  1215. }
  1216. }
  1217. ?>