Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

ResponseCacheStrategy.php

Zuletzt modifiziert: 02.04.2025, 15:03 - Dateigröße: 7.57 KiB


001  <?php
002   
003  /*
004   * This file is part of the Symfony package.
005   *
006   * (c) Fabien Potencier <fabien@symfony.com>
007   *
008   * For the full copyright and license information, please view the LICENSE
009   * file that was distributed with this source code.
010   */
011   
012  namespace Symfony\Component\HttpKernel\HttpCache;
013   
014  use Symfony\Component\HttpFoundation\Response;
015   
016  /**
017   * ResponseCacheStrategy knows how to compute the Response cache HTTP header
018   * based on the different response cache headers.
019   *
020   * This implementation changes the master response TTL to the smallest TTL received
021   * or force validation if one of the surrogates has validation cache strategy.
022   *
023   * @author Fabien Potencier <fabien@symfony.com>
024   */
025  class ResponseCacheStrategy implements ResponseCacheStrategyInterface
026  {
027      /**
028       * Cache-Control headers that are sent to the final response if they appear in ANY of the responses.
029       */
030      private static $overrideDirectives = ['private', 'no-cache', 'no-store', 'no-transform', 'must-revalidate', 'proxy-revalidate'];
031   
032      /**
033       * Cache-Control headers that are sent to the final response if they appear in ALL of the responses.
034       */
035      private static $inheritDirectives = ['public', 'immutable'];
036   
037      private $embeddedResponses = 0;
038      private $isNotCacheableResponseEmbedded = false;
039      private $age = 0;
040      private $flagDirectives = [
041          'no-cache' => null,
042          'no-store' => null,
043          'no-transform' => null,
044          'must-revalidate' => null,
045          'proxy-revalidate' => null,
046          'public' => null,
047          'private' => null,
048          'immutable' => null,
049      ];
050      private $ageDirectives = [
051          'max-age' => null,
052          's-maxage' => null,
053          'expires' => null,
054      ];
055   
056      /**
057       * {@inheritdoc}
058       */
059      public function add(Response $response)
060      {
061          ++$this->embeddedResponses;
062   
063          foreach (self::$overrideDirectives as $directive) {
064              if ($response->headers->hasCacheControlDirective($directive)) {
065                  $this->flagDirectives[$directive] = true;
066              }
067          }
068   
069          foreach (self::$inheritDirectives as $directive) {
070              if (false !== $this->flagDirectives[$directive]) {
071                  $this->flagDirectives[$directive] = $response->headers->hasCacheControlDirective($directive);
072              }
073          }
074   
075          $age = $response->getAge();
076          $this->age = max($this->age, $age);
077   
078          if ($this->willMakeFinalResponseUncacheable($response)) {
079              $this->isNotCacheableResponseEmbedded = true;
080   
081              return;
082          }
083   
084          $this->storeRelativeAgeDirective('max-age', $response->headers->getCacheControlDirective('max-age'), $age);
085          $this->storeRelativeAgeDirective('s-maxage', $response->headers->getCacheControlDirective('s-maxage') ?: $response->headers->getCacheControlDirective('max-age'), $age);
086   
087          $expires = $response->getExpires();
088          $expires = null !== $expires ? (int) $expires->format('U') - (int) $response->getDate()->format('U') : null;
089          $this->storeRelativeAgeDirective('expires', $expires >= 0 ? $expires : null, 0);
090      }
091   
092      /**
093       * {@inheritdoc}
094       */
095      public function update(Response $response)
096      {
097          // if we have no embedded Response, do nothing
098          if (0 === $this->embeddedResponses) {
099              return;
100          }
101   
102          // Remove validation related headers of the master response,
103          // because some of the response content comes from at least
104          // one embedded response (which likely has a different caching strategy).
105          $response->setEtag(null);
106          $response->setLastModified(null);
107   
108          $this->add($response);
109   
110          $response->headers->set('Age', $this->age);
111   
112          if ($this->isNotCacheableResponseEmbedded) {
113              if ($this->flagDirectives['no-store']) {
114                  $response->headers->set('Cache-Control', 'no-cache, no-store, must-revalidate');
115              } else {
116                  $response->headers->set('Cache-Control', 'no-cache, must-revalidate');
117              }
118   
119              return;
120          }
121   
122          $flags = array_filter($this->flagDirectives);
123   
124          if (isset($flags['must-revalidate'])) {
125              $flags['no-cache'] = true;
126          }
127   
128          $response->headers->set('Cache-Control', implode(', ', array_keys($flags)));
129   
130          $maxAge = null;
131   
132          if (is_numeric($this->ageDirectives['max-age'])) {
133              $maxAge = $this->ageDirectives['max-age'] + $this->age;
134              $response->headers->addCacheControlDirective('max-age', $maxAge);
135          }
136   
137          if (is_numeric($this->ageDirectives['s-maxage'])) {
138              $sMaxage = $this->ageDirectives['s-maxage'] + $this->age;
139   
140              if ($maxAge !== $sMaxage) {
141                  $response->headers->addCacheControlDirective('s-maxage', $sMaxage);
142              }
143          }
144   
145          if (is_numeric($this->ageDirectives['expires'])) {
146              $date = clone $response->getDate();
147              $date->modify('+'.($this->ageDirectives['expires'] + $this->age).' seconds');
148              $response->setExpires($date);
149          }
150      }
151   
152      /**
153       * RFC2616, Section 13.4.
154       *
155       * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4
156       *
157       * @return bool
158       */
159      private function willMakeFinalResponseUncacheable(Response $response)
160      {
161          // RFC2616: A response received with a status code of 200, 203, 300, 301 or 410
162          // MAY be stored by a cache […] unless a cache-control directive prohibits caching.
163          if ($response->headers->hasCacheControlDirective('no-cache')
164              || $response->headers->getCacheControlDirective('no-store')
165          ) {
166              return true;
167          }
168   
169          // Last-Modified and Etag headers cannot be merged, they render the response uncacheable
170          // by default (except if the response also has max-age etc.).
171          if (\in_array($response->getStatusCode(), [200, 203, 300, 301, 410])
172              && null === $response->getLastModified()
173              && null === $response->getEtag()
174          ) {
175              return false;
176          }
177   
178          // RFC2616: A response received with any other status code (e.g. status codes 302 and 307)
179          // MUST NOT be returned in a reply to a subsequent request unless there are
180          // cache-control directives or another header(s) that explicitly allow it.
181          $cacheControl = ['max-age', 's-maxage', 'must-revalidate', 'proxy-revalidate', 'public', 'private'];
182          foreach ($cacheControl as $key) {
183              if ($response->headers->hasCacheControlDirective($key)) {
184                  return false;
185              }
186          }
187   
188          if ($response->headers->has('Expires')) {
189              return false;
190          }
191   
192          return true;
193      }
194   
195      /**
196       * Store lowest max-age/s-maxage/expires for the final response.
197       *
198       * The response might have been stored in cache a while ago. To keep things comparable,
199       * we have to subtract the age so that the value is normalized for an age of 0.
200       *
201       * If the value is lower than the currently stored value, we update the value, to keep a rolling
202       * minimal value of each instruction. If the value is NULL, the directive will not be set on the final response.
203       *
204       * @param string   $directive
205       * @param int|null $value
206       * @param int      $age
207       */
208      private function storeRelativeAgeDirective($directive, $value, $age)
209      {
210          if (null === $value) {
211              $this->ageDirectives[$directive] = false;
212          }
213   
214          if (false !== $this->ageDirectives[$directive]) {
215              $value -= $age;
216              $this->ageDirectives[$directive] = null !== $this->ageDirectives[$directive] ? min($this->ageDirectives[$directive], $value) : $value;
217          }
218      }
219  }
220