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