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

/application/libraries/Zend/Cache/Frontend/Page.php

https://github.com/grandison/budo16
PHP | 402 lines | 241 code | 16 blank | 145 comment | 38 complexity | b19f421b52d275379068d019afbb424f MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  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@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Cache
  17. * @subpackage Zend_Cache_Frontend
  18. * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id: Page.php 16974 2009-07-22 19:23:08Z matthew $
  21. */
  22. /**
  23. * @see Zend_Cache_Core
  24. */
  25. // require_once 'Zend/Cache/Core.php';
  26. /**
  27. * @package Zend_Cache
  28. * @subpackage Zend_Cache_Frontend
  29. * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  30. * @license http://framework.zend.com/license/new-bsd New BSD License
  31. */
  32. class Zend_Cache_Frontend_Page extends Zend_Cache_Core
  33. {
  34. /**
  35. * This frontend specific options
  36. *
  37. * ====> (boolean) http_conditional :
  38. * - if true, http conditional mode is on
  39. * WARNING : http_conditional OPTION IS NOT IMPLEMENTED FOR THE MOMENT (TODO)
  40. *
  41. * ====> (boolean) debug_header :
  42. * - if true, a debug text is added before each cached pages
  43. *
  44. * ====> (boolean) content_type_memorization :
  45. * - deprecated => use memorize_headers instead
  46. * - if the Content-Type header is sent after the cache was started, the
  47. * corresponding value can be memorized and replayed when the cache is hit
  48. * (if false (default), the frontend doesn't take care of Content-Type header)
  49. *
  50. * ====> (array) memorize_headers :
  51. * - an array of strings corresponding to some HTTP headers name. Listed headers
  52. * will be stored with cache datas and "replayed" when the cache is hit
  53. *
  54. * ====> (array) default_options :
  55. * - an associative array of default options :
  56. * - (boolean) cache : cache is on by default if true
  57. * - (boolean) cacheWithXXXVariables (XXXX = 'Get', 'Post', 'Session', 'Files' or 'Cookie') :
  58. * if true, cache is still on even if there are some variables in this superglobal array
  59. * if false, cache is off if there are some variables in this superglobal array
  60. * - (boolean) makeIdWithXXXVariables (XXXX = 'Get', 'Post', 'Session', 'Files' or 'Cookie') :
  61. * if true, we have to use the content of this superglobal array to make a cache id
  62. * if false, the cache id won't be dependent of the content of this superglobal array
  63. * - (int) specific_lifetime : cache specific lifetime
  64. * (false => global lifetime is used, null => infinite lifetime,
  65. * integer => this lifetime is used), this "lifetime" is probably only
  66. * usefull when used with "regexps" array
  67. * - (array) tags : array of tags (strings)
  68. * - (int) priority : integer between 0 (very low priority) and 10 (maximum priority) used by
  69. * some particular backends
  70. *
  71. * ====> (array) regexps :
  72. * - an associative array to set options only for some REQUEST_URI
  73. * - keys are (pcre) regexps
  74. * - values are associative array with specific options to set if the regexp matchs on $_SERVER['REQUEST_URI']
  75. * (see default_options for the list of available options)
  76. * - if several regexps match the $_SERVER['REQUEST_URI'], only the last one will be used
  77. *
  78. * @var array options
  79. */
  80. protected $_specificOptions = array(
  81. 'http_conditional' => false,
  82. 'debug_header' => false,
  83. 'content_type_memorization' => false,
  84. 'memorize_headers' => array(),
  85. 'default_options' => array(
  86. 'cache_with_get_variables' => false,
  87. 'cache_with_post_variables' => false,
  88. 'cache_with_session_variables' => false,
  89. 'cache_with_files_variables' => false,
  90. 'cache_with_cookie_variables' => false,
  91. 'make_id_with_get_variables' => true,
  92. 'make_id_with_post_variables' => true,
  93. 'make_id_with_session_variables' => true,
  94. 'make_id_with_files_variables' => true,
  95. 'make_id_with_cookie_variables' => true,
  96. 'cache' => true,
  97. 'specific_lifetime' => false,
  98. 'tags' => array(),
  99. 'priority' => null
  100. ),
  101. 'regexps' => array()
  102. );
  103. /**
  104. * Internal array to store some options
  105. *
  106. * @var array associative array of options
  107. */
  108. protected $_activeOptions = array();
  109. /**
  110. * If true, the page won't be cached
  111. *
  112. * @var boolean
  113. */
  114. protected $_cancel = false;
  115. /**
  116. * Constructor
  117. *
  118. * @param array $options Associative array of options
  119. * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
  120. * @throws Zend_Cache_Exception
  121. * @return void
  122. */
  123. public function __construct(array $options = array())
  124. {
  125. while (list($name, $value) = each($options)) {
  126. $name = strtolower($name);
  127. switch ($name) {
  128. case 'regexps':
  129. $this->_setRegexps($value);
  130. break;
  131. case 'default_options':
  132. $this->_setDefaultOptions($value);
  133. break;
  134. case 'content_type_memorization':
  135. $this->_setContentTypeMemorization($value);
  136. break;
  137. default:
  138. $this->setOption($name, $value);
  139. }
  140. }
  141. if (isset($this->_specificOptions['http_conditional'])) {
  142. if ($this->_specificOptions['http_conditional']) {
  143. Zend_Cache::throwException('http_conditional is not implemented for the moment !');
  144. }
  145. }
  146. $this->setOption('automatic_serialization', true);
  147. }
  148. /**
  149. * Specific setter for the 'default_options' option (with some additional tests)
  150. *
  151. * @param array $options Associative array
  152. * @throws Zend_Cache_Exception
  153. * @return void
  154. */
  155. protected function _setDefaultOptions($options)
  156. {
  157. if (!is_array($options)) {
  158. Zend_Cache::throwException('default_options must be an array !');
  159. }
  160. foreach ($options as $key=>$value) {
  161. if (!is_string($key)) {
  162. Zend_Cache::throwException("invalid option [$key] !");
  163. }
  164. $key = strtolower($key);
  165. if (isset($this->_specificOptions['default_options'][$key])) {
  166. $this->_specificOptions['default_options'][$key] = $value;
  167. }
  168. }
  169. }
  170. /**
  171. * Set the deprecated contentTypeMemorization option
  172. *
  173. * @param boolean $value value
  174. * @return void
  175. * @deprecated
  176. */
  177. protected function _setContentTypeMemorization($value)
  178. {
  179. $found = null;
  180. foreach ($this->_specificOptions['memorize_headers'] as $key => $value) {
  181. if (strtolower($value) == 'content-type') {
  182. $found = $key;
  183. }
  184. }
  185. if ($value) {
  186. if (!$found) {
  187. $this->_specificOptions['memorize_headers'][] = 'Content-Type';
  188. }
  189. } else {
  190. if ($found) {
  191. unset($this->_specificOptions['memorize_headers'][$found]);
  192. }
  193. }
  194. }
  195. /**
  196. * Specific setter for the 'regexps' option (with some additional tests)
  197. *
  198. * @param array $options Associative array
  199. * @throws Zend_Cache_Exception
  200. * @return void
  201. */
  202. protected function _setRegexps($regexps)
  203. {
  204. if (!is_array($regexps)) {
  205. Zend_Cache::throwException('regexps option must be an array !');
  206. }
  207. foreach ($regexps as $regexp=>$conf) {
  208. if (!is_array($conf)) {
  209. Zend_Cache::throwException('regexps option must be an array of arrays !');
  210. }
  211. $validKeys = array_keys($this->_specificOptions['default_options']);
  212. foreach ($conf as $key=>$value) {
  213. if (!is_string($key)) {
  214. Zend_Cache::throwException("unknown option [$key] !");
  215. }
  216. $key = strtolower($key);
  217. if (!in_array($key, $validKeys)) {
  218. unset($regexps[$regexp][$key]);
  219. }
  220. }
  221. }
  222. $this->setOption('regexps', $regexps);
  223. }
  224. /**
  225. * Start the cache
  226. *
  227. * @param string $id (optional) A cache id (if you set a value here, maybe you have to use Output frontend instead)
  228. * @param boolean $doNotDie For unit testing only !
  229. * @return boolean True if the cache is hit (false else)
  230. */
  231. public function start($id = false, $doNotDie = false)
  232. {
  233. $this->_cancel = false;
  234. $lastMatchingRegexp = null;
  235. foreach ($this->_specificOptions['regexps'] as $regexp => $conf) {
  236. if (preg_match("`$regexp`", $_SERVER['REQUEST_URI'])) {
  237. $lastMatchingRegexp = $regexp;
  238. }
  239. }
  240. $this->_activeOptions = $this->_specificOptions['default_options'];
  241. if ($lastMatchingRegexp !== null) {
  242. $conf = $this->_specificOptions['regexps'][$lastMatchingRegexp];
  243. foreach ($conf as $key=>$value) {
  244. $this->_activeOptions[$key] = $value;
  245. }
  246. }
  247. if (!($this->_activeOptions['cache'])) {
  248. return false;
  249. }
  250. if (!$id) {
  251. $id = $this->_makeId();
  252. if (!$id) {
  253. return false;
  254. }
  255. }
  256. $array = $this->load($id);
  257. if ($array !== false) {
  258. $data = $array['data'];
  259. $headers = $array['headers'];
  260. if (!headers_sent()) {
  261. foreach ($headers as $key=>$headerCouple) {
  262. $name = $headerCouple[0];
  263. $value = $headerCouple[1];
  264. header("$name: $value");
  265. }
  266. }
  267. if ($this->_specificOptions['debug_header']) {
  268. echo 'DEBUG HEADER : This is a cached page !';
  269. }
  270. echo $data;
  271. if ($doNotDie) {
  272. return true;
  273. }
  274. die();
  275. }
  276. ob_start(array($this, '_flush'));
  277. ob_implicit_flush(false);
  278. return false;
  279. }
  280. /**
  281. * Cancel the current caching process
  282. */
  283. public function cancel()
  284. {
  285. $this->_cancel = true;
  286. }
  287. /**
  288. * callback for output buffering
  289. * (shouldn't really be called manually)
  290. *
  291. * @param string $data Buffered output
  292. * @return string Data to send to browser
  293. */
  294. public function _flush($data)
  295. {
  296. if ($this->_cancel) {
  297. return $data;
  298. }
  299. $contentType = null;
  300. $storedHeaders = array();
  301. $headersList = headers_list();
  302. foreach($this->_specificOptions['memorize_headers'] as $key=>$headerName) {
  303. foreach ($headersList as $headerSent) {
  304. $tmp = explode(':', $headerSent);
  305. $headerSentName = trim(array_shift($tmp));
  306. if (strtolower($headerName) == strtolower($headerSentName)) {
  307. $headerSentValue = trim(implode(':', $tmp));
  308. $storedHeaders[] = array($headerSentName, $headerSentValue);
  309. }
  310. }
  311. }
  312. $array = array(
  313. 'data' => $data,
  314. 'headers' => $storedHeaders
  315. );
  316. $this->save($array, null, $this->_activeOptions['tags'], $this->_activeOptions['specific_lifetime'], $this->_activeOptions['priority']);
  317. return $data;
  318. }
  319. /**
  320. * Make an id depending on REQUEST_URI and superglobal arrays (depending on options)
  321. *
  322. * @return mixed|false a cache id (string), false if the cache should have not to be used
  323. */
  324. protected function _makeId()
  325. {
  326. $tmp = $_SERVER['REQUEST_URI'];
  327. $array = explode('?', $tmp, 2);
  328. $tmp = $array[0];
  329. foreach (array('Get', 'Post', 'Session', 'Files', 'Cookie') as $arrayName) {
  330. $tmp2 = $this->_makePartialId($arrayName, $this->_activeOptions['cache_with_' . strtolower($arrayName) . '_variables'], $this->_activeOptions['make_id_with_' . strtolower($arrayName) . '_variables']);
  331. if ($tmp2===false) {
  332. return false;
  333. }
  334. $tmp = $tmp . $tmp2;
  335. }
  336. return md5($tmp);
  337. }
  338. /**
  339. * Make a partial id depending on options
  340. *
  341. * @param string $arrayName Superglobal array name
  342. * @param bool $bool1 If true, cache is still on even if there are some variables in the superglobal array
  343. * @param bool $bool2 If true, we have to use the content of the superglobal array to make a partial id
  344. * @return mixed|false Partial id (string) or false if the cache should have not to be used
  345. */
  346. protected function _makePartialId($arrayName, $bool1, $bool2)
  347. {
  348. switch ($arrayName) {
  349. case 'Get':
  350. $var = $_GET;
  351. break;
  352. case 'Post':
  353. $var = $_POST;
  354. break;
  355. case 'Session':
  356. if (isset($_SESSION)) {
  357. $var = $_SESSION;
  358. } else {
  359. $var = null;
  360. }
  361. break;
  362. case 'Cookie':
  363. if (isset($_COOKIE)) {
  364. $var = $_COOKIE;
  365. } else {
  366. $var = null;
  367. }
  368. break;
  369. case 'Files':
  370. $var = $_FILES;
  371. break;
  372. default:
  373. return false;
  374. }
  375. if ($bool1) {
  376. if ($bool2) {
  377. return serialize($var);
  378. }
  379. return '';
  380. }
  381. if (count($var) > 0) {
  382. return false;
  383. }
  384. return '';
  385. }
  386. }