Development

/branches/1.2/lib/filter/sfCacheFilter.class.php

You must first sign up to be able to contribute.

root/branches/1.2/lib/filter/sfCacheFilter.class.php

Revision 24619, 5.7 kB (checked in by FabianLange, 5 years ago)

[1.0, 1.2, 1.3, 1.4] fixed incorrect array access of lastModified header which only was an array pre 1.0. This was effectively preventing 304 Not Modified response from working correctly. Fixed phpdoc referring to array as return type of getHttpHeader() (fixes #6633, #7539)

  • Property svn:mime-type set to text/x-php
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1 <?php
2
3 /*
4  * This file is part of the symfony package.
5  * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
6  *
7  * For the full copyright and license information, please view the LICENSE
8  * file that was distributed with this source code.
9  */
10
11 /**
12  * sfCacheFilter deals with page caching and action caching.
13  *
14  * @package    symfony
15  * @subpackage filter
16  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
17  * @version    SVN: $Id$
18  */
19 class sfCacheFilter extends sfFilter
20 {
21   protected
22     $cacheManager = null,
23     $request      = null,
24     $response     = null,
25     $routing      = null,
26     $cache        = array();
27
28   /**
29    * Initializes this Filter.
30    *
31    * @param sfContext $context    The current application context
32    * @param array     $parameters An associative array of initialization parameters
33    *
34    * @return bool true, if initialization completes successfully, otherwise false
35    *
36    * @throws <b>sfInitializationException</b> If an error occurs while initializing this Filter
37    */
38   public function initialize($context, $parameters = array())
39   {
40     parent::initialize($context, $parameters);
41
42     $this->cacheManager = $context->getViewCacheManager();
43     $this->request      = $context->getRequest();
44     $this->response     = $context->getResponse();
45     $this->routing      = $context->getRouting();
46   }
47
48   /**
49    * Executes this filter.
50    *
51    * @param sfFilterChain $filterChain A sfFilterChain instance
52    */
53   public function execute($filterChain)
54   {
55     // execute this filter only once, if cache is set and no GET or POST parameters
56     if (!sfConfig::get('sf_cache'))
57     {
58       $filterChain->execute();
59
60       return;
61     }
62
63     if ($this->executeBeforeExecution())
64     {
65       $filterChain->execute();
66     }
67
68     $this->executeBeforeRendering();
69   }
70
71   public function executeBeforeExecution()
72   {
73     $uri = $this->routing->getCurrentInternalUri();
74
75     if (is_null($uri))
76     {
77       return true;
78     }
79
80     // page cache
81     $cacheable = $this->cacheManager->isCacheable($uri);
82     if ($cacheable && $this->cacheManager->withLayout($uri))
83     {
84       $inCache = $this->cacheManager->getPageCache($uri);
85       $this->cache[$uri] = $inCache;
86
87       if ($inCache)
88       {
89         // page is in cache, so no need to run execution filter
90         return false;
91       }
92     }
93
94     return true;
95   }
96
97   /**
98    * Executes this filter.
99    */
100   public function executeBeforeRendering()
101   {
102     // cache only 200 HTTP status
103     if (200 != $this->response->getStatusCode())
104     {
105       return;
106     }
107
108     $uri = $this->routing->getCurrentInternalUri();
109
110     // save page in cache
111     if (isset($this->cache[$uri]) && false === $this->cache[$uri])
112     {
113       $this->setCacheExpiration($uri);
114       $this->setCacheValidation($uri);
115
116       // set Vary headers
117       foreach ($this->cacheManager->getVary($uri, 'page') as $vary)
118       {
119         $this->response->addVaryHttpHeader($vary);
120       }
121
122       $this->cacheManager->setPageCache($uri);
123     }
124
125     // cache validation
126     $this->checkCacheValidation();
127   }
128
129   /**
130    * Sets cache expiration headers.
131    *
132    * @param string $uri An internal URI
133    */
134   protected function setCacheExpiration($uri)
135   {
136     // don't add cache expiration (Expires) if
137     //   * the client lifetime is not set
138     //   * the response already has a cache validation (Last-Modified header)
139     //   * the Expires header has already been set
140     if (!$lifetime = $this->cacheManager->getClientLifeTime($uri, 'page'))
141     {
142       return;
143     }
144
145     if ($this->response->hasHttpHeader('Last-Modified'))
146     {
147       return;
148     }
149
150     if (!$this->response->hasHttpHeader('Expires'))
151     {
152       $this->response->setHttpHeader('Expires', $this->response->getDate(time() + $lifetime), false);
153       $this->response->addCacheControlHttpHeader('max-age', $lifetime);
154     }
155   }
156
157   /**
158    * Sets cache validation headers.
159    *
160    * @param string $uri An internal URI
161    */
162
163   protected function setCacheValidation($uri)
164   {
165     // don't add cache validation (Last-Modified) if
166     //   * the client lifetime is set (cache.yml)
167     //   * the response already has a Last-Modified header
168     if ($this->cacheManager->getClientLifeTime($uri, 'page'))
169     {
170       return;
171     }
172
173     if (!$this->response->hasHttpHeader('Last-Modified'))
174     {
175       $this->response->setHttpHeader('Last-Modified', $this->response->getDate(time()), false);
176     }
177
178     if (sfConfig::get('sf_etag'))
179     {
180       $etag = '"'.md5($this->response->getContent()).'"';
181       $this->response->setHttpHeader('ETag', $etag);
182     }
183   }
184
185   /**
186    * Checks cache validation headers.
187    */
188   protected function checkCacheValidation()
189   {
190     // Etag support
191     if (sfConfig::get('sf_etag'))
192     {
193       $etag = '"'.md5($this->response->getContent()).'"';
194
195       if ($this->request->getHttpHeader('IF_NONE_MATCH') == $etag)
196       {
197         $this->response->setStatusCode(304);
198         $this->response->setHeaderOnly(true);
199
200         if (sfConfig::get('sf_logging_enabled'))
201         {
202           $this->context->getEventDispatcher()->notify(new sfEvent($this, 'application.log', array('ETag matches If-None-Match (send 304)')));
203         }
204       }
205     }
206
207     // conditional GET support
208     // never in debug mode
209     if ($this->response->hasHttpHeader('Last-Modified') && !sfConfig::get('sf_debug'))
210     {
211       $lastModified = $this->response->getHttpHeader('Last-Modified');
212       if ($this->request->getHttpHeader('IF_MODIFIED_SINCE') == $lastModified)
213       {
214         $this->response->setStatusCode(304);
215         $this->response->setHeaderOnly(true);
216
217         if (sfConfig::get('sf_logging_enabled'))
218         {
219           $this->context->getEventDispatcher()->notify(new sfEvent($this, 'application.log', array('Last-Modified matches If-Modified-Since (send 304)')));
220         }
221       }
222     }
223   }
224 }
225
Note: See TracBrowser for help on using the browser.