Verzeichnisstruktur phpBB-3.3.16


Veröffentlicht
27.04.2026

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: 01.05.2026, 11:26 - 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