PageRenderTime 86ms CodeModel.GetById 41ms RepoModel.GetById 8ms app.codeStats 0ms

/library/Zend/Cache/Frontend/Page.php

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