Open Journal Systems  3.3.0
lib/vendor/symfony/http-foundation/BinaryFileResponse.php
1 <?php
2 
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11 
13 
16 
27 {
28  protected static $trustXSendfileTypeHeader = false;
29 
33  protected $file;
34  protected $offset;
35  protected $maxlen;
36  protected $deleteFileAfterSend = false;
37 
49  public function __construct($file, $status = 200, $headers = array(), $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
50  {
51  parent::__construct(null, $status, $headers);
52 
53  $this->setFile($file, $contentDisposition, $autoEtag, $autoLastModified);
54 
55  if ($public) {
56  $this->setPublic();
57  }
58  }
59 
71  public static function create($file = null, $status = 200, $headers = array(), $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
72  {
73  return new static($file, $status, $headers, $public, $contentDisposition, $autoEtag, $autoLastModified);
74  }
75 
88  public function setFile($file, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
89  {
90  if (!$file instanceof File) {
91  if ($file instanceof \SplFileInfo) {
92  $file = new File($file->getPathname());
93  } else {
94  $file = new File((string) $file);
95  }
96  }
97 
98  if (!$file->isReadable()) {
99  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 
124  public function getFile()
125  {
126  return $this->file;
127  }
128 
132  public function setAutoLastModified()
133  {
134  $this->setLastModified(\DateTime::createFromFormat('U', $this->file->getMTime()));
135 
136  return $this;
137  }
138 
142  public function setAutoEtag()
143  {
144  $this->setEtag(sha1_file($this->file->getPathname()));
145 
146  return $this;
147  }
148 
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, $filenameLength = mb_strlen($filename, $encoding); $i < $filenameLength; ++$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 
187  public function prepare(Request $request)
188  {
189  if (!$this->headers->has('Content-Type')) {
190  $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
191  }
192 
193  if ('HTTP/1.0' !== $request->server->get('SERVER_PROTOCOL')) {
194  $this->setProtocolVersion('1.1');
195  }
196 
197  $this->ensureIEOverSSLCompatibility($request);
198 
199  $this->offset = 0;
200  $this->maxlen = -1;
201 
202  if (false === $fileSize = $this->file->getSize()) {
203  return $this;
204  }
205  $this->headers->set('Content-Length', $fileSize);
206 
207  if (!$this->headers->has('Accept-Ranges')) {
208  // Only accept ranges on safe HTTP methods
209  $this->headers->set('Accept-Ranges', $request->isMethodSafe(false) ? 'bytes' : 'none');
210  }
211 
212  if (self::$trustXSendfileTypeHeader && $request->headers->has('X-Sendfile-Type')) {
213  // Use X-Sendfile, do not send any content.
214  $type = $request->headers->get('X-Sendfile-Type');
215  $path = $this->file->getRealPath();
216  // Fall back to scheme://path for stream wrapped locations.
217  if (false === $path) {
218  $path = $this->file->getPathname();
219  }
220  if (strtolower($type) === 'x-accel-redirect') {
221  // Do X-Accel-Mapping substitutions.
222  // @link http://wiki.nginx.org/X-accel#X-Accel-Redirect
223  foreach (explode(',', $request->headers->get('X-Accel-Mapping', '')) as $mapping) {
224  $mapping = explode('=', $mapping, 2);
225 
226  if (2 === count($mapping)) {
227  $pathPrefix = trim($mapping[0]);
228  $location = trim($mapping[1]);
229 
230  if (substr($path, 0, strlen($pathPrefix)) === $pathPrefix) {
231  $path = $location.substr($path, strlen($pathPrefix));
232  break;
233  }
234  }
235  }
236  }
237  $this->headers->set($type, $path);
238  $this->maxlen = 0;
239  } elseif ($request->headers->has('Range')) {
240  // Process the range headers.
241  if (!$request->headers->has('If-Range') || $this->hasValidIfRangeHeader($request->headers->get('If-Range'))) {
242  $range = $request->headers->get('Range');
243 
244  list($start, $end) = explode('-', substr($range, 6), 2) + array(0);
245 
246  $end = ('' === $end) ? $fileSize - 1 : (int) $end;
247 
248  if ('' === $start) {
249  $start = $fileSize - $end;
250  $end = $fileSize - 1;
251  } else {
252  $start = (int) $start;
253  }
254 
255  if ($start <= $end) {
256  if ($start < 0 || $end > $fileSize - 1) {
257  $this->setStatusCode(416);
258  $this->headers->set('Content-Range', sprintf('bytes */%s', $fileSize));
259  } elseif ($start !== 0 || $end !== $fileSize - 1) {
260  $this->maxlen = $end < $fileSize ? $end - $start + 1 : -1;
261  $this->offset = $start;
262 
263  $this->setStatusCode(206);
264  $this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize));
265  $this->headers->set('Content-Length', $end - $start + 1);
266  }
267  }
268  }
269  }
270 
271  return $this;
272  }
273 
274  private function hasValidIfRangeHeader($header)
275  {
276  if ($this->getEtag() === $header) {
277  return true;
278  }
279 
280  if (null === $lastModified = $this->getLastModified()) {
281  return false;
282  }
283 
284  return $lastModified->format('D, d M Y H:i:s').' GMT' === $header;
285  }
286 
292  public function sendContent()
293  {
294  if (!$this->isSuccessful()) {
295  return parent::sendContent();
296  }
297 
298  if (0 === $this->maxlen) {
299  return $this;
300  }
301 
302  $out = fopen('php://output', 'wb');
303  $file = fopen($this->file->getPathname(), 'rb');
304 
305  stream_copy_to_stream($file, $out, $this->maxlen, $this->offset);
306 
307  fclose($out);
308  fclose($file);
309 
310  if ($this->deleteFileAfterSend) {
311  unlink($this->file->getPathname());
312  }
313 
314  return $this;
315  }
316 
322  public function setContent($content)
323  {
324  if (null !== $content) {
325  throw new \LogicException('The content cannot be set on a BinaryFileResponse instance.');
326  }
327  }
328 
334  public function getContent()
335  {
336  return false;
337  }
338 
342  public static function trustXSendfileTypeHeader()
343  {
344  self::$trustXSendfileTypeHeader = true;
345  }
346 
355  public function deleteFileAfterSend($shouldDelete)
356  {
357  $this->deleteFileAfterSend = $shouldDelete;
358 
359  return $this;
360  }
361 }
Symfony\Component\HttpFoundation\BinaryFileResponse\setAutoLastModified
setAutoLastModified()
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:135
Symfony\Component\HttpFoundation\File\File
Definition: lib/vendor/symfony/http-foundation/File/File.php:24
Symfony\Component\HttpFoundation\BinaryFileResponse\prepare
prepare(Request $request)
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:190
Symfony\Component\HttpFoundation\Response\setProtocolVersion
setProtocolVersion($version)
Definition: lib/vendor/symfony/http-foundation/Response.php:454
Symfony\Component\HttpFoundation\Response
Definition: lib/vendor/symfony/http-foundation/Response.php:19
Symfony\Component\HttpFoundation\Request\isMethodSafe
isMethodSafe()
Definition: lib/vendor/symfony/http-foundation/Request.php:1612
Symfony\Component\HttpFoundation\Response\getLastModified
getLastModified()
Definition: lib/vendor/symfony/http-foundation/Response.php:896
Symfony\Component\HttpFoundation\Response\ensureIEOverSSLCompatibility
ensureIEOverSSLCompatibility(Request $request)
Definition: lib/vendor/symfony/http-foundation/Response.php:1298
Symfony\Component\HttpFoundation\Response\setLastModified
setLastModified(\DateTime $date=null)
Definition: lib/vendor/symfony/http-foundation/Response.php:912
Symfony\Component\HttpFoundation\BinaryFileResponse\setAutoEtag
setAutoEtag()
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:145
Symfony\Component\HttpFoundation\BinaryFileResponse\deleteFileAfterSend
deleteFileAfterSend($shouldDelete)
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:358
Symfony\Component\HttpFoundation\BinaryFileResponse\create
static create($file=null, $status=200, $headers=array(), $public=true, $contentDisposition=null, $autoEtag=false, $autoLastModified=true)
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:74
Symfony\Component\HttpFoundation\BinaryFileResponse\__construct
__construct($file, $status=200, $headers=array(), $public=true, $contentDisposition=null, $autoEtag=false, $autoLastModified=true)
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:52
Symfony\Component\HttpFoundation\BinaryFileResponse\setContent
setContent($content)
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:325
Symfony\Component\HttpFoundation\Request\get
get($key, $default=null)
Definition: lib/vendor/symfony/http-foundation/Request.php:869
Symfony\Component\HttpFoundation\Request
Definition: lib/vendor/symfony/http-foundation/Request.php:31
Symfony\Component\HttpFoundation\BinaryFileResponse\trustXSendfileTypeHeader
static trustXSendfileTypeHeader()
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:345
Symfony\Component\HttpFoundation\BinaryFileResponse\sendContent
sendContent()
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:295
Symfony\Component\HttpFoundation\BinaryFileResponse\setFile
setFile($file, $contentDisposition=null, $autoEtag=false, $autoLastModified=true)
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:91
Symfony\Component\HttpFoundation\Response\$content
$content
Definition: lib/vendor/symfony/http-foundation/Response.php:98
Symfony\Component\HttpFoundation\BinaryFileResponse
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:26
Symfony\Component\HttpFoundation\Response\$headers
$headers
Definition: lib/vendor/symfony/http-foundation/Response.php:90
Symfony\Component\HttpFoundation\BinaryFileResponse\setContentDisposition
setContentDisposition($disposition, $filename='', $filenameFallback='')
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:161
Symfony\Component\HttpFoundation\BinaryFileResponse\$trustXSendfileTypeHeader
static $trustXSendfileTypeHeader
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:28
Symfony\Component\HttpFoundation\BinaryFileResponse\$offset
$offset
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:37
Symfony\Component\HttpFoundation\BinaryFileResponse\getFile
getFile()
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:127
Symfony\Component\HttpFoundation\BinaryFileResponse\getContent
getContent()
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:337
Symfony\Component\HttpFoundation\Response\isSuccessful
isSuccessful()
Definition: lib/vendor/symfony/http-foundation/Response.php:1162
Seboettg\Collection\count
count()
Definition: ArrayListTrait.php:253
Symfony\Component\HttpFoundation\BinaryFileResponse\$file
$file
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:36
Symfony\Component\HttpFoundation\BinaryFileResponse\$deleteFileAfterSend
$deleteFileAfterSend
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:39
Symfony\Component\HttpFoundation
Definition: lib/vendor/symfony/http-foundation/AcceptHeader.php:12
Symfony\Component\HttpFoundation\Response\setPublic
setPublic()
Definition: lib/vendor/symfony/http-foundation/Response.php:633
Symfony\Component\HttpFoundation\Response\setEtag
setEtag($etag=null, $weak=false)
Definition: lib/vendor/symfony/http-foundation/Response.php:947
Symfony\Component\HttpFoundation\Response\getEtag
getEtag()
Definition: lib/vendor/symfony/http-foundation/Response.php:932
Symfony\Component\HttpFoundation\File\Exception\FileException
Definition: lib/vendor/symfony/http-foundation/File/Exception/FileException.php:19
Symfony\Component\HttpFoundation\Response\setStatusCode
setStatusCode($code, $text=null)
Definition: lib/vendor/symfony/http-foundation/Response.php:488
Symfony\Component\HttpFoundation\BinaryFileResponse\$maxlen
$maxlen
Definition: lib/vendor/symfony/http-foundation/BinaryFileResponse.php:38