PageRenderTime 58ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/luizbrandaoj/mini-blog
PHP | 404 lines | 244 code | 16 blank | 144 comment | 39 complexity | efcf79b494e8d5a75b327637b92f87c4 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-2011 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 23775 2011-03-01 17:25:24Z ralph $
  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-2011 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. if (isset($_SERVER['REQUEST_URI'])) {
  236. foreach ($this->_specificOptions['regexps'] as $regexp => $conf) {
  237. if (preg_match("`$regexp`", $_SERVER['REQUEST_URI'])) {
  238. $lastMatchingRegexp = $regexp;
  239. }
  240. }
  241. }
  242. $this->_activeOptions = $this->_specificOptions['default_options'];
  243. if ($lastMatchingRegexp !== null) {
  244. $conf = $this->_specificOptions['regexps'][$lastMatchingRegexp];
  245. foreach ($conf as $key=>$value) {
  246. $this->_activeOptions[$key] = $value;
  247. }
  248. }
  249. if (!($this->_activeOptions['cache'])) {
  250. return false;
  251. }
  252. if (!$id) {
  253. $id = $this->_makeId();
  254. if (!$id) {
  255. return false;
  256. }
  257. }
  258. $array = $this->load($id);
  259. if ($array !== false) {
  260. $data = $array['data'];
  261. $headers = $array['headers'];
  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. if ($this->_specificOptions['debug_header']) {
  270. echo 'DEBUG HEADER : This is a cached page !';
  271. }
  272. echo $data;
  273. if ($doNotDie) {
  274. return true;
  275. }
  276. die();
  277. }
  278. ob_start(array($this, '_flush'));
  279. ob_implicit_flush(false);
  280. return false;
  281. }
  282. /**
  283. * Cancel the current caching process
  284. */
  285. public function cancel()
  286. {
  287. $this->_cancel = true;
  288. }
  289. /**
  290. * callback for output buffering
  291. * (shouldn't really be called manually)
  292. *
  293. * @param string $data Buffered output
  294. * @return string Data to send to browser
  295. */
  296. public function _flush($data)
  297. {
  298. if ($this->_cancel) {
  299. return $data;
  300. }
  301. $contentType = null;
  302. $storedHeaders = array();
  303. $headersList = headers_list();
  304. foreach($this->_specificOptions['memorize_headers'] as $key=>$headerName) {
  305. foreach ($headersList as $headerSent) {
  306. $tmp = explode(':', $headerSent);
  307. $headerSentName = trim(array_shift($tmp));
  308. if (strtolower($headerName) == strtolower($headerSentName)) {
  309. $headerSentValue = trim(implode(':', $tmp));
  310. $storedHeaders[] = array($headerSentName, $headerSentValue);
  311. }
  312. }
  313. }
  314. $array = array(
  315. 'data' => $data,
  316. 'headers' => $storedHeaders
  317. );
  318. $this->save($array, null, $this->_activeOptions['tags'], $this->_activeOptions['specific_lifetime'], $this->_activeOptions['priority']);
  319. return $data;
  320. }
  321. /**
  322. * Make an id depending on REQUEST_URI and superglobal arrays (depending on options)
  323. *
  324. * @return mixed|false a cache id (string), false if the cache should have not to be used
  325. */
  326. protected function _makeId()
  327. {
  328. $tmp = $_SERVER['REQUEST_URI'];
  329. $array = explode('?', $tmp, 2);
  330. $tmp = $array[0];
  331. foreach (array('Get', 'Post', 'Session', 'Files', 'Cookie') as $arrayName) {
  332. $tmp2 = $this->_makePartialId($arrayName, $this->_activeOptions['cache_with_' . strtolower($arrayName) . '_variables'], $this->_activeOptions['make_id_with_' . strtolower($arrayName) . '_variables']);
  333. if ($tmp2===false) {
  334. return false;
  335. }
  336. $tmp = $tmp . $tmp2;
  337. }
  338. return md5($tmp);
  339. }
  340. /**
  341. * Make a partial id depending on options
  342. *
  343. * @param string $arrayName Superglobal array name
  344. * @param bool $bool1 If true, cache is still on even if there are some variables in the superglobal array
  345. * @param bool $bool2 If true, we have to use the content of the superglobal array to make a partial id
  346. * @return mixed|false Partial id (string) or false if the cache should have not to be used
  347. */
  348. protected function _makePartialId($arrayName, $bool1, $bool2)
  349. {
  350. switch ($arrayName) {
  351. case 'Get':
  352. $var = $_GET;
  353. break;
  354. case 'Post':
  355. $var = $_POST;
  356. break;
  357. case 'Session':
  358. if (isset($_SESSION)) {
  359. $var = $_SESSION;
  360. } else {
  361. $var = null;
  362. }
  363. break;
  364. case 'Cookie':
  365. if (isset($_COOKIE)) {
  366. $var = $_COOKIE;
  367. } else {
  368. $var = null;
  369. }
  370. break;
  371. case 'Files':
  372. $var = $_FILES;
  373. break;
  374. default:
  375. return false;
  376. }
  377. if ($bool1) {
  378. if ($bool2) {
  379. return serialize($var);
  380. }
  381. return '';
  382. }
  383. if (count($var) > 0) {
  384. return false;
  385. }
  386. return '';
  387. }
  388. }