PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.27.0
GiveWP – Donation Plugin and Fundraising Platform v2.27.0
4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / vendor / symfony / http-foundation / BinaryFileResponse.php
give / vendor / symfony / http-foundation Last commit date
Exception 4 years ago File 4 years ago Session 4 years ago Tests 4 years ago AcceptHeader.php 4 years ago AcceptHeaderItem.php 4 years ago ApacheRequest.php 4 years ago BinaryFileResponse.php 4 years ago Cookie.php 4 years ago ExpressionRequestMatcher.php 4 years ago FileBag.php 4 years ago HeaderBag.php 4 years ago IpUtils.php 4 years ago JsonResponse.php 4 years ago LICENSE 4 years ago ParameterBag.php 4 years ago RedirectResponse.php 4 years ago Request.php 4 years ago RequestMatcher.php 4 years ago RequestMatcherInterface.php 4 years ago RequestStack.php 4 years ago Response.php 4 years ago ResponseHeaderBag.php 4 years ago ServerBag.php 4 years ago StreamedResponse.php 4 years ago
BinaryFileResponse.php
368 lines
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
12 namespace Symfony\Component\HttpFoundation;
13
14 use Symfony\Component\HttpFoundation\File\Exception\FileException;
15 use Symfony\Component\HttpFoundation\File\File;
16
17 /**
18 * BinaryFileResponse represents an HTTP response delivering a file.
19 *
20 * @author Niklas Fiekas <niklas.fiekas@tu-clausthal.de>
21 * @author stealth35 <stealth35-php@live.fr>
22 * @author Igor Wiedler <igor@wiedler.ch>
23 * @author Jordan Alliot <jordan.alliot@gmail.com>
24 * @author Sergey Linnik <linniksa@gmail.com>
25 */
26 class BinaryFileResponse extends Response
27 {
28 protected static $trustXSendfileTypeHeader = false;
29
30 /**
31 * @var File
32 */
33 protected $file;
34 protected $offset = 0;
35 protected $maxlen = -1;
36 protected $deleteFileAfterSend = false;
37
38 /**
39 * @param \SplFileInfo|string $file The file to stream
40 * @param int $status The response status code
41 * @param array $headers An array of response headers
42 * @param bool $public Files are public by default
43 * @param string|null $contentDisposition The type of Content-Disposition to set automatically with the filename
44 * @param bool $autoEtag Whether the ETag header should be automatically set
45 * @param bool $autoLastModified Whether the Last-Modified header should be automatically set
46 */
47 public function __construct($file, $status = 200, $headers = [], $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
48 {
49 parent::__construct(null, $status, $headers);
50
51 $this->setFile($file, $contentDisposition, $autoEtag, $autoLastModified);
52
53 if ($public) {
54 $this->setPublic();
55 }
56 }
57
58 /**
59 * @param \SplFileInfo|string $file The file to stream
60 * @param int $status The response status code
61 * @param array $headers An array of response headers
62 * @param bool $public Files are public by default
63 * @param string|null $contentDisposition The type of Content-Disposition to set automatically with the filename
64 * @param bool $autoEtag Whether the ETag header should be automatically set
65 * @param bool $autoLastModified Whether the Last-Modified header should be automatically set
66 *
67 * @return static
68 */
69 public static function create($file = null, $status = 200, $headers = [], $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
70 {
71 return new static($file, $status, $headers, $public, $contentDisposition, $autoEtag, $autoLastModified);
72 }
73
74 /**
75 * Sets the file to stream.
76 *
77 * @param \SplFileInfo|string $file The file to stream
78 * @param string $contentDisposition
79 * @param bool $autoEtag
80 * @param bool $autoLastModified
81 *
82 * @return $this
83 *
84 * @throws FileException
85 */
86 public function setFile($file, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
87 {
88 if (!$file instanceof File) {
89 if ($file instanceof \SplFileInfo) {
90 $file = new File($file->getPathname());
91 } else {
92 $file = new File((string) $file);
93 }
94 }
95
96 if (!$file->isReadable()) {
97 throw new FileException('File must be readable.');
98 }
99
100 $this->file = $file;
101
102 if ($autoEtag) {
103 $this->setAutoEtag();
104 }
105
106 if ($autoLastModified) {
107 $this->setAutoLastModified();
108 }
109
110 if ($contentDisposition) {
111 $this->setContentDisposition($contentDisposition);
112 }
113
114 return $this;
115 }
116
117 /**
118 * Gets the file.
119 *
120 * @return File The file to stream
121 */
122 public function getFile()
123 {
124 return $this->file;
125 }
126
127 /**
128 * Automatically sets the Last-Modified header according the file modification date.
129 */
130 public function setAutoLastModified()
131 {
132 $this->setLastModified(\DateTime::createFromFormat('U', $this->file->getMTime()));
133
134 return $this;
135 }
136
137 /**
138 * Automatically sets the ETag header according to the checksum of the file.
139 */
140 public function setAutoEtag()
141 {
142 $this->setEtag(base64_encode(hash_file('sha256', $this->file->getPathname(), true)));
143
144 return $this;
145 }
146
147 /**
148 * Sets the Content-Disposition header with the given filename.
149 *
150 * @param string $disposition ResponseHeaderBag::DISPOSITION_INLINE or ResponseHeaderBag::DISPOSITION_ATTACHMENT
151 * @param string $filename Optionally use this UTF-8 encoded filename instead of the real name of the file
152 * @param string $filenameFallback A fallback filename, containing only ASCII characters. Defaults to an automatically encoded filename
153 *
154 * @return $this
155 */
156 public function setContentDisposition($disposition, $filename = '', $filenameFallback = '')
157 {
158 if ('' === $filename) {
159 $filename = $this->file->getFilename();
160 }
161
162 if ('' === $filenameFallback && (!preg_match('/^[\x20-\x7e]*$/', $filename) || false !== strpos($filename, '%'))) {
163 $encoding = mb_detect_encoding($filename, null, true) ?: '8bit';
164
165 for ($i = 0, $filenameLength = mb_strlen($filename, $encoding); $i < $filenameLength; ++$i) {
166 $char = mb_substr($filename, $i, 1, $encoding);
167
168 if ('%' === $char || \ord($char) < 32 || \ord($char) > 126) {
169 $filenameFallback .= '_';
170 } else {
171 $filenameFallback .= $char;
172 }
173 }
174 }
175
176 $dispositionHeader = $this->headers->makeDisposition($disposition, $filename, $filenameFallback);
177 $this->headers->set('Content-Disposition', $dispositionHeader);
178
179 return $this;
180 }
181
182 /**
183 * {@inheritdoc}
184 */
185 public function prepare(Request $request)
186 {
187 if (!$this->headers->has('Content-Type')) {
188 $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
189 }
190
191 if ('HTTP/1.0' !== $request->server->get('SERVER_PROTOCOL')) {
192 $this->setProtocolVersion('1.1');
193 }
194
195 $this->ensureIEOverSSLCompatibility($request);
196
197 $this->offset = 0;
198 $this->maxlen = -1;
199
200 if (false === $fileSize = $this->file->getSize()) {
201 return $this;
202 }
203 $this->headers->set('Content-Length', $fileSize);
204
205 if (!$this->headers->has('Accept-Ranges')) {
206 // Only accept ranges on safe HTTP methods
207 $this->headers->set('Accept-Ranges', $request->isMethodSafe(false) ? 'bytes' : 'none');
208 }
209
210 if (self::$trustXSendfileTypeHeader && $request->headers->has('X-Sendfile-Type')) {
211 // Use X-Sendfile, do not send any content.
212 $type = $request->headers->get('X-Sendfile-Type');
213 $path = $this->file->getRealPath();
214 // Fall back to scheme://path for stream wrapped locations.
215 if (false === $path) {
216 $path = $this->file->getPathname();
217 }
218 if ('x-accel-redirect' === strtolower($type)) {
219 // Do X-Accel-Mapping substitutions.
220 // @link https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/#x-accel-redirect
221 foreach (explode(',', $request->headers->get('X-Accel-Mapping', '')) as $mapping) {
222 $mapping = explode('=', $mapping, 2);
223
224 if (2 === \count($mapping)) {
225 $pathPrefix = trim($mapping[0]);
226 $location = trim($mapping[1]);
227
228 if (substr($path, 0, \strlen($pathPrefix)) === $pathPrefix) {
229 $path = $location.substr($path, \strlen($pathPrefix));
230 // Only set X-Accel-Redirect header if a valid URI can be produced
231 // as nginx does not serve arbitrary file paths.
232 $this->headers->set($type, $path);
233 $this->maxlen = 0;
234 break;
235 }
236 }
237 }
238 } else {
239 $this->headers->set($type, $path);
240 $this->maxlen = 0;
241 }
242 } elseif ($request->headers->has('Range') && $request->isMethod('GET')) {
243 // Process the range headers.
244 if (!$request->headers->has('If-Range') || $this->hasValidIfRangeHeader($request->headers->get('If-Range'))) {
245 $range = $request->headers->get('Range');
246
247 if (0 === strpos($range, 'bytes=')) {
248 list($start, $end) = explode('-', substr($range, 6), 2) + [0];
249
250 $end = ('' === $end) ? $fileSize - 1 : (int) $end;
251
252 if ('' === $start) {
253 $start = $fileSize - $end;
254 $end = $fileSize - 1;
255 } else {
256 $start = (int) $start;
257 }
258
259 if ($start <= $end) {
260 $end = min($end, $fileSize - 1);
261 if ($start < 0 || $start > $end) {
262 $this->setStatusCode(416);
263 $this->headers->set('Content-Range', sprintf('bytes */%s', $fileSize));
264 } elseif ($end - $start < $fileSize - 1) {
265 $this->maxlen = $end < $fileSize ? $end - $start + 1 : -1;
266 $this->offset = $start;
267
268 $this->setStatusCode(206);
269 $this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize));
270 $this->headers->set('Content-Length', $end - $start + 1);
271 }
272 }
273 }
274 }
275 }
276
277 return $this;
278 }
279
280 private function hasValidIfRangeHeader($header)
281 {
282 if ($this->getEtag() === $header) {
283 return true;
284 }
285
286 if (null === $lastModified = $this->getLastModified()) {
287 return false;
288 }
289
290 return $lastModified->format('D, d M Y H:i:s').' GMT' === $header;
291 }
292
293 /**
294 * Sends the file.
295 *
296 * {@inheritdoc}
297 */
298 public function sendContent()
299 {
300 if (!$this->isSuccessful()) {
301 return parent::sendContent();
302 }
303
304 if (0 === $this->maxlen) {
305 return $this;
306 }
307
308 $out = fopen('php://output', 'wb');
309 $file = fopen($this->file->getPathname(), 'rb');
310
311 stream_copy_to_stream($file, $out, $this->maxlen, $this->offset);
312
313 fclose($out);
314 fclose($file);
315
316 if ($this->deleteFileAfterSend && file_exists($this->file->getPathname())) {
317 unlink($this->file->getPathname());
318 }
319
320 return $this;
321 }
322
323 /**
324 * {@inheritdoc}
325 *
326 * @throws \LogicException when the content is not null
327 */
328 public function setContent($content)
329 {
330 if (null !== $content) {
331 throw new \LogicException('The content cannot be set on a BinaryFileResponse instance.');
332 }
333
334 return $this;
335 }
336
337 /**
338 * {@inheritdoc}
339 */
340 public function getContent()
341 {
342 return false;
343 }
344
345 /**
346 * Trust X-Sendfile-Type header.
347 */
348 public static function trustXSendfileTypeHeader()
349 {
350 self::$trustXSendfileTypeHeader = true;
351 }
352
353 /**
354 * If this is set to true, the file will be unlinked after the request is sent
355 * Note: If the X-Sendfile header is used, the deleteFileAfterSend setting will not be used.
356 *
357 * @param bool $shouldDelete
358 *
359 * @return $this
360 */
361 public function deleteFileAfterSend($shouldDelete)
362 {
363 $this->deleteFileAfterSend = $shouldDelete;
364
365 return $this;
366 }
367 }
368