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