Updates to vendors etc

This commit is contained in:
Chris Hunt
2025-07-11 15:57:48 +01:00
parent d972cbcd0a
commit 8fb6438254
8043 changed files with 248005 additions and 189479 deletions

View File

@@ -25,16 +25,14 @@ use Symfony\Component\HttpFoundation\File\File;
*/
class BinaryFileResponse extends Response
{
protected static $trustXSendfileTypeHeader = false;
protected static bool $trustXSendfileTypeHeader = false;
/**
* @var File
*/
protected $file;
protected $offset = 0;
protected $maxlen = -1;
protected $deleteFileAfterSend = false;
protected $chunkSize = 16 * 1024;
protected File $file;
protected ?\SplTempFileObject $tempFileObject = null;
protected int $offset = 0;
protected int $maxlen = -1;
protected bool $deleteFileAfterSend = false;
protected int $chunkSize = 16 * 1024;
/**
* @param \SplFileInfo|string $file The file to stream
@@ -65,15 +63,18 @@ class BinaryFileResponse extends Response
*/
public function setFile(\SplFileInfo|string $file, ?string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true): static
{
$isTemporaryFile = $file instanceof \SplTempFileObject;
$this->tempFileObject = $isTemporaryFile ? $file : null;
if (!$file instanceof File) {
if ($file instanceof \SplFileInfo) {
$file = new File($file->getPathname());
$file = new File($file->getPathname(), !$isTemporaryFile);
} else {
$file = new File((string) $file);
$file = new File($file);
}
}
if (!$file->isReadable()) {
if (!$file->isReadable() && !$isTemporaryFile) {
throw new FileException('File must be readable.');
}
@@ -83,7 +84,7 @@ class BinaryFileResponse extends Response
$this->setAutoEtag();
}
if ($autoLastModified) {
if ($autoLastModified && !$isTemporaryFile) {
$this->setAutoLastModified();
}
@@ -109,8 +110,8 @@ class BinaryFileResponse extends Response
*/
public function setChunkSize(int $chunkSize): static
{
if ($chunkSize < 1 || $chunkSize > \PHP_INT_MAX) {
throw new \LogicException('The chunk size of a BinaryFileResponse cannot be less than 1 or greater than PHP_INT_MAX.');
if ($chunkSize < 1) {
throw new \InvalidArgumentException('The chunk size of a BinaryFileResponse cannot be less than 1.');
}
$this->chunkSize = $chunkSize;
@@ -125,7 +126,7 @@ class BinaryFileResponse extends Response
*/
public function setAutoLastModified(): static
{
$this->setLastModified(\DateTimeImmutable::createFromFormat('U', $this->file->getMTime()));
$this->setLastModified(\DateTimeImmutable::createFromFormat('U', $this->tempFileObject ? time() : $this->file->getMTime()));
return $this;
}
@@ -137,7 +138,7 @@ class BinaryFileResponse extends Response
*/
public function setAutoEtag(): static
{
$this->setEtag(base64_encode(hash_file('sha256', $this->file->getPathname(), true)));
$this->setEtag(base64_encode(hash_file('xxh128', $this->file->getPathname(), true)));
return $this;
}
@@ -188,7 +189,12 @@ class BinaryFileResponse extends Response
}
if (!$this->headers->has('Content-Type')) {
$this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
$mimeType = null;
if (!$this->tempFileObject) {
$mimeType = $this->file->getMimeType();
}
$this->headers->set('Content-Type', $mimeType ?: 'application/octet-stream');
}
parent::prepare($request);
@@ -196,7 +202,9 @@ class BinaryFileResponse extends Response
$this->offset = 0;
$this->maxlen = -1;
if (false === $fileSize = $this->file->getSize()) {
if ($this->tempFileObject) {
$fileSize = $this->tempFileObject->fstat()['size'];
} elseif (false === $fileSize = $this->file->getSize()) {
return $this;
}
$this->headers->remove('Transfer-Encoding');
@@ -217,15 +225,19 @@ class BinaryFileResponse extends Response
}
if ('x-accel-redirect' === strtolower($type)) {
// Do X-Accel-Mapping substitutions.
// @link https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/#x-accel-redirect
$parts = HeaderUtils::split($request->headers->get('X-Accel-Mapping', ''), ',=');
// @link https://github.com/rack/rack/blob/main/lib/rack/sendfile.rb
// @link https://mattbrictson.com/blog/accelerated-rails-downloads
if (!$request->headers->has('X-Accel-Mapping')) {
throw new \LogicException('The "X-Accel-Mapping" header must be set when "X-Sendfile-Type" is set to "X-Accel-Redirect".');
}
$parts = HeaderUtils::split($request->headers->get('X-Accel-Mapping'), ',=');
foreach ($parts as $part) {
[$pathPrefix, $location] = $part;
if (str_starts_with($path, $pathPrefix)) {
$path = $location.substr($path, \strlen($pathPrefix));
// Only set X-Accel-Redirect header if a valid URI can be produced
// as nginx does not serve arbitrary file paths.
$this->headers->set($type, $path);
$this->headers->set($type, rawurlencode($path));
$this->maxlen = 0;
break;
}
@@ -255,13 +267,13 @@ class BinaryFileResponse extends Response
$end = min($end, $fileSize - 1);
if ($start < 0 || $start > $end) {
$this->setStatusCode(416);
$this->headers->set('Content-Range', sprintf('bytes */%s', $fileSize));
$this->headers->set('Content-Range', \sprintf('bytes */%s', $fileSize));
} elseif ($end - $start < $fileSize - 1) {
$this->maxlen = $end < $fileSize ? $end - $start + 1 : -1;
$this->offset = $start;
$this->setStatusCode(206);
$this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize));
$this->headers->set('Content-Range', \sprintf('bytes %s-%s/%s', $start, $end, $fileSize));
$this->headers->set('Content-Length', $end - $start + 1);
}
}
@@ -301,19 +313,25 @@ class BinaryFileResponse extends Response
}
$out = fopen('php://output', 'w');
$file = fopen($this->file->getPathname(), 'r');
if ($this->tempFileObject) {
$file = $this->tempFileObject;
$file->rewind();
} else {
$file = new \SplFileObject($this->file->getPathname(), 'r');
}
ignore_user_abort(true);
if (0 !== $this->offset) {
fseek($file, $this->offset);
$file->fseek($this->offset);
}
$length = $this->maxlen;
while ($length && !feof($file)) {
while ($length && !$file->eof()) {
$read = $length > $this->chunkSize || 0 > $length ? $this->chunkSize : $length;
if (false === $data = fread($file, $read)) {
if (false === $data = $file->fread($read)) {
break;
}
while ('' !== $data) {
@@ -329,9 +347,8 @@ class BinaryFileResponse extends Response
}
fclose($out);
fclose($file);
} finally {
if ($this->deleteFileAfterSend && is_file($this->file->getPathname())) {
if (null === $this->tempFileObject && $this->deleteFileAfterSend && is_file($this->file->getPathname())) {
unlink($this->file->getPathname());
}
}
@@ -358,10 +375,8 @@ class BinaryFileResponse extends Response
/**
* Trust X-Sendfile-Type header.
*
* @return void
*/
public static function trustXSendfileTypeHeader()
public static function trustXSendfileTypeHeader(): void
{
self::$trustXSendfileTypeHeader = true;
}