PageRenderTime 72ms CodeModel.GetById 35ms app.highlight 31ms RepoModel.GetById 1ms app.codeStats 0ms

/framework/vendor/zend/Zend/Cache/Frontend/Page.php

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