Files
usher-manage-stack/app/Support/DownloadFile.php

72 lines
2.2 KiB
PHP

<?php
namespace App\Support;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;
class DownloadFile
{
/**
* Create a download response with UTF-8 filename support.
*/
public static function fromDisk(
string $disk,
string $path,
string $downloadName,
array $headers = []
): Response {
$safeName = static::asciiFallbackFilename($downloadName);
$response = Storage::disk($disk)->download($path, $safeName, $headers);
$response->headers->set('Content-Disposition', static::contentDisposition($downloadName));
return $response;
}
/**
* Build RFC 5987 compatible Content-Disposition value.
*/
public static function contentDisposition(
string $downloadName,
string $type = 'attachment'
): string {
$safeOriginalName = static::sanitizeHeaderFilename($downloadName);
$safeFallback = addcslashes(static::asciiFallbackFilename($safeOriginalName), "\"\\");
$encoded = rawurlencode($safeOriginalName);
return "{$type}; filename=\"{$safeFallback}\"; filename*=UTF-8''{$encoded}";
}
/**
* Generate ASCII fallback filename for old clients.
*/
public static function asciiFallbackFilename(string $filename): string
{
$filename = static::sanitizeHeaderFilename($filename);
$extension = pathinfo($filename, PATHINFO_EXTENSION);
$basename = pathinfo($filename, PATHINFO_FILENAME);
$asciiBase = Str::ascii($basename);
$asciiBase = preg_replace('/[^A-Za-z0-9._-]+/', '_', (string) $asciiBase);
$asciiBase = trim((string) $asciiBase, '._-');
if ($asciiBase === '') {
$asciiBase = 'download';
}
$asciiExtension = Str::ascii((string) $extension);
$asciiExtension = preg_replace('/[^A-Za-z0-9]+/', '', (string) $asciiExtension);
return $asciiExtension === ''
? $asciiBase
: "{$asciiBase}.{$asciiExtension}";
}
private static function sanitizeHeaderFilename(string $filename): string
{
$filename = str_replace(["\r", "\n"], '', trim($filename));
return $filename !== '' ? $filename : 'download';
}
}