File indexing completed on 2025-01-19 05:20:57
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Cache 0017 * @subpackage Zend_Cache_Frontend 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 0024 /** 0025 * @see Zend_Cache_Core 0026 */ 0027 // require_once 'Zend/Cache/Core.php'; 0028 0029 0030 /** 0031 * @package Zend_Cache 0032 * @subpackage Zend_Cache_Frontend 0033 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0034 * @license http://framework.zend.com/license/new-bsd New BSD License 0035 */ 0036 class Zend_Cache_Frontend_Page extends Zend_Cache_Core 0037 { 0038 /** 0039 * This frontend specific options 0040 * 0041 * ====> (boolean) http_conditional : 0042 * - if true, http conditional mode is on 0043 * WARNING : http_conditional OPTION IS NOT IMPLEMENTED FOR THE MOMENT (TODO) 0044 * 0045 * ====> (boolean) debug_header : 0046 * - if true, a debug text is added before each cached pages 0047 * 0048 * ====> (boolean) content_type_memorization : 0049 * - deprecated => use memorize_headers instead 0050 * - if the Content-Type header is sent after the cache was started, the 0051 * corresponding value can be memorized and replayed when the cache is hit 0052 * (if false (default), the frontend doesn't take care of Content-Type header) 0053 * 0054 * ====> (array) memorize_headers : 0055 * - an array of strings corresponding to some HTTP headers name. Listed headers 0056 * will be stored with cache datas and "replayed" when the cache is hit 0057 * 0058 * ====> (array) default_options : 0059 * - an associative array of default options : 0060 * - (boolean) cache : cache is on by default if true 0061 * - (boolean) cacheWithXXXVariables (XXXX = 'Get', 'Post', 'Session', 'Files' or 'Cookie') : 0062 * if true, cache is still on even if there are some variables in this superglobal array 0063 * if false, cache is off if there are some variables in this superglobal array 0064 * - (boolean) makeIdWithXXXVariables (XXXX = 'Get', 'Post', 'Session', 'Files' or 'Cookie') : 0065 * if true, we have to use the content of this superglobal array to make a cache id 0066 * if false, the cache id won't be dependent of the content of this superglobal array 0067 * - (int) specific_lifetime : cache specific lifetime 0068 * (false => global lifetime is used, null => infinite lifetime, 0069 * integer => this lifetime is used), this "lifetime" is probably only 0070 * usefull when used with "regexps" array 0071 * - (array) tags : array of tags (strings) 0072 * - (int) priority : integer between 0 (very low priority) and 10 (maximum priority) used by 0073 * some particular backends 0074 * 0075 * ====> (array) regexps : 0076 * - an associative array to set options only for some REQUEST_URI 0077 * - keys are (pcre) regexps 0078 * - values are associative array with specific options to set if the regexp matchs on $_SERVER['REQUEST_URI'] 0079 * (see default_options for the list of available options) 0080 * - if several regexps match the $_SERVER['REQUEST_URI'], only the last one will be used 0081 * 0082 * @var array options 0083 */ 0084 protected $_specificOptions = array( 0085 'http_conditional' => false, 0086 'debug_header' => false, 0087 'content_type_memorization' => false, 0088 'memorize_headers' => array(), 0089 'default_options' => array( 0090 'cache_with_get_variables' => false, 0091 'cache_with_post_variables' => false, 0092 'cache_with_session_variables' => false, 0093 'cache_with_files_variables' => false, 0094 'cache_with_cookie_variables' => false, 0095 'make_id_with_get_variables' => true, 0096 'make_id_with_post_variables' => true, 0097 'make_id_with_session_variables' => true, 0098 'make_id_with_files_variables' => true, 0099 'make_id_with_cookie_variables' => true, 0100 'cache' => true, 0101 'specific_lifetime' => false, 0102 'tags' => array(), 0103 'priority' => null 0104 ), 0105 'regexps' => array() 0106 ); 0107 0108 /** 0109 * Internal array to store some options 0110 * 0111 * @var array associative array of options 0112 */ 0113 protected $_activeOptions = array(); 0114 0115 /** 0116 * If true, the page won't be cached 0117 * 0118 * @var boolean 0119 */ 0120 protected $_cancel = false; 0121 0122 /** 0123 * Constructor 0124 * 0125 * @param array $options Associative array of options 0126 * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested 0127 * @throws Zend_Cache_Exception 0128 * @return void 0129 */ 0130 public function __construct(array $options = array()) 0131 { 0132 foreach ($options as $name => $value) { 0133 $name = strtolower($name); 0134 switch ($name) { 0135 case 'regexps': 0136 $this->_setRegexps($value); 0137 break; 0138 case 'default_options': 0139 $this->_setDefaultOptions($value); 0140 break; 0141 case 'content_type_memorization': 0142 $this->_setContentTypeMemorization($value); 0143 break; 0144 default: 0145 $this->setOption($name, $value); 0146 } 0147 } 0148 if (isset($this->_specificOptions['http_conditional'])) { 0149 if ($this->_specificOptions['http_conditional']) { 0150 Zend_Cache::throwException('http_conditional is not implemented for the moment !'); 0151 } 0152 } 0153 $this->setOption('automatic_serialization', true); 0154 } 0155 0156 /** 0157 * Specific setter for the 'default_options' option (with some additional tests) 0158 * 0159 * @param array $options Associative array 0160 * @throws Zend_Cache_Exception 0161 * @return void 0162 */ 0163 protected function _setDefaultOptions($options) 0164 { 0165 if (!is_array($options)) { 0166 Zend_Cache::throwException('default_options must be an array !'); 0167 } 0168 foreach ($options as $key=>$value) { 0169 if (!is_string($key)) { 0170 Zend_Cache::throwException("invalid option [$key] !"); 0171 } 0172 $key = strtolower($key); 0173 if (isset($this->_specificOptions['default_options'][$key])) { 0174 $this->_specificOptions['default_options'][$key] = $value; 0175 } 0176 } 0177 } 0178 0179 /** 0180 * Set the deprecated contentTypeMemorization option 0181 * 0182 * @param boolean $value value 0183 * @return void 0184 * @deprecated 0185 */ 0186 protected function _setContentTypeMemorization($value) 0187 { 0188 $found = null; 0189 foreach ($this->_specificOptions['memorize_headers'] as $key => $value) { 0190 if (strtolower($value) == 'content-type') { 0191 $found = $key; 0192 } 0193 } 0194 if ($value) { 0195 if (!$found) { 0196 $this->_specificOptions['memorize_headers'][] = 'Content-Type'; 0197 } 0198 } else { 0199 if ($found) { 0200 unset($this->_specificOptions['memorize_headers'][$found]); 0201 } 0202 } 0203 } 0204 0205 /** 0206 * Specific setter for the 'regexps' option (with some additional tests) 0207 * 0208 * @param array $options Associative array 0209 * @throws Zend_Cache_Exception 0210 * @return void 0211 */ 0212 protected function _setRegexps($regexps) 0213 { 0214 if (!is_array($regexps)) { 0215 Zend_Cache::throwException('regexps option must be an array !'); 0216 } 0217 foreach ($regexps as $regexp=>$conf) { 0218 if (!is_array($conf)) { 0219 Zend_Cache::throwException('regexps option must be an array of arrays !'); 0220 } 0221 $validKeys = array_keys($this->_specificOptions['default_options']); 0222 foreach ($conf as $key=>$value) { 0223 if (!is_string($key)) { 0224 Zend_Cache::throwException("unknown option [$key] !"); 0225 } 0226 $key = strtolower($key); 0227 if (!in_array($key, $validKeys)) { 0228 unset($regexps[$regexp][$key]); 0229 } 0230 } 0231 } 0232 $this->setOption('regexps', $regexps); 0233 } 0234 0235 /** 0236 * Start the cache 0237 * 0238 * @param string $id (optional) A cache id (if you set a value here, maybe you have to use Output frontend instead) 0239 * @param boolean $doNotDie For unit testing only ! 0240 * @return boolean True if the cache is hit (false else) 0241 */ 0242 public function start($id = false, $doNotDie = false) 0243 { 0244 $this->_cancel = false; 0245 $lastMatchingRegexp = null; 0246 if (isset($_SERVER['REQUEST_URI'])) { 0247 foreach ($this->_specificOptions['regexps'] as $regexp => $conf) { 0248 if (preg_match("`$regexp`", $_SERVER['REQUEST_URI'])) { 0249 $lastMatchingRegexp = $regexp; 0250 } 0251 } 0252 } 0253 $this->_activeOptions = $this->_specificOptions['default_options']; 0254 if ($lastMatchingRegexp !== null) { 0255 $conf = $this->_specificOptions['regexps'][$lastMatchingRegexp]; 0256 foreach ($conf as $key=>$value) { 0257 $this->_activeOptions[$key] = $value; 0258 } 0259 } 0260 if (!($this->_activeOptions['cache'])) { 0261 return false; 0262 } 0263 if (!$id) { 0264 $id = $this->_makeId(); 0265 if (!$id) { 0266 return false; 0267 } 0268 } 0269 $array = $this->load($id); 0270 if ($array !== false) { 0271 $data = $array['data']; 0272 $headers = $array['headers']; 0273 if (!headers_sent()) { 0274 foreach ($headers as $key=>$headerCouple) { 0275 $name = $headerCouple[0]; 0276 $value = $headerCouple[1]; 0277 header("$name: $value"); 0278 } 0279 } 0280 if ($this->_specificOptions['debug_header']) { 0281 echo 'DEBUG HEADER : This is a cached page !'; 0282 } 0283 echo $data; 0284 if ($doNotDie) { 0285 return true; 0286 } 0287 die(); 0288 } 0289 ob_start(array($this, '_flush')); 0290 ob_implicit_flush(false); 0291 return false; 0292 } 0293 0294 /** 0295 * Cancel the current caching process 0296 */ 0297 public function cancel() 0298 { 0299 $this->_cancel = true; 0300 } 0301 0302 /** 0303 * callback for output buffering 0304 * (shouldn't really be called manually) 0305 * 0306 * @param string $data Buffered output 0307 * @return string Data to send to browser 0308 */ 0309 public function _flush($data) 0310 { 0311 if ($this->_cancel) { 0312 return $data; 0313 } 0314 $contentType = null; 0315 $storedHeaders = array(); 0316 $headersList = headers_list(); 0317 foreach($this->_specificOptions['memorize_headers'] as $key=>$headerName) { 0318 foreach ($headersList as $headerSent) { 0319 $tmp = explode(':', $headerSent); 0320 $headerSentName = trim(array_shift($tmp)); 0321 if (strtolower($headerName) == strtolower($headerSentName)) { 0322 $headerSentValue = trim(implode(':', $tmp)); 0323 $storedHeaders[] = array($headerSentName, $headerSentValue); 0324 } 0325 } 0326 } 0327 $array = array( 0328 'data' => $data, 0329 'headers' => $storedHeaders 0330 ); 0331 $this->save($array, null, $this->_activeOptions['tags'], $this->_activeOptions['specific_lifetime'], $this->_activeOptions['priority']); 0332 return $data; 0333 } 0334 0335 /** 0336 * Make an id depending on REQUEST_URI and superglobal arrays (depending on options) 0337 * 0338 * @return mixed|false a cache id (string), false if the cache should have not to be used 0339 */ 0340 protected function _makeId() 0341 { 0342 $tmp = $_SERVER['REQUEST_URI']; 0343 $array = explode('?', $tmp, 2); 0344 $tmp = $array[0]; 0345 foreach (array('Get', 'Post', 'Session', 'Files', 'Cookie') as $arrayName) { 0346 $tmp2 = $this->_makePartialId($arrayName, $this->_activeOptions['cache_with_' . strtolower($arrayName) . '_variables'], $this->_activeOptions['make_id_with_' . strtolower($arrayName) . '_variables']); 0347 if ($tmp2===false) { 0348 return false; 0349 } 0350 $tmp = $tmp . $tmp2; 0351 } 0352 return md5($tmp); 0353 } 0354 0355 /** 0356 * Make a partial id depending on options 0357 * 0358 * @param string $arrayName Superglobal array name 0359 * @param bool $bool1 If true, cache is still on even if there are some variables in the superglobal array 0360 * @param bool $bool2 If true, we have to use the content of the superglobal array to make a partial id 0361 * @return mixed|false Partial id (string) or false if the cache should have not to be used 0362 */ 0363 protected function _makePartialId($arrayName, $bool1, $bool2) 0364 { 0365 switch ($arrayName) { 0366 case 'Get': 0367 $var = $_GET; 0368 break; 0369 case 'Post': 0370 $var = $_POST; 0371 break; 0372 case 'Session': 0373 if (isset($_SESSION)) { 0374 $var = $_SESSION; 0375 } else { 0376 $var = null; 0377 } 0378 break; 0379 case 'Cookie': 0380 if (isset($_COOKIE)) { 0381 $var = $_COOKIE; 0382 } else { 0383 $var = null; 0384 } 0385 break; 0386 case 'Files': 0387 $var = $_FILES; 0388 break; 0389 default: 0390 return false; 0391 } 0392 if ($bool1) { 0393 if ($bool2) { 0394 return serialize($var); 0395 } 0396 return ''; 0397 } 0398 if (count($var) > 0) { 0399 return false; 0400 } 0401 return ''; 0402 } 0403 0404 }