Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

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

BinaryFileResponse.php

Zuletzt modifiziert: 09.10.2024, 12:54 - Dateigröße: 11.62 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\HttpFoundation;
 013   
 014  use Symfony\Component\HttpFoundation\File\File;
 015  use Symfony\Component\HttpFoundation\File\Exception\FileException;
 016   
 017  /**
 018   * BinaryFileResponse represents an HTTP response delivering a file.
 019   *
 020   * @author Niklas Fiekas <niklas.fiekas@tu-clausthal.de>
 021   * @author stealth35 <stealth35-php@live.fr>
 022   * @author Igor Wiedler <igor@wiedler.ch>
 023   * @author Jordan Alliot <jordan.alliot@gmail.com>
 024   * @author Sergey Linnik <linniksa@gmail.com>
 025   */
 026  class BinaryFileResponse extends Response
 027  {
 028      protected static $trustXSendfileTypeHeader = false;
 029   
 030      /**
 031       * @var File
 032       */
 033      protected $file;
 034      protected $offset;
 035      protected $maxlen;
 036      protected $deleteFileAfterSend = false;
 037   
 038      /**
 039       * Constructor.
 040       *
 041       * @param \SplFileInfo|string $file               The file to stream
 042       * @param int                 $status             The response status code
 043       * @param array               $headers            An array of response headers
 044       * @param bool                $public             Files are public by default
 045       * @param null|string         $contentDisposition The type of Content-Disposition to set automatically with the filename
 046       * @param bool                $autoEtag           Whether the ETag header should be automatically set
 047       * @param bool                $autoLastModified   Whether the Last-Modified header should be automatically set
 048       */
 049      public function __construct($file, $status = 200, $headers = array(), $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
 050      {
 051          parent::__construct(null, $status, $headers);
 052   
 053          $this->setFile($file, $contentDisposition, $autoEtag, $autoLastModified);
 054   
 055          if ($public) {
 056              $this->setPublic();
 057          }
 058      }
 059   
 060      /**
 061       * @param \SplFileInfo|string $file               The file to stream
 062       * @param int                 $status             The response status code
 063       * @param array               $headers            An array of response headers
 064       * @param bool                $public             Files are public by default
 065       * @param null|string         $contentDisposition The type of Content-Disposition to set automatically with the filename
 066       * @param bool                $autoEtag           Whether the ETag header should be automatically set
 067       * @param bool                $autoLastModified   Whether the Last-Modified header should be automatically set
 068       *
 069       * @return BinaryFileResponse The created response
 070       */
 071      public static function create($file = null, $status = 200, $headers = array(), $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
 072      {
 073          return new static($file, $status, $headers, $public, $contentDisposition, $autoEtag, $autoLastModified);
 074      }
 075   
 076      /**
 077       * Sets the file to stream.
 078       *
 079       * @param \SplFileInfo|string $file               The file to stream
 080       * @param string              $contentDisposition
 081       * @param bool                $autoEtag
 082       * @param bool                $autoLastModified
 083       *
 084       * @return BinaryFileResponse
 085       *
 086       * @throws FileException
 087       */
 088      public function setFile($file, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
 089      {
 090          if (!$file instanceof File) {
 091              if ($file instanceof \SplFileInfo) {
 092                  $file = new File($file->getPathname());
 093              } else {
 094                  $file = new File((string) $file);
 095              }
 096          }
 097   
 098          if (!$file->isReadable()) {
 099              throw new FileException('File must be readable.');
 100          }
 101   
 102          $this->file = $file;
 103   
 104          if ($autoEtag) {
 105              $this->setAutoEtag();
 106          }
 107   
 108          if ($autoLastModified) {
 109              $this->setAutoLastModified();
 110          }
 111   
 112          if ($contentDisposition) {
 113              $this->setContentDisposition($contentDisposition);
 114          }
 115   
 116          return $this;
 117      }
 118   
 119      /**
 120       * Gets the file.
 121       *
 122       * @return File The file to stream
 123       */
 124      public function getFile()
 125      {
 126          return $this->file;
 127      }
 128   
 129      /**
 130       * Automatically sets the Last-Modified header according the file modification date.
 131       */
 132      public function setAutoLastModified()
 133      {
 134          $this->setLastModified(\DateTime::createFromFormat('U', $this->file->getMTime()));
 135   
 136          return $this;
 137      }
 138   
 139      /**
 140       * Automatically sets the ETag header according to the checksum of the file.
 141       */
 142      public function setAutoEtag()
 143      {
 144          $this->setEtag(sha1_file($this->file->getPathname()));
 145   
 146          return $this;
 147      }
 148   
 149      /**
 150       * Sets the Content-Disposition header with the given filename.
 151       *
 152       * @param string $disposition      ResponseHeaderBag::DISPOSITION_INLINE or ResponseHeaderBag::DISPOSITION_ATTACHMENT
 153       * @param string $filename         Optionally use this filename instead of the real name of the file
 154       * @param string $filenameFallback A fallback filename, containing only ASCII characters. Defaults to an automatically encoded filename
 155       *
 156       * @return BinaryFileResponse
 157       */
 158      public function setContentDisposition($disposition, $filename = '', $filenameFallback = '')
 159      {
 160          if ($filename === '') {
 161              $filename = $this->file->getFilename();
 162          }
 163   
 164          if ('' === $filenameFallback && (!preg_match('/^[\x20-\x7e]*$/', $filename) || false !== strpos($filename, '%'))) {
 165              $encoding = mb_detect_encoding($filename, null, true);
 166   
 167              for ($i = 0; $i < mb_strlen($filename, $encoding); ++$i) {
 168                  $char = mb_substr($filename, $i, 1, $encoding);
 169   
 170                  if ('%' === $char || ord($char) < 32 || ord($char) > 126) {
 171                      $filenameFallback .= '_';
 172                  } else {
 173                      $filenameFallback .= $char;
 174                  }
 175              }
 176          }
 177   
 178          $dispositionHeader = $this->headers->makeDisposition($disposition, $filename, $filenameFallback);
 179          $this->headers->set('Content-Disposition', $dispositionHeader);
 180   
 181          return $this;
 182      }
 183   
 184      /**
 185       * {@inheritdoc}
 186       */
 187      public function prepare(Request $request)
 188      {
 189          $this->headers->set('Content-Length', $this->file->getSize());
 190   
 191          if (!$this->headers->has('Accept-Ranges')) {
 192              // Only accept ranges on safe HTTP methods
 193              $this->headers->set('Accept-Ranges', $request->isMethodSafe() ? 'bytes' : 'none');
 194          }
 195   
 196          if (!$this->headers->has('Content-Type')) {
 197              $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
 198          }
 199   
 200          if ('HTTP/1.0' !== $request->server->get('SERVER_PROTOCOL')) {
 201              $this->setProtocolVersion('1.1');
 202          }
 203   
 204          $this->ensureIEOverSSLCompatibility($request);
 205   
 206          $this->offset = 0;
 207          $this->maxlen = -1;
 208   
 209          if (self::$trustXSendfileTypeHeader && $request->headers->has('X-Sendfile-Type')) {
 210              // Use X-Sendfile, do not send any content.
 211              $type = $request->headers->get('X-Sendfile-Type');
 212              $path = $this->file->getRealPath();
 213              // Fall back to scheme://path for stream wrapped locations.
 214              if (false === $path) {
 215                  $path = $this->file->getPathname();
 216              }
 217              if (strtolower($type) === 'x-accel-redirect') {
 218                  // Do X-Accel-Mapping substitutions.
 219                  // @link http://wiki.nginx.org/X-accel#X-Accel-Redirect
 220                  foreach (explode(',', $request->headers->get('X-Accel-Mapping', '')) as $mapping) {
 221                      $mapping = explode('=', $mapping, 2);
 222   
 223                      if (2 === count($mapping)) {
 224                          $pathPrefix = trim($mapping[0]);
 225                          $location = trim($mapping[1]);
 226   
 227                          if (substr($path, 0, strlen($pathPrefix)) === $pathPrefix) {
 228                              $path = $location.substr($path, strlen($pathPrefix));
 229                              break;
 230                          }
 231                      }
 232                  }
 233              }
 234              $this->headers->set($type, $path);
 235              $this->maxlen = 0;
 236          } elseif ($request->headers->has('Range')) {
 237              // Process the range headers.
 238              if (!$request->headers->has('If-Range') || $this->hasValidIfRangeHeader($request->headers->get('If-Range'))) {
 239                  $range = $request->headers->get('Range');
 240                  $fileSize = $this->file->getSize();
 241   
 242                  list($start, $end) = explode('-', substr($range, 6), 2) + array(0);
 243   
 244                  $end = ('' === $end) ? $fileSize - 1 : (int) $end;
 245   
 246                  if ('' === $start) {
 247                      $start = $fileSize - $end;
 248                      $end = $fileSize - 1;
 249                  } else {
 250                      $start = (int) $start;
 251                  }
 252   
 253                  if ($start <= $end) {
 254                      if ($start < 0 || $end > $fileSize - 1) {
 255                          $this->setStatusCode(416);
 256                          $this->headers->set('Content-Range', sprintf('bytes */%s', $fileSize));
 257                      } elseif ($start !== 0 || $end !== $fileSize - 1) {
 258                          $this->maxlen = $end < $fileSize ? $end - $start + 1 : -1;
 259                          $this->offset = $start;
 260   
 261                          $this->setStatusCode(206);
 262                          $this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize));
 263                          $this->headers->set('Content-Length', $end - $start + 1);
 264                      }
 265                  }
 266              }
 267          }
 268   
 269          return $this;
 270      }
 271   
 272      private function hasValidIfRangeHeader($header)
 273      {
 274          if ($this->getEtag() === $header) {
 275              return true;
 276          }
 277   
 278          if (null === $lastModified = $this->getLastModified()) {
 279              return false;
 280          }
 281   
 282          return $lastModified->format('D, d M Y H:i:s').' GMT' === $header;
 283      }
 284   
 285      /**
 286       * Sends the file.
 287       *
 288       * {@inheritdoc}
 289       */
 290      public function sendContent()
 291      {
 292          if (!$this->isSuccessful()) {
 293              return parent::sendContent();
 294          }
 295   
 296          if (0 === $this->maxlen) {
 297              return $this;
 298          }
 299   
 300          $out = fopen('php://output', 'wb');
 301          $file = fopen($this->file->getPathname(), 'rb');
 302   
 303          stream_copy_to_stream($file, $out, $this->maxlen, $this->offset);
 304   
 305          fclose($out);
 306          fclose($file);
 307   
 308          if ($this->deleteFileAfterSend) {
 309              unlink($this->file->getPathname());
 310          }
 311   
 312          return $this;
 313      }
 314   
 315      /**
 316       * {@inheritdoc}
 317       *
 318       * @throws \LogicException when the content is not null
 319       */
 320      public function setContent($content)
 321      {
 322          if (null !== $content) {
 323              throw new \LogicException('The content cannot be set on a BinaryFileResponse instance.');
 324          }
 325      }
 326   
 327      /**
 328       * {@inheritdoc}
 329       *
 330       * @return false
 331       */
 332      public function getContent()
 333      {
 334          return false;
 335      }
 336   
 337      /**
 338       * Trust X-Sendfile-Type header.
 339       */
 340      public static function trustXSendfileTypeHeader()
 341      {
 342          self::$trustXSendfileTypeHeader = true;
 343      }
 344   
 345      /**
 346       * If this is set to true, the file will be unlinked after the request is send
 347       * Note: If the X-Sendfile header is used, the deleteFileAfterSend setting will not be used.
 348       *
 349       * @param bool $shouldDelete
 350       *
 351       * @return BinaryFileResponse
 352       */
 353      public function deleteFileAfterSend($shouldDelete)
 354      {
 355          $this->deleteFileAfterSend = $shouldDelete;
 356   
 357          return $this;
 358      }
 359  }
 360