Merge branch 'master' into replace-table-with-chart-in-readme

pull/718/head
n0nag0n 1 day ago committed by GitHub
commit cb27287bbc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -16,11 +16,11 @@ This is the main FlightPHP core library for building fast, simple, and extensibl
- Run tests: `composer test` (uses phpunit/phpunit and spatie/phpunit-watcher)
- Run test server: `composer test-server` or `composer test-server-v2`
- Lint code & Check code style: `composer lint` (uses phpstan/phpstan, level 6)
- Beautify code: `composer format` (uses squizlabs/php_codesniffer, PSR1)
- Beautify code: `composer format` (uses squizlabs/php_codesniffer, PSR12)
- Test coverage: `composer test-coverage`
## Coding Standards
- Follow PSR1 coding standards (enforced by PHPCS)
- Follow PSR12 coding standards (enforced by PHPCS)
- Use strict comparisons (`===`, `!==`)
- PHPStan level 6 compliance
- Focus on PHP 7.4 compatibility (avoid PHP 8+ only features)

@ -16,11 +16,11 @@ This is the main FlightPHP core library for building fast, simple, and extensibl
- Run tests: `composer test` (uses phpunit/phpunit and spatie/phpunit-watcher)
- Run test server: `composer test-server` or `composer test-server-v2`
- Lint code & Check code style: `composer lint` (uses phpstan/phpstan, level 6)
- Beautify code: `composer format` (uses squizlabs/php_codesniffer, PSR1)
- Beautify code: `composer format` (uses squizlabs/php_codesniffer, PSR12)
- Test coverage: `composer test-coverage`
## Coding Standards
- Follow PSR1 coding standards (enforced by PHPCS)
- Follow PSR12 coding standards (enforced by PHPCS)
- Use strict comparisons (`===`, `!==`)
- PHPStan level 6 compliance
- Focus on PHP 7.4 compatibility (avoid PHP 8+ only features)

@ -16,11 +16,11 @@ This is the main FlightPHP core library for building fast, simple, and extensibl
- Run tests: `composer test` (uses phpunit/phpunit and spatie/phpunit-watcher)
- Run test server: `composer test-server` or `composer test-server-v2`
- Lint code & Check code style: `composer lint` (uses phpstan/phpstan, level 6)
- Beautify code: `composer format` (uses squizlabs/php_codesniffer, PSR1)
- Beautify code: `composer format` (uses squizlabs/php_codesniffer, PSR12)
- Test coverage: `composer test-coverage`
## Coding Standards
- Follow PSR1 coding standards (enforced by PHPCS)
- Follow PSR12 coding standards (enforced by PHPCS)
- Use strict comparisons (`===`, `!==`)
- PHPStan level 6 compliance
- Focus on PHP 7.4 compatibility (avoid PHP 8+ only features)

@ -9,19 +9,19 @@ Flight aims to be simple and fast. Anything that compromises either of those two
* **Dependencies** - We strive to be dependency free in Flight. Yes even polyfills, yes even `Interface` only repos like `psr/container`. The fewer dependencies, the fewer your exposed attack vectors.
* **Coding Standards** - We use PSR1 coding standards enforced by PHPCS. Some standards that either need additional configuration or need to be manually done are:
* **Coding Standards** - We use PSR-12 coding standards enforced by PHPCS. Some standards that either need additional configuration or need to be manually done are:
* PHPStan is at level 6.
* `===` instead of truthy or falsey statements like `==` or `!is_array()`.
* `===` instead of truthy or falsy statements like `==`.
* **PHP 7.4 Focused** - We do not make PHP 8+ focused enhancements on the framework as the focus is maintaining PHP 7.4.
* **Core functionality vs Plugin** - Have a conversation with us in the [chatroom](https://matrix.to/#/!cTfwPXhpkTXPXwVmxY:matrix.org?via=matrix.org&via=leitstelle511.net&via=integrations.ems.host) to know if your idea is worth makes sense in the framework or in a plugin.
* **Testing** - Until automated testing is put into place, any PRs must pass unit testing in PHP 7.4 and PHP 8.2+. Additionally you need to run `composer test-server` and `composer test-server-v2` and ensure all the header links work correctly.
* **Testing** - PRs must pass unit tests on PHP 7.4 through PHP 8.5+. Additionally you need to run `composer test-server` and `composer test-server-v2` and ensure all the header links work correctly.
#### **Did you find a bug?**
* **Do not open up a GitHub issue if the bug is a security vulnerability**. Instead contact maintainers directly via email to safely pass in the information related to the security vuln.
* **Do not open up a GitHub issue if the bug is a security vulnerability**. Instead contact maintainers directly via email to safely share details about the security vulnerability.
* **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/flightphp/core/issues).

@ -22,13 +22,10 @@ composer require flightphp/core
or you can download a zip of this repo. Then you would have a basic `index.php` file like the following:
```php
// if installed with composer
require 'vendor/autoload.php';
// or if installed manually by zip file
// require 'flight/Flight.php';
require 'flight/autoload.php';
Flight::route('/', function () {
echo 'hello world!';
echo 'hello world!';
});
Flight::start();
@ -38,7 +35,7 @@ Flight::start();
Yes! Flight is fast. It is one of the fastest PHP frameworks available. You can see all the benchmarks at [TechEmpower](https://www.techempower.com/benchmarks/#section=data-r18&hw=ph&test=frameworks)
See the benchmark below with some other popular PHP frameworks. This is measured in requests processed within the same timeframe.
See the benchmark below with some other popular PHP frameworks. This is measured in requests processed within the same timeframe.
```mermaid
---
@ -78,9 +75,10 @@ If you have a current project on v2, you should be able to upgrade to v3 with no
> [!IMPORTANT]
> Flight requires `PHP 7.4` or greater.
**Note:** PHP 7.4 is supported because at the current time of writing (2024) PHP 7.4 is the default version for some LTS Linux distributions. Forcing a move to PHP >8 would cause a lot of heartburn for those users.
The framework also supports PHP >8.
> [!NOTE]
> PHP 7.4 is supported because at the current time of writing (2024) PHP 7.4 is the default version for some LTS Linux distributions.
> Forcing a move to PHP 8 would cause a lot of heartburn for those users.
> The framework also supports PHP 8.
# Roadmap

@ -24,8 +24,7 @@ use Psr\Container\ContainerInterface;
* It is responsible for loading an HTTP request, running the assigned services,
* and generating an HTTP response.
*
* @license MIT, https://docs.flightphp.com/license
* @copyright Copyright (c) 2011-2025, Mike Cao <mike@mikecao.com>, n0nag0n <n0nag0n@sky-9.com>
* @copyright 2011-2026, Mike Cao https://mikecao.com, n0nag0n <n0nag0n@sky-9.com>
*
* @method void start()
* @method void stop()
@ -75,10 +74,7 @@ use Psr\Container\ContainerInterface;
* @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)
*
* 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
* @license https://docs.flightphp.com/license MIT
*/
class Engine
{
@ -227,8 +223,24 @@ class Engine
// which causes a lot of problems. This will be removed
// in v4
$self->response()->v2_output_buffering = $this->get('flight.v2.output_buffering');
// Propagate method override setting to Request
$self->request()::$allowMethodOverride = (bool) $self->get('flight.allow_method_override');
// Propagate method override setting to Request.
// Assign the static on the class first — do not call request() before this,
// or Request's constructor caches the method while the flag is still the default (true).
Request::$allowMethodOverride = (bool) $self->get('flight.allow_method_override');
// If a Request was already built earlier (common: apps touch request() before start)
// while override was still enabled, refresh the cached verb when override is off
// and an override input is present. When no override input exists, leave any
// intentional manual method assignment alone.
if (Request::$allowMethodOverride === false) {
$hasOverrideInput = Request::getVar('HTTP_X_HTTP_METHOD_OVERRIDE') !== ''
|| isset($_REQUEST['_method']);
if ($hasOverrideInput === true) {
$request = $self->request();
$request->method = Request::getMethod();
}
}
});
$this->initialized = true;

@ -15,7 +15,7 @@ use Psr\Container\ContainerInterface;
* The Flight class is a static representation of the framework.
*
* @license MIT, https://docs.flightphp.com/license
* @copyright Copyright (c) 2011-2025, Mike Cao <mike@mikecao.com>, n0nag0n <n0nag0n@sky-9.com>
* @copyright 2011-2026, Mike Cao https://mikecao.com, n0nag0n <n0nag0n@sky-9.com>
*
* @method static void start()
* @method static void path(string $dir)
@ -77,11 +77,8 @@ use Psr\Container\ContainerInterface;
* @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)
*
* Note: IDEs will use standard @method tags for autocompletion,
* while PHPStan will use @phpstan-* tags for advanced type checking.
* @license https://docs.flightphp.com/license MIT
*/
// phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace
class Flight
{
/**

@ -18,8 +18,8 @@ use TypeError;
* allows you to hook other functions to an event that can modify the
* input parameters and/or the output.
*
* @license MIT, http://flightphp.com/license
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @copyright 2011 Mike Cao https://mikecao.com
* @license https://docs.flightphp.com/license MIT
* @phpstan-template EngineTemplate of object
*/
class Dispatcher

@ -6,134 +6,83 @@ namespace flight\core;
class EventDispatcher
{
/** @var self|null Singleton instance of the EventDispatcher */
private static ?self $instance = null;
/** @var array<string, array<int, callable>> */
/** @var array<string, callable[]> */
protected array $listeners = [];
/**
* Singleton instance of the EventDispatcher.
*
* @return self
*/
public static function getInstance(): self
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Register a callback for an event.
*
* @param string $event Event name
* @param callable $callback Callback function
*/
public function on(string $event, callable $callback): void
{
if (isset($this->listeners[$event]) === false) {
$this->listeners[$event] = [];
}
$this->listeners[$event] ??= [];
$this->listeners[$event][] = $callback;
}
/**
* Trigger an event with optional arguments.
*
* @param string $event Event name
* @param mixed ...$args Arguments to pass to the callbacks
*
* @param mixed ...$args Arguments to pass to the listeners.
* @return mixed
*/
public function trigger(string $event, ...$args)
{
$result = null;
if (isset($this->listeners[$event]) === true) {
foreach ($this->listeners[$event] as $callback) {
$result = call_user_func_array($callback, $args);
// If you return false, it will break the loop and stop the other event listeners.
if ($result === false) {
break; // Stop executing further listeners
}
$listenerReturnValue = null;
foreach ($this->getListeners($event) as $listener) {
$listenerReturnValue = $listener(...$args);
if ($listenerReturnValue === false) {
break;
}
}
return $result;
return $listenerReturnValue;
}
/**
* Check if an event has any registered listeners.
*
* @param string $event Event name
*
* @return bool True if the event has listeners, false otherwise
*/
public function hasListeners(string $event): bool
{
return isset($this->listeners[$event]) === true && count($this->listeners[$event]) > 0;
return (
isset($this->listeners[$event])
&& is_array($this->listeners[$event])
&& count($this->listeners[$event])
);
}
/**
* Get all listeners registered for a specific event.
*
* @param string $event Event name
*
* @return array<int, callable> Array of callbacks registered for the event
*/
/** @return callable[] */
public function getListeners(string $event): array
{
return $this->listeners[$event] ?? [];
}
/**
* Get a list of all events that have registered listeners.
*
* @return array<int, string> Array of event names
*/
/** @return string[] */
public function getAllRegisteredEvents(): array
{
return array_keys($this->listeners);
}
/**
* Remove a specific listener for an event.
*
* @param string $event the event name
* @param callable $callback the exact callback to remove
*
* @return void
*/
public function removeListener(string $event, callable $callback): void
{
if (isset($this->listeners[$event]) === true && count($this->listeners[$event]) > 0) {
$this->listeners[$event] = array_filter($this->listeners[$event], function ($listener) use ($callback) {
return $listener !== $callback;
});
$this->listeners[$event] = array_values($this->listeners[$event]); // Re-index the array
if (!$this->hasListeners($event)) {
return;
}
$this->listeners[$event] = array_values(array_filter(
$this->getListeners($event),
static fn(callable $listener): bool => $listener !== $callback,
));
}
/**
* Remove all listeners for a specific event.
*
* @param string $event the event name
*
* @return void
*/
public function removeAllListeners(string $event): void
{
if (isset($this->listeners[$event]) === true) {
unset($this->listeners[$event]);
}
unset($this->listeners[$event]);
}
/**
* Remove the current singleton instance of the EventDispatcher.
*
* @return void
*/
public static function resetInstance(): void
{
self::$instance = null;

@ -13,8 +13,8 @@ use Exception;
* instances with custom initialization parameters. It also performs
* class autoloading.
*
* @license MIT, http://flightphp.com/license
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @copyright 2011 Mike Cao https://mikecao.com
* @license https://docs.flightphp.com/license MIT
*/
class Loader
{

@ -11,8 +11,8 @@ use flight\util\Collection;
* all the super globals $_GET, $_POST, $_COOKIE, and $_FILES
* are stored and accessible via the Request object.
*
* @license MIT, http://flightphp.com/license
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @copyright 2011 Mike Cao https://mikecao.com
* @license https://docs.flightphp.com/license MIT
*
* The default request properties are:
*

@ -12,8 +12,8 @@ use flight\core\EventDispatcher;
* contains the response headers, HTTP status code, and response
* body.
*
* @license MIT, http://flightphp.com/license
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @copyright 2011 Mike Cao https://mikecao.com
* @license https://docs.flightphp.com/license MIT
*/
class Response
{

@ -9,8 +9,8 @@ namespace flight\net;
* an assigned callback function. The Router tries to match the
* requested URL against a series of URL patterns.
*
* @license MIT, http://flightphp.com/license
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @copyright 2011 Mike Cao https://mikecao.com
* @license https://docs.flightphp.com/license MIT
*/
class Route
{

@ -12,8 +12,8 @@ use flight\net\Route;
* an assigned callback function. The Router tries to match the
* requested URL against a series of URL patterns.
*
* @license MIT, http://flightphp.com/license
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @copyright 2011 Mike Cao https://mikecao.com
* @license https://docs.flightphp.com/license MIT
*/
class Router
{

@ -9,8 +9,8 @@ namespace flight\template;
* methods for managing view data and inserts the data into
* view templates upon rendering.
*
* @license MIT, http://flightphp.com/license
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @copyright 2011 Mike Cao https://mikecao.com
* @license https://docs.flightphp.com/license MIT
*/
class View
{

@ -13,10 +13,10 @@ use JsonSerializable;
* The Collection class allows you to access a set of data
* using both array and object notation.
*
* @license MIT, http://flightphp.com/license
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @copyright 2011 Mike Cao https://mikecao.com
* @implements ArrayAccess<string, mixed>
* @implements Iterator<string, mixed>
* @license https://docs.flightphp.com/license MIT
*/
class Collection implements ArrayAccess, Iterator, Countable, JsonSerializable
{

@ -23,11 +23,18 @@ class EngineTest extends TestCase
public function setUp(): void
{
$_SERVER = [];
$_REQUEST = [];
$_GET = [];
$_POST = [];
// Static flag leaks across tests (and across Engine instances).
Request::$allowMethodOverride = true;
}
public function tearDown(): void
{
$_SERVER = [];
$_REQUEST = [];
Request::$allowMethodOverride = true;
}
public function testInitBeforeStart(): void
@ -1207,4 +1214,170 @@ class EngineTest extends TestCase
$this->expectExceptionMessage("/path/to/nowhere cannot be found.");
$engine->download('/path/to/nowhere');
}
/**
* Regression for GHSA method-override opt-out: setting the flag to false must
* prevent X-HTTP-Method-Override from selecting a different route.
*
* The original mitigation assigned Request::$allowMethodOverride via
* $self->request()::$allowMethodOverride, which built Request (and cached the
* overridden verb) before the static was set.
*/
public function testAllowMethodOverrideFalseBlocksHeaderOverrideOnStart(): void
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['REQUEST_URI'] = '/test';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'DELETE';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_SERVER['SERVER_NAME'] = 'localhost';
$_SERVER['HTTP_HOST'] = 'localhost';
$engine = new Engine();
$engine->set('flight.allow_method_override', false);
$hit = null;
$engine->route('GET /test', function () use (&$hit) {
$hit = 'get';
echo 'get';
});
$engine->route('DELETE /test', function () use (&$hit) {
$hit = 'delete';
echo 'delete';
});
$this->expectOutputString('get');
$engine->start();
$this->assertSame('get', $hit);
$this->assertFalse(Request::$allowMethodOverride);
$this->assertSame('GET', $engine->request()->method);
}
public function testAllowMethodOverrideFalseBlocksPostMethodFieldOnStart(): void
{
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REQUEST_URI'] = '/test';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_SERVER['SERVER_NAME'] = 'localhost';
$_SERVER['HTTP_HOST'] = 'localhost';
$_REQUEST['_method'] = 'PUT';
$engine = new Engine();
$engine->set('flight.allow_method_override', false);
$hit = null;
$engine->route('POST /test', function () use (&$hit) {
$hit = 'post';
echo 'post';
});
$engine->route('PUT /test', function () use (&$hit) {
$hit = 'put';
echo 'put';
});
$this->expectOutputString('post');
$engine->start();
$this->assertSame('post', $hit);
$this->assertSame('POST', $engine->request()->method);
}
public function testAllowMethodOverrideTrueStillHonorsHeaderOnStart(): void
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['REQUEST_URI'] = '/test';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'DELETE';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_SERVER['SERVER_NAME'] = 'localhost';
$_SERVER['HTTP_HOST'] = 'localhost';
$engine = new Engine();
// default is true; set explicitly for clarity
$engine->set('flight.allow_method_override', true);
$hit = null;
$engine->route('GET /test', function () use (&$hit) {
$hit = 'get';
echo 'get';
});
$engine->route('DELETE /test', function () use (&$hit) {
$hit = 'delete';
echo 'delete';
});
$this->expectOutputString('delete');
$engine->start();
$this->assertSame('delete', $hit);
$this->assertTrue(Request::$allowMethodOverride);
$this->assertSame('DELETE', $engine->request()->method);
}
/**
* App code often touches request() before start() (set url, inspect headers, etc.).
* The flag must still win even when Request was constructed early under the default.
*/
public function testAllowMethodOverrideFalseRefreshesMethodIfRequestBuiltEarly(): void
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['REQUEST_URI'] = '/test';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'DELETE';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_SERVER['SERVER_NAME'] = 'localhost';
$_SERVER['HTTP_HOST'] = 'localhost';
$engine = new Engine();
$engine->set('flight.allow_method_override', false);
// Construct Request while static is still the default (true)
$this->assertTrue(Request::$allowMethodOverride);
$early = $engine->request();
$this->assertSame('DELETE', $early->method, 'pre-start construction still sees default override=on');
$hit = null;
$engine->route('GET /test', function () use (&$hit) {
$hit = 'get';
echo 'get';
});
$engine->route('DELETE /test', function () use (&$hit) {
$hit = 'delete';
echo 'delete';
});
$this->expectOutputString('get');
$engine->start();
$this->assertSame('get', $hit);
$this->assertFalse(Request::$allowMethodOverride);
$this->assertSame('GET', $engine->request()->method);
$this->assertSame($early, $engine->request(), 'same Request instance is refreshed, not replaced');
}
public function testAllowMethodOverrideFalseDoesNotClobberManualMethodWithoutOverrideInput(): void
{
// No X-HTTP-Method-Override / _method — manual method assignment must survive start().
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['REQUEST_URI'] = '/someRoute';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_SERVER['SERVER_NAME'] = 'localhost';
$_SERVER['HTTP_HOST'] = 'localhost';
$engine = new Engine();
$engine->set('flight.allow_method_override', false);
$engine->route('GET /someRoute', function () {
echo 'i ran';
}, true);
$engine->request()->method = 'HEAD';
$engine->request()->url = '/someRoute';
$this->expectOutputString('');
$engine->start();
$this->assertSame('HEAD', $engine->request()->method);
}
}

@ -31,11 +31,15 @@ class RequestTest extends TestCase
$_COOKIE = [];
$_FILES = [];
// Static flag leaks across tests; always restore the framework default.
Request::$allowMethodOverride = true;
$this->request = new Request();
}
protected function tearDown(): void
{
Request::$allowMethodOverride = true;
unset($_REQUEST);
unset($_SERVER);
}
@ -127,6 +131,49 @@ class RequestTest extends TestCase
$this->assertEquals('PUT', $request->method);
}
public function testMethodOverrideDisabledIgnoresHeader(): void
{
Request::$allowMethodOverride = false;
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'DELETE';
$request = new Request();
$this->assertSame('GET', $request->method);
$this->assertSame('GET', Request::getMethod());
}
public function testMethodOverrideDisabledIgnoresPostField(): void
{
Request::$allowMethodOverride = false;
$_SERVER['REQUEST_METHOD'] = 'POST';
$_REQUEST['_method'] = 'PUT';
$request = new Request();
$this->assertSame('POST', $request->method);
$this->assertSame('POST', Request::getMethod());
}
public function testMethodOverrideFlagMustBeSetBeforeConstruction(): void
{
// Documents the caching behavior: flipping the static after construct
// does not rewrite the already-cached $request->method.
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'DELETE';
Request::$allowMethodOverride = true;
$request = new Request();
$this->assertSame('DELETE', $request->method);
Request::$allowMethodOverride = false;
$this->assertSame('DELETE', $request->method, 'cached method is not auto-refreshed');
$this->assertSame('GET', Request::getMethod(), 'getMethod() respects the new flag');
$request->method = Request::getMethod();
$this->assertSame('GET', $request->method);
}
public function testHttps(): void
{
$_SERVER['HTTPS'] = 'on';

Loading…
Cancel
Save