adjusted phpstan linting to be friendlier and changed download() to also specify file name

pull/663/head
n0nag0n 2 weeks ago
parent f0dc1b1adf
commit 053227b3b0

@ -24,60 +24,58 @@ use Psr\Container\ContainerInterface;
* It is responsible for loading an HTTP request, running the assigned services,
* and generating an HTTP response.
*
* @license MIT, http://flightphp.com/license
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @license MIT, https://docs.flightphp.com/license
* @copyright Copyright (c) 2011-2025, Mike Cao <mike@mikecao.com>, n0nag0n <n0nag0n@sky-9.com>
*
* # Core methods
* @method void start() Starts engine
* @method void stop() Stops framework and outputs current response
* @method void halt(int $code = 200, string $message = '', bool $actuallyExit = true) Stops processing and returns a given response.
* @method void start()
* @method void stop()
* @method void halt(int $code = 200, string $message = '', bool $actuallyExit = true)
* @method EventDispatcher eventDispatcher()
* @method Route route(string $pattern, callable|string|array $callback, bool $pass_route = false, string $alias = '')
* @method void group(string $pattern, callable $callback, array $group_middlewares = [])
* @method Route post(string $pattern, callable|string|array $callback, bool $pass_route = false, string $alias = '')
* @method Route put(string $pattern, callable|string|array $callback, bool $pass_route = false, string $alias = '')
* @method Route patch(string $pattern, callable|string|array $callback, bool $pass_route = false, string $alias = '')
* @method Route delete(string $pattern, callable|string|array $callback, bool $pass_route = false, string $alias = '')
* @method void resource(string $pattern, string $controllerClass, array $methods = [])
* @method Router router()
* @method string getUrl(string $alias)
* @method void render(string $file, array $data = null, string $key = null)
* @method View view()
* @method void onEvent(string $event, callable $callback)
* @method void triggerEvent(string $event, ...$args)
* @method Request request()
* @method Response response()
* @method void error(Throwable $e)
* @method void notFound()
* @method void redirect(string $url, int $code = 303)
* @method void json($data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0)
* @method void jsonHalt($data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0)
* @method void jsonp($data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0)
* @method void etag(string $id, string $type = 'strong')
* @method void lastModified(int $time)
* @method void download(string $filePath)
*
* # Class registration
* @method EventDispatcher eventDispatcher() Gets event dispatcher
* @phpstan-template EngineTemplate of object
* @phpstan-method void registerContainerHandler(ContainerInterface|callable(class-string<EngineTemplate> $id, array<int|string, mixed> $params): ?EngineTemplate $containerHandler)
* @phpstan-method Route route(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* @phpstan-method void group(string $pattern, callable $callback, (class-string|callable|array{0: class-string, 1: string})[] $group_middlewares = [])
* @phpstan-method Route post(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* @phpstan-method Route put(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* @phpstan-method Route patch(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* @phpstan-method Route delete(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* @phpstan-method void resource(string $pattern, class-string $controllerClass, array<string, string|array<string>> $methods = [])
* @phpstan-method string getUrl(string $alias, array<string, mixed> $params = [])
* @phpstan-method void before(string $name, Closure(array<int, mixed> &$params, string &$output): (void|false) $callback)
* @phpstan-method void after(string $name, Closure(array<int, mixed> &$params, string &$output): (void|false) $callback)
* @phpstan-method void set(string|iterable<string, mixed> $key, ?mixed $value = null)
* @phpstan-method mixed get(?string $key)
* @phpstan-method void render(string $file, ?array<string, mixed> $data = null, ?string $key = null)
* @phpstan-method void json(mixed $data, int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512)
* @phpstan-method void jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0)
* @phpstan-method void jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512)
*
* # Routing
* @method Route route(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* Routes a URL to a callback function with all applicable methods
* @method void group(string $pattern, callable $callback, (class-string|callable|array{0: class-string, 1: string})[] $group_middlewares = [])
* Groups a set of routes together under a common prefix.
* @method Route post(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* Routes a POST URL to a callback function.
* @method Route put(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* Routes a PUT URL to a callback function.
* @method Route patch(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* Routes a PATCH URL to a callback function.
* @method Route delete(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* Routes a DELETE URL to a callback function.
* @method void resource(string $pattern, class-string $controllerClass, array<string, string|array<string>> $methods = [])
* Adds standardized RESTful routes for a controller.
* @method Router router() Gets router
* @method string getUrl(string $alias) Gets a url from an alias
*
* # Views
* @method void render(string $file, ?array<string,mixed> $data = null, ?string $key = null) Renders template
* @method View view() Gets current view
*
* # Events
* @method void onEvent(string $event, callable $callback) Registers a callback for an event.
* @method void triggerEvent(string $event, ...$args) Triggers an event.
*
* # Request-Response
* @method Request request() Gets current request
* @method Response response() Gets current response
* @method void error(Throwable $e) Sends an HTTP 500 response for any errors.
* @method void notFound() Sends an HTTP 404 response when a URL is not found.
* @method void redirect(string $url, int $code = 303) Redirects the current request to another URL.
* @method void json(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0)
* Sends a JSON response.
* @method void jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0)
* Sends a JSON response and immediately halts the request.
* @method void jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0)
* Sends a JSONP response.
*
* # HTTP methods
* @method void etag(string $id, ('strong'|'weak') $type = 'strong') Handles ETag HTTP caching.
* @method void lastModified(int $time) Handles last modified HTTP caching.
* @method void download(string $filePath) Downloads a file
* Note: IDEs will use standard @method tags for autocompletion, while PHPStan will use @phpstan-* tags for advanced type checking.
*
* phpcs:disable PSR2.Methods.MethodDeclaration.Underscore
*/
@ -118,7 +116,7 @@ class Engine
/** Class loader. */
protected Loader $loader;
/** Method and class dispatcher. */
/** @var Dispatcher<EngineTemplate> Method and class dispatcher. */
protected Dispatcher $dispatcher;
/** Event dispatcher. */
@ -370,7 +368,7 @@ class Engine
*
* @param string|iterable<string, mixed> $key
* Variable name as `string` or an iterable of `'varName' => $varValue`
* @param mixed $value Ignored if `$key` is an `iterable`
* @param ?mixed $value Ignored if `$key` is an `iterable`
*/
public function set($key, $value = null): void
{
@ -981,14 +979,15 @@ class Engine
* Downloads a file
*
* @param string $filePath The path to the file to download
* @param string $fileName The name the file should be downloaded as
*
* @throws Exception If the file cannot be found
*
* @return void
*/
public function _download(string $filePath): void
public function _download(string $filePath, string $fileName = ''): void
{
$this->response()->downloadFile($filePath);
$this->response()->downloadFile($filePath, $fileName);
}
/**
@ -1020,8 +1019,8 @@ class Engine
public function _lastModified(int $time): void
{
$this->response()->header('Last-Modified', gmdate('D, d M Y H:i:s \G\M\T', $time));
$request = $this->request();
$ifModifiedSince = $request->header('If-Modified-Since');
$request = $this->request();
$ifModifiedSince = $request->header('If-Modified-Since');
$hit = isset($ifModifiedSince) && strtotime($ifModifiedSince) === $time;
$this->triggerEvent('flight.cache.checked', 'lastModified', $hit, 0.0);

@ -16,90 +16,76 @@ require_once __DIR__ . '/autoload.php';
/**
* The Flight class is a static representation of the framework.
*
* @license MIT, http://flightphp.com/license
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @license MIT, https://docs.flightphp.com/license
* @copyright Copyright (c) 2011-2025, Mike Cao <mike@mikecao.com>, n0nag0n <n0nag0n@sky-9.com>
*
* @template T of object
*
* # Core methods
* @method static void start() Starts the framework.
* @method static void path(string $dir) Adds a path for autoloading classes.
* @method static void stop(?int $code = null) Stops the framework and sends a response.
* @method static void start()
* @method static void path(string $dir)
* @method static void stop(int $code = null)
* @method static void halt(int $code = 200, string $message = '', bool $actuallyExit = true)
* Stop the framework with an optional status code and message.
* @method static void register(string $name, string $class, array<int, mixed> $params = [], ?callable $callback = null)
* Registers a class to a framework method.
* @method static void register(string $name, string $class, array $params = [], callable $callback = null)
* @method static void unregister(string $methodName)
* Unregisters a class to a framework method.
* @method static void registerContainerHandler(ContainerInterface|callable(class-string<T> $id, array<int|string, mixed> $params): ?T $containerHandler) Registers a container handler.
*
* # Class registration
* @method EventDispatcher eventDispatcher() Gets event dispatcher
*
* # Class registration
* @method EventDispatcher eventDispatcher() Gets event dispatcher
*
* # Routing
* @method static Route route(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* Maps a URL pattern to a callback with all applicable methods.
* @method static void group(string $pattern, callable $callback, (class-string|callable|array{0: class-string, 1: string})[] $group_middlewares = [])
* Groups a set of routes together under a common prefix.
* @method static Route post(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* Routes a POST URL to a callback function.
* @method static Route put(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* Routes a PUT URL to a callback function.
* @method static Route patch(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* Routes a PATCH URL to a callback function.
* @method static Route delete(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* Routes a DELETE URL to a callback function.
* @method static void resource(string $pattern, class-string $controllerClass, array<string, string|array<string>> $methods = [])
* Adds standardized RESTful routes for a controller.
* @method static Router router() Returns Router instance.
* @method static string getUrl(string $alias, array<string, mixed> $params = []) Gets a url from an alias
* @method static void map(string $name, callable $callback) Creates a custom framework method.
*
* # Filters
* @method static void before(string $name, Closure(array<int, mixed> &$params, string &$output): (void|false) $callback)
* Adds a filter before a framework method.
* @method static void after(string $name, Closure(array<int, mixed> &$params, string &$output): (void|false) $callback)
* Adds a filter after a framework method.
* @method static void registerContainerHandler($containerHandler)
* @method static EventDispatcher eventDispatcher()
* @method static Route route(string $pattern, callable $callback, bool $pass_route = false, string $alias = '')
* @method static void group(string $pattern, callable $callback, array $group_middlewares = [])
* @method static Route post(string $pattern, callable $callback, bool $pass_route = false, string $alias = '')
* @method static Route put(string $pattern, callable $callback, bool $pass_route = false, string $alias = '')
* @method static Route patch(string $pattern, callable $callback, bool $pass_route = false, string $alias = '')
* @method static Route delete(string $pattern, callable $callback, bool $pass_route = false, string $alias = '')
* @method static void resource(string $pattern, string $controllerClass, array $methods = [])
* @method static Router router()
* @method static string getUrl(string $alias, array $params = [])
* @method static void map(string $name, callable $callback)
* @method static void before(string $name, Closure $callback)
* @method static void after(string $name, Closure $callback)
* @method static void set($key, $value)
* @method static mixed get($key = null)
* @method static bool has(string $key)
* @method static void clear($key = null)
* @method static void render(string $file, array $data = null, string $key = null)
* @method static View view()
* @method void onEvent(string $event, callable $callback)
* @method void triggerEvent(string $event, ...$args)
* @method static Request request()
* @method static Response response()
* @method static void redirect(string $url, int $code = 303)
* @method static void json($data, int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512)
* @method static void jsonHalt($data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0)
* @method static void jsonp($data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512)
* @method static void error(Throwable $exception)
* @method static void notFound()
* @method static void etag(string $id, string $type = 'strong')
* @method static void lastModified(int $time)
* @method static void download(string $filePath)
*
* # Variables
* @method static void set(string|iterable<string, mixed> $key, mixed $value) Sets a variable.
* @method static mixed get(?string $key) Gets a variable.
* @method static bool has(string $key) Checks if a variable is set.
* @method static void clear(?string $key = null) Clears a variable.
* @phpstan-template FlightTemplate of object
* @phpstan-method static void register(string $name, class-string<FlightTemplate> $class, array<int|string, mixed> $params = [], (callable(class-string<FlightTemplate> $class, array<int|string, mixed> $params): void)|null $callback = null)
* @phpstan-method static void registerContainerHandler(ContainerInterface|callable(class-string<FlightTemplate> $id, array<int|string, mixed> $params): ?FlightTemplate $containerHandler)
* @phpstan-method static Route route(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* @phpstan-method static void group(string $pattern, callable $callback, (class-string|callable|array{0: class-string, 1: string})[] $group_middlewares = [])
* @phpstan-method static Route post(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* @phpstan-method static Route put(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* @phpstan-method static Route patch(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* @phpstan-method static Route delete(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '')
* @phpstan-method static void resource(string $pattern, class-string $controllerClass, array<string, string|array<string>> $methods = [])
* @phpstan-method static string getUrl(string $alias, array<string, mixed> $params = [])
* @phpstan-method static void before(string $name, Closure(array<int, mixed> &$params, string &$output): (void|false) $callback)
* @phpstan-method static void after(string $name, Closure(array<int, mixed> &$params, string &$output): (void|false) $callback)
* @phpstan-method static void set(string|iterable<string, mixed> $key, mixed $value)
* @phpstan-method static mixed get(?string $key)
* @phpstan-method static void render(string $file, ?array<string, mixed> $data = null, ?string $key = null)
* @phpstan-method static void json(mixed $data, int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512)
* @phpstan-method static void jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0)
* @phpstan-method static void jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512)
*
* # Views
* @method static void render(string $file, ?array<string, mixed> $data = null, ?string $key = null)
* Renders a template file.
* @method static View view() Returns View instance.
*
* # Events
* @method void onEvent(string $event, callable $callback) Registers a callback for an event.
* @method void triggerEvent(string $event, ...$args) Triggers an event.
*
* # Request-Response
* @method static Request request() Returns Request instance.
* @method static Response response() Returns Response instance.
* @method static void redirect(string $url, int $code = 303) Redirects to another URL.
* @method static void json(mixed $data, int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512)
* Sends a JSON response.
* @method static void jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0)
* Sends a JSON response and immediately halts the request.
* @method static void jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512)
* Sends a JSONP response.
* @method static void error(Throwable $exception) Sends an HTTP 500 response.
* @method static void notFound() Sends an HTTP 404 response.
*
* # HTTP methods
* @method static void etag(string $id, ('strong'|'weak') $type = 'strong') Performs ETag HTTP caching.
* @method static void lastModified(int $time) Performs last modified HTTP caching.
* @method static void download(string $filePath) Downloads a file
* Note: IDEs will use standard @method tags for autocompletion, while PHPStan will use @phpstan-* tags for advanced type checking.
*/
class Flight
{
/** Framework engine. */
/**
* @var Engine<FlightTemplate>
*/
private static Engine $engine;
/**
@ -138,7 +124,7 @@ class Flight
return self::app()->{$name}(...$params);
}
/** @return Engine Application instance */
/** @return Engine<FlightTemplate> Application instance */
public static function app(): Engine
{
return self::$engine ?? self::$engine = new Engine();
@ -147,7 +133,7 @@ class Flight
/**
* Set the engine instance
*
* @param Engine $engine Vroom vroom!
* @param Engine<FlightTemplate> $engine Vroom vroom!
*/
public static function setEngine(Engine $engine): void
{

@ -20,6 +20,7 @@ use TypeError;
*
* @license MIT, http://flightphp.com/license
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @phpstan-template EngineTemplate of object
*/
class Dispatcher
{
@ -29,7 +30,7 @@ class Dispatcher
/** Exception message if thrown by setting the container as a callable method. */
protected ?Throwable $containerException = null;
/** @var ?Engine $engine Engine instance. */
/** @var ?Engine<EngineTemplate> $engine Engine instance. */
protected ?Engine $engine = null;
/** @var array<string, callable(): (void|mixed)> Mapped events. */
@ -77,6 +78,13 @@ class Dispatcher
);
}
/**
* Sets the engine instance
*
* @param Engine<EngineTemplate> $engine Flight instance
*
* @return void
*/
public function setEngine(Engine $engine): void
{
$this->engine = $engine;
@ -88,8 +96,9 @@ class Dispatcher
* @param string $name Event name.
* @param array<int, mixed> $params Callback parameters.
*
* @return mixed Output of callback
* @throws Exception If event name isn't found or if event throws an `Exception`.
*
* @return mixed Output of callback
*/
public function run(string $name, array $params = [])
{
@ -102,8 +111,9 @@ class Dispatcher
/**
* @param array<int, mixed> &$params
*
* @return $this
* @throws Exception
*
* @return $this
*/
protected function runPreFilters(string $eventName, array &$params): self
{

@ -100,9 +100,9 @@ class PdoWrapper extends PDO
* @param string $sql - Ex: "SELECT * FROM table WHERE something = ?"
* @param array<int|string,mixed> $params - Ex: [ $something ]
*
* @return Collection
* @return Collection|array<mixed,mixed>
*/
public function fetchRow(string $sql, array $params = []): Collection
public function fetchRow(string $sql, array $params = [])
{
$sql .= stripos($sql, 'LIMIT') === false ? ' LIMIT 1' : '';
$result = $this->fetchAll($sql, $params);
@ -120,7 +120,7 @@ class PdoWrapper extends PDO
* @param string $sql - Ex: "SELECT * FROM table WHERE something = ?"
* @param array<int|string,mixed> $params - Ex: [ $something ]
*
* @return array<int,Collection>
* @return array<int,Collection|array<string,mixed>>
*/
public function fetchAll(string $sql, array $params = [])
{

@ -156,16 +156,16 @@ class Request
{
// Default properties
if (empty($config) === true) {
$scheme = $this->getScheme();
$url = $this->getVar('REQUEST_URI', '/');
if (strpos($url, '@') !== false) {
$url = str_replace('@', '%40', $url);
}
$base = $this->getVar('SCRIPT_NAME', '');
if (strpos($base, ' ') !== false || strpos($base, '\\') !== false) {
$base = str_replace(['\\', ' '], ['/', '%20'], $base);
}
$base = dirname($base);
$scheme = $this->getScheme();
$url = $this->getVar('REQUEST_URI', '/');
if (strpos($url, '@') !== false) {
$url = str_replace('@', '%40', $url);
}
$base = $this->getVar('SCRIPT_NAME', '');
if (strpos($base, ' ') !== false || strpos($base, '\\') !== false) {
$base = str_replace(['\\', ' '], ['/', '%20'], $base);
}
$base = dirname($base);
$config = [
'url' => $url,
'base' => $base,
@ -261,9 +261,9 @@ class Request
$method = $this->method ?? $this->getMethod();
if (in_array($method, ['POST', 'PUT', 'DELETE', 'PATCH'], true) === true) {
$body = file_get_contents($this->stream_path);
}
if (in_array($method, ['POST', 'PUT', 'DELETE', 'PATCH'], true) === true) {
$body = file_get_contents($this->stream_path);
}
$this->body = $body;
@ -305,7 +305,7 @@ class Request
$flags = \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE;
foreach ($forwarded as $key) {
$serverVar = self::getVar($key);
$serverVar = self::getVar($key);
if ($serverVar !== '') {
sscanf($serverVar, '%[^,]', $ip);
if (filter_var($ip, \FILTER_VALIDATE_IP, $flags) !== false) {
@ -414,17 +414,17 @@ class Request
*/
public static function parseQuery(string $url): array
{
$queryPos = strpos($url, '?');
if ($queryPos === false) {
return [];
}
$query = substr($url, $queryPos + 1);
if ($query === '') {
return [];
}
$params = [];
parse_str($query, $params);
return $params;
$queryPos = strpos($url, '?');
if ($queryPos === false) {
return [];
}
$query = substr($url, $queryPos + 1);
if ($query === '') {
return [];
}
$params = [];
parse_str($query, $params);
return $params;
}
/**

@ -324,7 +324,7 @@ class Response
);
// @codeCoverageIgnoreEnd
} else {
$serverProtocol = Request::getVar('SERVER_PROTOCOL') ?: 'HTTP/1.1';
$serverProtocol = Request::getVar('SERVER_PROTOCOL') ?: 'HTTP/1.1';
$this->setRealHeader(
sprintf(
'%s %d %s',
@ -484,10 +484,13 @@ class Response
* Downloads a file.
*
* @param string $filePath The path to the file to be downloaded.
* @param string $fileName The name the downloaded file should have. If not provided, the name of the file on disk will be used.
*
* @throws Exception If the file cannot be found.
*
* @return void
*/
public function downloadFile(string $filePath): void
public function downloadFile(string $filePath, string $fileName = ''): void
{
if (file_exists($filePath) === false) {
throw new Exception("$filePath cannot be found.");
@ -498,10 +501,14 @@ class Response
$mimeType = mime_content_type($filePath);
$mimeType = $mimeType !== false ? $mimeType : 'application/octet-stream';
if ($fileName === '') {
$fileName = basename($filePath);
}
$this->send();
$this->setRealHeader('Content-Description: File Transfer');
$this->setRealHeader('Content-Type: ' . $mimeType);
$this->setRealHeader('Content-Disposition: attachment; filename="' . basename($filePath) . '"');
$this->setRealHeader('Content-Disposition: attachment; filename="' . $fileName . '"');
$this->setRealHeader('Expires: 0');
$this->setRealHeader('Cache-Control: must-revalidate');
$this->setRealHeader('Pragma: public');

Loading…
Cancel
Save