PageRenderTime 54ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/baruffaldi/cms-php-bfcms
PHP | 385 lines | 233 code | 16 blank | 136 comment | 37 complexity | 7bb8dee58ad44888f2bc6df346bc13d3 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. *
  63. * ====> (array) regexps :
  64. * - an associative array to set options only for some REQUEST_URI
  65. * - keys are (pcre) regexps
  66. * - values are associative array with specific options to set if the regexp matchs on $_SERVER['REQUEST_URI']
  67. * (see default_options for the list of available options)
  68. * - if several regexps match the $_SERVER['REQUEST_URI'], only the last one will be used
  69. *
  70. * @var array options
  71. */
  72. protected $_specificOptions = array(
  73. 'http_conditional' => false,
  74. 'debug_header' => false,
  75. 'content_type_memorization' => false,
  76. 'memorize_headers' => array(),
  77. 'default_options' => array(
  78. 'cache_with_get_variables' => false,
  79. 'cache_with_post_variables' => false,
  80. 'cache_with_session_variables' => false,
  81. 'cache_with_files_variables' => false,
  82. 'cache_with_cookie_variables' => false,
  83. 'make_id_with_get_variables' => true,
  84. 'make_id_with_post_variables' => true,
  85. 'make_id_with_session_variables' => true,
  86. 'make_id_with_files_variables' => true,
  87. 'make_id_with_cookie_variables' => true,
  88. 'cache' => true
  89. ),
  90. 'regexps' => array()
  91. );
  92. /**
  93. * Internal array to store some options
  94. *
  95. * @var array associative array of options
  96. */
  97. protected $_activeOptions = array();
  98. /**
  99. * If true, the page won't be cached
  100. *
  101. * @var boolean
  102. */
  103. private $_cancel = false;
  104. /**
  105. * Constructor
  106. *
  107. * @param array $options Associative array of options
  108. * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
  109. * @throws Zend_Cache_Exception
  110. * @return void
  111. */
  112. public function __construct(array $options = array())
  113. {
  114. while (list($name, $value) = each($options)) {
  115. $name = strtolower($name);
  116. switch ($name) {
  117. case 'regexps':
  118. $this->_setRegexps($value);
  119. break;
  120. case 'default_options':
  121. $this->_setDefaultOptions($value);
  122. break;
  123. case 'content_type_memorization':
  124. $this->_setContentTypeMemorization($value);
  125. break;
  126. default:
  127. $this->setOption($name, $value);
  128. }
  129. }
  130. if (isset($this->_specificOptions['http_conditional'])) {
  131. if ($this->_specificOptions['http_conditional']) {
  132. Zend_Cache::throwException('http_conditional is not implemented for the moment !');
  133. }
  134. }
  135. $this->setOption('automatic_serialization', true);
  136. }
  137. /**
  138. * Specific setter for the 'default_options' option (with some additional tests)
  139. *
  140. * @param array $options Associative array
  141. * @throws Zend_Cache_Exception
  142. * @return void
  143. */
  144. protected function _setDefaultOptions($options)
  145. {
  146. if (!is_array($options)) {
  147. Zend_Cache::throwException('default_options must be an array !');
  148. }
  149. foreach ($options as $key=>$value) {
  150. $key = strtolower($key);
  151. if (!isset($this->_specificOptions['default_options'][$key])) {
  152. Zend_Cache::throwException("unknown option [$key] !");
  153. } else {
  154. $this->_specificOptions['default_options'][$key] = $value;
  155. }
  156. }
  157. }
  158. /**
  159. * Set the deprecated contentTypeMemorization option
  160. *
  161. * @param boolean $value value
  162. * @return void
  163. * @deprecated
  164. */
  165. protected function _setContentTypeMemorization($value)
  166. {
  167. $found = null;
  168. foreach ($this->_specificOptions['memorize_headers'] as $key => $value) {
  169. if (strtolower($value) == 'content-type') {
  170. $found = $key;
  171. }
  172. }
  173. if ($value) {
  174. if (!$found) {
  175. $this->_specificOptions['memorize_headers'][] = 'Content-Type';
  176. }
  177. } else {
  178. if ($found) {
  179. unset($this->_specificOptions['memorize_headers'][$found]);
  180. }
  181. }
  182. }
  183. /**
  184. * Specific setter for the 'regexps' option (with some additional tests)
  185. *
  186. * @param array $options Associative array
  187. * @throws Zend_Cache_Exception
  188. * @return void
  189. */
  190. protected function _setRegexps($regexps)
  191. {
  192. if (!is_array($regexps)) {
  193. Zend_Cache::throwException('regexps option must be an array !');
  194. }
  195. foreach ($regexps as $regexp=>$conf) {
  196. if (!is_array($conf)) {
  197. Zend_Cache::throwException('regexps option must be an array of arrays !');
  198. }
  199. $validKeys = array_keys($this->_specificOptions['default_options']);
  200. foreach ($conf as $key=>$value) {
  201. $key = strtolower($key);
  202. if (!in_array($key, $validKeys)) {
  203. Zend_Cache::throwException("unknown option [$key] !");
  204. }
  205. }
  206. }
  207. $this->setOption('regexps', $regexps);
  208. }
  209. /**
  210. * Start the cache
  211. *
  212. * @param string $id (optional) A cache id (if you set a value here, maybe you have to use Output frontend instead)
  213. * @param boolean $doNotDie For unit testing only !
  214. * @return boolean True if the cache is hit (false else)
  215. */
  216. public function start($id = false, $doNotDie = false)
  217. {
  218. $this->_cancel = false;
  219. $lastMatchingRegexp = null;
  220. foreach ($this->_specificOptions['regexps'] as $regexp => $conf) {
  221. if (preg_match("`$regexp`", $_SERVER['REQUEST_URI'])) {
  222. $lastMatchingRegexp = $regexp;
  223. }
  224. }
  225. $this->_activeOptions = $this->_specificOptions['default_options'];
  226. if (!is_null($lastMatchingRegexp)) {
  227. $conf = $this->_specificOptions['regexps'][$lastMatchingRegexp];
  228. foreach ($conf as $key=>$value) {
  229. $this->_activeOptions[$key] = $value;
  230. }
  231. }
  232. if (!($this->_activeOptions['cache'])) {
  233. return false;
  234. }
  235. if (!$id) {
  236. $id = $this->_makeId();
  237. if (!$id) {
  238. return false;
  239. }
  240. }
  241. $array = $this->load($id);
  242. if ($array !== false) {
  243. $data = $array['data'];
  244. $headers = $array['headers'];
  245. if ($this->_specificOptions['debug_header']) {
  246. echo 'DEBUG HEADER : This is a cached page !';
  247. }
  248. if (!headers_sent()) {
  249. foreach ($headers as $key=>$headerCouple) {
  250. $name = $headerCouple[0];
  251. $value = $headerCouple[1];
  252. header("$name: $value");
  253. }
  254. }
  255. echo $data;
  256. if ($doNotDie) {
  257. return true;
  258. }
  259. die();
  260. }
  261. ob_start(array($this, '_flush'));
  262. ob_implicit_flush(false);
  263. return false;
  264. }
  265. /**
  266. * Cancel the current caching process
  267. */
  268. public function cancel()
  269. {
  270. $this->_cancel = true;
  271. }
  272. /**
  273. * callback for output buffering
  274. * (shouldn't really be called manually)
  275. *
  276. * @param string $data Buffered output
  277. * @return string Data to send to browser
  278. */
  279. public function _flush($data)
  280. {
  281. if ($this->_cancel) {
  282. return $data;
  283. }
  284. $contentType = null;
  285. $storedHeaders = array();
  286. $headersList = headers_list();
  287. foreach($this->_specificOptions['memorize_headers'] as $key=>$headerName) {
  288. foreach ($headersList as $headerSent) {
  289. $tmp = split(':', $headerSent);
  290. $headerSentName = trim(array_shift($tmp));
  291. if (strtolower($headerName) == strtolower($headerSentName)) {
  292. $headerSentValue = trim(implode(':', $tmp));
  293. $storedHeaders[] = array($headerSentName, $headerSentValue);
  294. }
  295. }
  296. }
  297. $array = array(
  298. 'data' => $data,
  299. 'headers' => $storedHeaders
  300. );
  301. $this->save($array);
  302. return $data;
  303. }
  304. /**
  305. * Make an id depending on REQUEST_URI and superglobal arrays (depending on options)
  306. *
  307. * @return mixed|false a cache id (string), false if the cache should have not to be used
  308. */
  309. private function _makeId()
  310. {
  311. $tmp = $_SERVER['REQUEST_URI'];
  312. foreach (array('Get', 'Post', 'Session', 'Files', 'Cookie') as $arrayName) {
  313. $tmp2 = $this->_makePartialId($arrayName, $this->_activeOptions['cache_with_' . strtolower($arrayName) . '_variables'], $this->_activeOptions['make_id_with_' . strtolower($arrayName) . '_variables']);
  314. if ($tmp2===false) {
  315. return false;
  316. }
  317. $tmp = $tmp . $tmp2;
  318. }
  319. return md5($tmp);
  320. }
  321. /**
  322. * Make a partial id depending on options
  323. *
  324. * @param string $arrayName Superglobal array name
  325. * @param bool $bool1 If true, cache is still on even if there are some variables in the superglobal array
  326. * @param bool $bool2 If true, we have to use the content of the superglobal array to make a partial id
  327. * @return mixed|false Partial id (string) or false if the cache should have not to be used
  328. */
  329. private function _makePartialId($arrayName, $bool1, $bool2)
  330. {
  331. switch ($arrayName) {
  332. case 'Get':
  333. $var = $_GET;
  334. break;
  335. case 'Post':
  336. $var = $_POST;
  337. break;
  338. case 'Session':
  339. if (isset($_SESSION)) {
  340. $var = $_SESSION;
  341. } else {
  342. $var = null;
  343. }
  344. break;
  345. case 'Cookie':
  346. if (isset($_COOKIE)) {
  347. $var = $_COOKIE;
  348. } else {
  349. $var = null;
  350. }
  351. break;
  352. case 'Files':
  353. $var = $_FILES;
  354. break;
  355. default:
  356. return false;
  357. }
  358. if ($bool1) {
  359. if ($bool2) {
  360. return serialize($var);
  361. }
  362. return '';
  363. }
  364. if (count($var) > 0) {
  365. return false;
  366. }
  367. return '';
  368. }
  369. }