[ Index ] |
PHP Cross Reference of phpBB-3.1.12-deutsch |
[Summary view] [Print] [Text view]
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\File; 15 use Symfony\Component\HttpFoundation\File\Exception\FileException; 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; 35 protected $maxlen; 36 37 /** 38 * Constructor. 39 * 40 * @param \SplFileInfo|string $file The file to stream 41 * @param int $status The response status code 42 * @param array $headers An array of response headers 43 * @param bool $public Files are public by default 44 * @param null|string $contentDisposition The type of Content-Disposition to set automatically with the filename 45 * @param bool $autoEtag Whether the ETag header should be automatically set 46 * @param bool $autoLastModified Whether the Last-Modified header should be automatically set 47 */ 48 public function __construct($file, $status = 200, $headers = array(), $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true) 49 { 50 parent::__construct(null, $status, $headers); 51 52 $this->setFile($file, $contentDisposition, $autoEtag, $autoLastModified); 53 54 if ($public) { 55 $this->setPublic(); 56 } 57 } 58 59 /** 60 * @param \SplFileInfo|string $file The file to stream 61 * @param int $status The response status code 62 * @param array $headers An array of response headers 63 * @param bool $public Files are public by default 64 * @param null|string $contentDisposition The type of Content-Disposition to set automatically with the filename 65 * @param bool $autoEtag Whether the ETag header should be automatically set 66 * @param bool $autoLastModified Whether the Last-Modified header should be automatically set 67 * 68 * @return BinaryFileResponse The created response 69 */ 70 public static function create($file = null, $status = 200, $headers = array(), $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true) 71 { 72 return new static($file, $status, $headers, $public, $contentDisposition, $autoEtag, $autoLastModified); 73 } 74 75 /** 76 * Sets the file to stream. 77 * 78 * @param \SplFileInfo|string $file The file to stream 79 * @param string $contentDisposition 80 * @param bool $autoEtag 81 * @param bool $autoLastModified 82 * 83 * @return BinaryFileResponse 84 * 85 * @throws FileException 86 */ 87 public function setFile($file, $contentDisposition = null, $autoEtag = false, $autoLastModified = true) 88 { 89 if (!$file instanceof File) { 90 if ($file instanceof \SplFileInfo) { 91 $file = new File($file->getPathname()); 92 } else { 93 $file = new File((string) $file); 94 } 95 } 96 97 if (!$file->isReadable()) { 98 throw new FileException('File must be readable.'); 99 } 100 101 $this->file = $file; 102 103 if ($autoEtag) { 104 $this->setAutoEtag(); 105 } 106 107 if ($autoLastModified) { 108 $this->setAutoLastModified(); 109 } 110 111 if ($contentDisposition) { 112 $this->setContentDisposition($contentDisposition); 113 } 114 115 return $this; 116 } 117 118 /** 119 * Gets the file. 120 * 121 * @return File The file to stream 122 */ 123 public function getFile() 124 { 125 return $this->file; 126 } 127 128 /** 129 * Automatically sets the Last-Modified header according the file modification date. 130 */ 131 public function setAutoLastModified() 132 { 133 $this->setLastModified(\DateTime::createFromFormat('U', $this->file->getMTime())); 134 135 return $this; 136 } 137 138 /** 139 * Automatically sets the ETag header according to the checksum of the file. 140 */ 141 public function setAutoEtag() 142 { 143 $this->setEtag(sha1_file($this->file->getPathname())); 144 145 return $this; 146 } 147 148 /** 149 * Sets the Content-Disposition header with the given filename. 150 * 151 * @param string $disposition ResponseHeaderBag::DISPOSITION_INLINE or ResponseHeaderBag::DISPOSITION_ATTACHMENT 152 * @param string $filename Optionally use this filename instead of the real name of the file 153 * @param string $filenameFallback A fallback filename, containing only ASCII characters. Defaults to an automatically encoded filename 154 * 155 * @return BinaryFileResponse 156 */ 157 public function setContentDisposition($disposition, $filename = '', $filenameFallback = '') 158 { 159 if ($filename === '') { 160 $filename = $this->file->getFilename(); 161 } 162 163 if ('' === $filenameFallback && (!preg_match('/^[\x20-\x7e]*$/', $filename) || false !== strpos($filename, '%'))) { 164 $encoding = mb_detect_encoding($filename, null, true); 165 166 for ($i = 0; $i < mb_strlen($filename, $encoding); ++$i) { 167 $char = mb_substr($filename, $i, 1, $encoding); 168 169 if ('%' === $char || ord($char) < 32 || ord($char) > 126) { 170 $filenameFallback .= '_'; 171 } else { 172 $filenameFallback .= $char; 173 } 174 } 175 } 176 177 $dispositionHeader = $this->headers->makeDisposition($disposition, $filename, $filenameFallback); 178 $this->headers->set('Content-Disposition', $dispositionHeader); 179 180 return $this; 181 } 182 183 /** 184 * {@inheritdoc} 185 */ 186 public function prepare(Request $request) 187 { 188 $this->headers->set('Content-Length', $this->file->getSize()); 189 190 if (!$this->headers->has('Accept-Ranges')) { 191 // Only accept ranges on safe HTTP methods 192 $this->headers->set('Accept-Ranges', $request->isMethodSafe() ? 'bytes' : 'none'); 193 } 194 195 if (!$this->headers->has('Content-Type')) { 196 $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream'); 197 } 198 199 if ('HTTP/1.0' !== $request->server->get('SERVER_PROTOCOL')) { 200 $this->setProtocolVersion('1.1'); 201 } 202 203 $this->ensureIEOverSSLCompatibility($request); 204 205 $this->offset = 0; 206 $this->maxlen = -1; 207 208 if (self::$trustXSendfileTypeHeader && $request->headers->has('X-Sendfile-Type')) { 209 // Use X-Sendfile, do not send any content. 210 $type = $request->headers->get('X-Sendfile-Type'); 211 $path = $this->file->getRealPath(); 212 // Fall back to scheme://path for stream wrapped locations. 213 if (false === $path) { 214 $path = $this->file->getPathname(); 215 } 216 if (strtolower($type) === 'x-accel-redirect') { 217 // Do X-Accel-Mapping substitutions. 218 // @link http://wiki.nginx.org/X-accel#X-Accel-Redirect 219 foreach (explode(',', $request->headers->get('X-Accel-Mapping', '')) as $mapping) { 220 $mapping = explode('=', $mapping, 2); 221 222 if (2 === count($mapping)) { 223 $pathPrefix = trim($mapping[0]); 224 $location = trim($mapping[1]); 225 226 if (substr($path, 0, strlen($pathPrefix)) === $pathPrefix) { 227 $path = $location.substr($path, strlen($pathPrefix)); 228 break; 229 } 230 } 231 } 232 } 233 $this->headers->set($type, $path); 234 $this->maxlen = 0; 235 } elseif ($request->headers->has('Range')) { 236 // Process the range headers. 237 if (!$request->headers->has('If-Range') || $this->hasValidIfRangeHeader($request->headers->get('If-Range'))) { 238 $range = $request->headers->get('Range'); 239 $fileSize = $this->file->getSize(); 240 241 list($start, $end) = explode('-', substr($range, 6), 2) + array(0); 242 243 $end = ('' === $end) ? $fileSize - 1 : (int) $end; 244 245 if ('' === $start) { 246 $start = $fileSize - $end; 247 $end = $fileSize - 1; 248 } else { 249 $start = (int) $start; 250 } 251 252 if ($start <= $end) { 253 if ($start < 0 || $end > $fileSize - 1) { 254 $this->setStatusCode(416); 255 $this->headers->set('Content-Range', sprintf('bytes */%s', $fileSize)); 256 } elseif ($start !== 0 || $end !== $fileSize - 1) { 257 $this->maxlen = $end < $fileSize ? $end - $start + 1 : -1; 258 $this->offset = $start; 259 260 $this->setStatusCode(206); 261 $this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize)); 262 $this->headers->set('Content-Length', $end - $start + 1); 263 } 264 } 265 } 266 } 267 268 return $this; 269 } 270 271 private function hasValidIfRangeHeader($header) 272 { 273 if ($this->getEtag() === $header) { 274 return true; 275 } 276 277 if (null === $lastModified = $this->getLastModified()) { 278 return false; 279 } 280 281 return $lastModified->format('D, d M Y H:i:s').' GMT' === $header; 282 } 283 284 /** 285 * Sends the file. 286 * 287 * {@inheritdoc} 288 */ 289 public function sendContent() 290 { 291 if (!$this->isSuccessful()) { 292 return parent::sendContent(); 293 } 294 295 if (0 === $this->maxlen) { 296 return $this; 297 } 298 299 $out = fopen('php://output', 'wb'); 300 $file = fopen($this->file->getPathname(), 'rb'); 301 302 stream_copy_to_stream($file, $out, $this->maxlen, $this->offset); 303 304 fclose($out); 305 fclose($file); 306 307 return $this; 308 } 309 310 /** 311 * {@inheritdoc} 312 * 313 * @throws \LogicException when the content is not null 314 */ 315 public function setContent($content) 316 { 317 if (null !== $content) { 318 throw new \LogicException('The content cannot be set on a BinaryFileResponse instance.'); 319 } 320 } 321 322 /** 323 * {@inheritdoc} 324 * 325 * @return false 326 */ 327 public function getContent() 328 { 329 return false; 330 } 331 332 /** 333 * Trust X-Sendfile-Type header. 334 */ 335 public static function trustXSendfileTypeHeader() 336 { 337 self::$trustXSendfileTypeHeader = true; 338 } 339 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Jan 11 00:25:41 2018 | Cross-referenced by PHPXref 0.7.1 |