Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

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

Store.php

Zuletzt modifiziert: 09.10.2024, 12:58 - Dateigröße: 11.75 KiB


 001  <?php
 002   
 003  /*
 004   * This file is part of the Symfony package.
 005   *
 006   * (c) Fabien Potencier <fabien@symfony.com>
 007   *
 008   * This code is partially based on the Rack-Cache library by Ryan Tomayko,
 009   * which is released under the MIT license.
 010   *
 011   * For the full copyright and license information, please view the LICENSE
 012   * file that was distributed with this source code.
 013   */
 014   
 015  namespace Symfony\Component\HttpKernel\HttpCache;
 016   
 017  use Symfony\Component\HttpFoundation\Request;
 018  use Symfony\Component\HttpFoundation\Response;
 019   
 020  /**
 021   * Store implements all the logic for storing cache metadata (Request and Response headers).
 022   *
 023   * @author Fabien Potencier <fabien@symfony.com>
 024   */
 025  class Store implements StoreInterface
 026  {
 027      protected $root;
 028      private $keyCache;
 029      private $locks;
 030   
 031      /**
 032       * Constructor.
 033       *
 034       * @param string $root The path to the cache directory
 035       */
 036      public function __construct($root)
 037      {
 038          $this->root = $root;
 039          if (!is_dir($this->root)) {
 040              mkdir($this->root, 0777, true);
 041          }
 042          $this->keyCache = new \SplObjectStorage();
 043          $this->locks = array();
 044      }
 045   
 046      /**
 047       * Cleanups storage.
 048       */
 049      public function cleanup()
 050      {
 051          // unlock everything
 052          foreach ($this->locks as $lock) {
 053              if (file_exists($lock)) {
 054                  @unlink($lock);
 055              }
 056          }
 057   
 058          $error = error_get_last();
 059          if (1 === $error['type'] && false === headers_sent()) {
 060              // send a 503
 061              header('HTTP/1.0 503 Service Unavailable');
 062              header('Retry-After: 10');
 063              echo '503 Service Unavailable';
 064          }
 065      }
 066   
 067      /**
 068       * Locks the cache for a given Request.
 069       *
 070       * @param Request $request A Request instance
 071       *
 072       * @return bool|string    true if the lock is acquired, the path to the current lock otherwise
 073       */
 074      public function lock(Request $request)
 075      {
 076          $path = $this->getPath($this->getCacheKey($request).'.lck');
 077          if (!is_dir(dirname($path)) && false === @mkdir(dirname($path), 0777, true)) {
 078              return false;
 079          }
 080   
 081          $lock = @fopen($path, 'x');
 082          if (false !== $lock) {
 083              fclose($lock);
 084   
 085              $this->locks[] = $path;
 086   
 087              return true;
 088          }
 089   
 090          return !file_exists($path) ?: $path;
 091      }
 092   
 093      /**
 094       * Releases the lock for the given Request.
 095       *
 096       * @param Request $request A Request instance
 097       *
 098       * @return bool    False if the lock file does not exist or cannot be unlocked, true otherwise
 099       */
 100      public function unlock(Request $request)
 101      {
 102          $file = $this->getPath($this->getCacheKey($request).'.lck');
 103   
 104          return is_file($file) ? @unlink($file) : false;
 105      }
 106   
 107      public function isLocked(Request $request)
 108      {
 109          return is_file($this->getPath($this->getCacheKey($request).'.lck'));
 110      }
 111   
 112      /**
 113       * Locates a cached Response for the Request provided.
 114       *
 115       * @param Request $request A Request instance
 116       *
 117       * @return Response|null A Response instance, or null if no cache entry was found
 118       */
 119      public function lookup(Request $request)
 120      {
 121          $key = $this->getCacheKey($request);
 122   
 123          if (!$entries = $this->getMetadata($key)) {
 124              return;
 125          }
 126   
 127          // find a cached entry that matches the request.
 128          $match = null;
 129          foreach ($entries as $entry) {
 130              if ($this->requestsMatch(isset($entry[1]['vary'][0]) ? $entry[1]['vary'][0] : '', $request->headers->all(), $entry[0])) {
 131                  $match = $entry;
 132   
 133                  break;
 134              }
 135          }
 136   
 137          if (null === $match) {
 138              return;
 139          }
 140   
 141          list($req, $headers) = $match;
 142          if (is_file($body = $this->getPath($headers['x-content-digest'][0]))) {
 143              return $this->restoreResponse($headers, $body);
 144          }
 145   
 146          // TODO the metaStore referenced an entity that doesn't exist in
 147          // the entityStore. We definitely want to return nil but we should
 148          // also purge the entry from the meta-store when this is detected.
 149      }
 150   
 151      /**
 152       * Writes a cache entry to the store for the given Request and Response.
 153       *
 154       * Existing entries are read and any that match the response are removed. This
 155       * method calls write with the new list of cache entries.
 156       *
 157       * @param Request  $request  A Request instance
 158       * @param Response $response A Response instance
 159       *
 160       * @return string The key under which the response is stored
 161       *
 162       * @throws \RuntimeException
 163       */
 164      public function write(Request $request, Response $response)
 165      {
 166          $key = $this->getCacheKey($request);
 167          $storedEnv = $this->persistRequest($request);
 168   
 169          // write the response body to the entity store if this is the original response
 170          if (!$response->headers->has('X-Content-Digest')) {
 171              $digest = $this->generateContentDigest($response);
 172   
 173              if (false === $this->save($digest, $response->getContent())) {
 174                  throw new \RuntimeException('Unable to store the entity.');
 175              }
 176   
 177              $response->headers->set('X-Content-Digest', $digest);
 178   
 179              if (!$response->headers->has('Transfer-Encoding')) {
 180                  $response->headers->set('Content-Length', strlen($response->getContent()));
 181              }
 182          }
 183   
 184          // read existing cache entries, remove non-varying, and add this one to the list
 185          $entries = array();
 186          $vary = $response->headers->get('vary');
 187          foreach ($this->getMetadata($key) as $entry) {
 188              if (!isset($entry[1]['vary'][0])) {
 189                  $entry[1]['vary'] = array('');
 190              }
 191   
 192              if ($vary != $entry[1]['vary'][0] || !$this->requestsMatch($vary, $entry[0], $storedEnv)) {
 193                  $entries[] = $entry;
 194              }
 195          }
 196   
 197          $headers = $this->persistResponse($response);
 198          unset($headers['age']);
 199   
 200          array_unshift($entries, array($storedEnv, $headers));
 201   
 202          if (false === $this->save($key, serialize($entries))) {
 203              throw new \RuntimeException('Unable to store the metadata.');
 204          }
 205   
 206          return $key;
 207      }
 208   
 209      /**
 210       * Returns content digest for $response.
 211       *
 212       * @param Response $response
 213       *
 214       * @return string
 215       */
 216      protected function generateContentDigest(Response $response)
 217      {
 218          return 'en'.sha1($response->getContent());
 219      }
 220   
 221      /**
 222       * Invalidates all cache entries that match the request.
 223       *
 224       * @param Request $request A Request instance
 225       *
 226       * @throws \RuntimeException
 227       */
 228      public function invalidate(Request $request)
 229      {
 230          $modified = false;
 231          $key = $this->getCacheKey($request);
 232   
 233          $entries = array();
 234          foreach ($this->getMetadata($key) as $entry) {
 235              $response = $this->restoreResponse($entry[1]);
 236              if ($response->isFresh()) {
 237                  $response->expire();
 238                  $modified = true;
 239                  $entries[] = array($entry[0], $this->persistResponse($response));
 240              } else {
 241                  $entries[] = $entry;
 242              }
 243          }
 244   
 245          if ($modified) {
 246              if (false === $this->save($key, serialize($entries))) {
 247                  throw new \RuntimeException('Unable to store the metadata.');
 248              }
 249          }
 250      }
 251   
 252      /**
 253       * Determines whether two Request HTTP header sets are non-varying based on
 254       * the vary response header value provided.
 255       *
 256       * @param string $vary A Response vary header
 257       * @param array  $env1 A Request HTTP header array
 258       * @param array  $env2 A Request HTTP header array
 259       *
 260       * @return bool    true if the two environments match, false otherwise
 261       */
 262      private function requestsMatch($vary, $env1, $env2)
 263      {
 264          if (empty($vary)) {
 265              return true;
 266          }
 267   
 268          foreach (preg_split('/[\s,]+/', $vary) as $header) {
 269              $key = strtr(strtolower($header), '_', '-');
 270              $v1 = isset($env1[$key]) ? $env1[$key] : null;
 271              $v2 = isset($env2[$key]) ? $env2[$key] : null;
 272              if ($v1 !== $v2) {
 273                  return false;
 274              }
 275          }
 276   
 277          return true;
 278      }
 279   
 280      /**
 281       * Gets all data associated with the given key.
 282       *
 283       * Use this method only if you know what you are doing.
 284       *
 285       * @param string $key The store key
 286       *
 287       * @return array An array of data associated with the key
 288       */
 289      private function getMetadata($key)
 290      {
 291          if (false === $entries = $this->load($key)) {
 292              return array();
 293          }
 294   
 295          return unserialize($entries);
 296      }
 297   
 298      /**
 299       * Purges data for the given URL.
 300       *
 301       * @param string $url A URL
 302       *
 303       * @return bool    true if the URL exists and has been purged, false otherwise
 304       */
 305      public function purge($url)
 306      {
 307          if (is_file($path = $this->getPath($this->getCacheKey(Request::create($url))))) {
 308              unlink($path);
 309   
 310              return true;
 311          }
 312   
 313          return false;
 314      }
 315   
 316      /**
 317       * Loads data for the given key.
 318       *
 319       * @param string $key The store key
 320       *
 321       * @return string The data associated with the key
 322       */
 323      private function load($key)
 324      {
 325          $path = $this->getPath($key);
 326   
 327          return is_file($path) ? file_get_contents($path) : false;
 328      }
 329   
 330      /**
 331       * Save data for the given key.
 332       *
 333       * @param string $key  The store key
 334       * @param string $data The data to store
 335       *
 336       * @return bool
 337       */
 338      private function save($key, $data)
 339      {
 340          $path = $this->getPath($key);
 341          if (!is_dir(dirname($path)) && false === @mkdir(dirname($path), 0777, true)) {
 342              return false;
 343          }
 344   
 345          $tmpFile = tempnam(dirname($path), basename($path));
 346          if (false === $fp = @fopen($tmpFile, 'wb')) {
 347              return false;
 348          }
 349          @fwrite($fp, $data);
 350          @fclose($fp);
 351   
 352          if ($data != file_get_contents($tmpFile)) {
 353              return false;
 354          }
 355   
 356          if (false === @rename($tmpFile, $path)) {
 357              return false;
 358          }
 359   
 360          @chmod($path, 0666 & ~umask());
 361      }
 362   
 363      public function getPath($key)
 364      {
 365          return $this->root.DIRECTORY_SEPARATOR.substr($key, 0, 2).DIRECTORY_SEPARATOR.substr($key, 2, 2).DIRECTORY_SEPARATOR.substr($key, 4, 2).DIRECTORY_SEPARATOR.substr($key, 6);
 366      }
 367   
 368      /**
 369       * Returns a cache key for the given Request.
 370       *
 371       * @param Request $request A Request instance
 372       *
 373       * @return string A key for the given Request
 374       */
 375      private function getCacheKey(Request $request)
 376      {
 377          if (isset($this->keyCache[$request])) {
 378              return $this->keyCache[$request];
 379          }
 380   
 381          return $this->keyCache[$request] = 'md'.sha1($request->getUri());
 382      }
 383   
 384      /**
 385       * Persists the Request HTTP headers.
 386       *
 387       * @param Request $request A Request instance
 388       *
 389       * @return array An array of HTTP headers
 390       */
 391      private function persistRequest(Request $request)
 392      {
 393          return $request->headers->all();
 394      }
 395   
 396      /**
 397       * Persists the Response HTTP headers.
 398       *
 399       * @param Response $response A Response instance
 400       *
 401       * @return array An array of HTTP headers
 402       */
 403      private function persistResponse(Response $response)
 404      {
 405          $headers = $response->headers->all();
 406          $headers['X-Status'] = array($response->getStatusCode());
 407   
 408          return $headers;
 409      }
 410   
 411      /**
 412       * Restores a Response from the HTTP headers and body.
 413       *
 414       * @param array  $headers An array of HTTP headers for the Response
 415       * @param string $body    The Response body
 416       *
 417       * @return Response
 418       */
 419      private function restoreResponse($headers, $body = null)
 420      {
 421          $status = $headers['X-Status'][0];
 422          unset($headers['X-Status']);
 423   
 424          if (null !== $body) {
 425              $headers['X-Body-File'] = array($body);
 426          }
 427   
 428          return new Response($body, $status, $headers);
 429      }
 430  }
 431