diff --git a/app/Config/Feature.php b/app/Config/Feature.php
index 39a37676183c..c8f2cafcccd0 100644
--- a/app/Config/Feature.php
+++ b/app/Config/Feature.php
@@ -18,4 +18,17 @@ class Feature extends BaseConfig
* Use filter execution order in 4.4 or before.
*/
public bool $oldFilterOrder = false;
+
+ /**
+ * Use lowercase HTTP method names like "get", "post" in Config\Filters::$methods.
+ *
+ * But the HTTP method is case-sensitive. So using lowercase is wrong.
+ * We should disable this and use uppercase names like "GET", "POST", etc.
+ *
+ * The method token is case-sensitive because it might be used as a gateway
+ * to object-based systems with case-sensitive method names. By convention,
+ * standardized methods are defined in all-uppercase US-ASCII letters.
+ * https://www.rfc-editor.org/rfc/rfc9110#name-overview
+ */
+ public bool $lowerCaseFilterMethods = true;
}
diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php
index 68cb5a9f5497..3eecebfbed31 100644
--- a/system/CodeIgniter.php
+++ b/system/CodeIgniter.php
@@ -1027,7 +1027,7 @@ public function storePreviousURL($uri)
public function spoofRequestMethod()
{
// Only works with POSTED forms
- if (strtolower($this->request->getMethod()) !== 'post') {
+ if ($this->request->getMethod() !== 'POST') {
return;
}
@@ -1038,7 +1038,7 @@ public function spoofRequestMethod()
}
// Only allows PUT, PATCH, DELETE
- if (in_array(strtoupper($method), ['PUT', 'PATCH', 'DELETE'], true)) {
+ if (in_array($method, ['PUT', 'PATCH', 'DELETE'], true)) {
$this->request = $this->request->setMethod($method);
}
}
diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php
index 8a28aeb0118e..84100ed08879 100644
--- a/system/Filters/Filters.php
+++ b/system/Filters/Filters.php
@@ -494,8 +494,9 @@ protected function processMethods()
return;
}
- // Request method won't be set for CLI-based requests
- $method = strtolower($this->request->getMethod()) ?? 'cli';
+ if (config(Feature::class)->lowerCaseFilterMethods) {
+ $method = strtolower($this->request->getMethod());
+ }
if (array_key_exists($method, $this->config->methods)) {
if (config(Feature::class)->oldFilterOrder) {
diff --git a/system/HTTP/CLIRequest.php b/system/HTTP/CLIRequest.php
index 878e8a1d66c6..2b12694d86b9 100644
--- a/system/HTTP/CLIRequest.php
+++ b/system/HTTP/CLIRequest.php
@@ -56,7 +56,7 @@ class CLIRequest extends Request
*
* @var string
*/
- protected $method = 'cli';
+ protected $method = 'CLI';
/**
* Constructor
diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php
index c8b3b9fe9f92..48605b1e8274 100644
--- a/system/HTTP/CURLRequest.php
+++ b/system/HTTP/CURLRequest.php
@@ -130,7 +130,7 @@ public function __construct(App $config, URI $uri, ?ResponseInterface $response
* Sends an HTTP request to the specified $url. If this is a relative
* URL, it will be merged with $this->baseURI to form a complete URL.
*
- * @param string $method
+ * @param string $method HTTP method
*/
public function request($method, string $url, array $options = []): ResponseInterface
{
@@ -177,7 +177,7 @@ protected function resetOptions()
*/
public function get(string $url, array $options = []): ResponseInterface
{
- return $this->request('get', $url, $options);
+ return $this->request('GET', $url, $options);
}
/**
@@ -185,7 +185,7 @@ public function get(string $url, array $options = []): ResponseInterface
*/
public function delete(string $url, array $options = []): ResponseInterface
{
- return $this->request('delete', $url, $options);
+ return $this->request('DELETE', $url, $options);
}
/**
@@ -193,7 +193,7 @@ public function delete(string $url, array $options = []): ResponseInterface
*/
public function head(string $url, array $options = []): ResponseInterface
{
- return $this->request('head', $url, $options);
+ return $this->request('HEAD', $url, $options);
}
/**
@@ -201,7 +201,7 @@ public function head(string $url, array $options = []): ResponseInterface
*/
public function options(string $url, array $options = []): ResponseInterface
{
- return $this->request('options', $url, $options);
+ return $this->request('OPTIONS', $url, $options);
}
/**
@@ -209,7 +209,7 @@ public function options(string $url, array $options = []): ResponseInterface
*/
public function patch(string $url, array $options = []): ResponseInterface
{
- return $this->request('patch', $url, $options);
+ return $this->request('PATCH', $url, $options);
}
/**
@@ -217,7 +217,7 @@ public function patch(string $url, array $options = []): ResponseInterface
*/
public function post(string $url, array $options = []): ResponseInterface
{
- return $this->request('post', $url, $options);
+ return $this->request('POST', $url, $options);
}
/**
@@ -225,7 +225,7 @@ public function post(string $url, array $options = []): ResponseInterface
*/
public function put(string $url, array $options = []): ResponseInterface
{
- return $this->request('put', $url, $options);
+ return $this->request('PUT', $url, $options);
}
/**
@@ -339,17 +339,6 @@ protected function prepareURL(string $url): string
);
}
- /**
- * Get the request method. Overrides the Request class' method
- * since users expect a different answer here.
- *
- * @param bool|false $upper Whether to return in upper or lower case.
- */
- public function getMethod(bool $upper = false): string
- {
- return ($upper) ? strtoupper($this->method) : strtolower($this->method);
- }
-
/**
* Fires the actual cURL request.
*
@@ -446,8 +435,6 @@ protected function applyRequestHeaders(array $curlOptions = []): array
*/
protected function applyMethod(string $method, array $curlOptions): array
{
- $method = strtoupper($method);
-
$this->method = $method;
$curlOptions[CURLOPT_CUSTOMREQUEST] = $method;
diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php
index dbb3a31bea9b..f80337658e43 100755
--- a/system/HTTP/IncomingRequest.php
+++ b/system/HTTP/IncomingRequest.php
@@ -406,7 +406,7 @@ public function is(string $type): bool
$httpMethods = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'PATCH', 'OPTIONS'];
if (in_array($valueUpper, $httpMethods, true)) {
- return strtoupper($this->getMethod()) === $valueUpper;
+ return $this->getMethod() === $valueUpper;
}
if ($valueUpper === 'JSON') {
diff --git a/system/HTTP/OutgoingRequest.php b/system/HTTP/OutgoingRequest.php
index 698cde263bc1..5738b1aea2e7 100644
--- a/system/HTTP/OutgoingRequest.php
+++ b/system/HTTP/OutgoingRequest.php
@@ -66,15 +66,13 @@ private function getHostFromUri(URI $uri): string
}
/**
- * Get the request method.
+ * Retrieves the HTTP method of the request.
*
- * @param bool $upper Whether to return in upper or lower case.
- *
- * @deprecated The $upper functionality will be removed and this will revert to its PSR-7 equivalent
+ * @return string Returns the request method.
*/
- public function getMethod(bool $upper = false): string
+ public function getMethod(): string
{
- return ($upper) ? strtoupper($this->method) : strtolower($this->method);
+ return $this->method;
}
/**
diff --git a/system/HTTP/OutgoingRequestInterface.php b/system/HTTP/OutgoingRequestInterface.php
index 3839b64fd8e1..b4a62dfde73f 100644
--- a/system/HTTP/OutgoingRequestInterface.php
+++ b/system/HTTP/OutgoingRequestInterface.php
@@ -21,14 +21,11 @@
interface OutgoingRequestInterface extends MessageInterface
{
/**
- * Get the request method.
- * An extension of PSR-7's getMethod to allow casing.
+ * Retrieves the HTTP method of the request.
*
- * @param bool $upper Whether to return in upper or lower case.
- *
- * @deprecated The $upper functionality will be removed and this will revert to its PSR-7 equivalent
+ * @return string Returns the request method.
*/
- public function getMethod(bool $upper = false): string;
+ public function getMethod(): string;
/**
* Return an instance with the provided HTTP method.
diff --git a/system/HTTP/Request.php b/system/HTTP/Request.php
index baf60c0305b6..462cb5731952 100644
--- a/system/HTTP/Request.php
+++ b/system/HTTP/Request.php
@@ -49,20 +49,6 @@ public function __construct($config = null) // @phpstan-ignore-line
}
}
- /**
- * Get the request method.
- *
- * @param bool $upper Whether to return in upper or lower case.
- *
- * @deprecated 4.0.5 The $upper functionality will be removed and this will revert to its PSR-7 equivalent
- *
- * @codeCoverageIgnore
- */
- public function getMethod(bool $upper = false): string
- {
- return ($upper) ? strtoupper($this->method) : strtolower($this->method);
- }
-
/**
* Sets the request method. Used when spoofing the request.
*
diff --git a/tests/system/CodeIgniterTest.php b/tests/system/CodeIgniterTest.php
index 505d1f5e5a7b..948e9c2dcd5d 100644
--- a/tests/system/CodeIgniterTest.php
+++ b/tests/system/CodeIgniterTest.php
@@ -733,7 +733,7 @@ public function testSpoofRequestMethodCanUsePUT(): void
$this->codeigniter->run();
ob_get_clean();
- $this->assertSame('put', Services::incomingrequest()->getMethod());
+ $this->assertSame('PUT', Services::incomingrequest()->getMethod());
}
public function testSpoofRequestMethodCannotUseGET(): void
@@ -758,7 +758,7 @@ public function testSpoofRequestMethodCannotUseGET(): void
$this->codeigniter->run();
ob_get_clean();
- $this->assertSame('post', Services::incomingrequest()->getMethod());
+ $this->assertSame('POST', Services::incomingrequest()->getMethod());
}
/**
diff --git a/tests/system/HTTP/CLIRequestTest.php b/tests/system/HTTP/CLIRequestTest.php
index e15f0fca4f87..3c6293131d70 100644
--- a/tests/system/HTTP/CLIRequestTest.php
+++ b/tests/system/HTTP/CLIRequestTest.php
@@ -525,8 +525,7 @@ public function testGetIPAddressDefault(): void
public function testMethodReturnsRightStuff(): void
{
// Defaults method to CLI now.
- $this->assertSame('cli', $this->request->getMethod());
- $this->assertSame('CLI', $this->request->getMethod(true));
+ $this->assertSame('CLI', $this->request->getMethod());
}
public function testMethodIsCliReturnsAlwaysTrue(): void
diff --git a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php
index d8e96424dae5..c9710616e2d2 100644
--- a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php
+++ b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php
@@ -103,7 +103,7 @@ public function testGetSetsCorrectMethod(): void
{
$this->request->get('http://example.com');
- $this->assertSame('get', $this->request->getMethod());
+ $this->assertSame('GET', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -115,7 +115,7 @@ public function testDeleteSetsCorrectMethod(): void
{
$this->request->delete('http://example.com');
- $this->assertSame('delete', $this->request->getMethod());
+ $this->assertSame('DELETE', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -127,7 +127,7 @@ public function testHeadSetsCorrectMethod(): void
{
$this->request->head('http://example.com');
- $this->assertSame('head', $this->request->getMethod());
+ $this->assertSame('HEAD', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -139,7 +139,7 @@ public function testOptionsSetsCorrectMethod(): void
{
$this->request->options('http://example.com');
- $this->assertSame('options', $this->request->getMethod());
+ $this->assertSame('OPTIONS', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -281,7 +281,7 @@ public function testPatchSetsCorrectMethod(): void
{
$this->request->patch('http://example.com');
- $this->assertSame('patch', $this->request->getMethod());
+ $this->assertSame('PATCH', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -293,7 +293,7 @@ public function testPostSetsCorrectMethod(): void
{
$this->request->post('http://example.com');
- $this->assertSame('post', $this->request->getMethod());
+ $this->assertSame('POST', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -305,7 +305,7 @@ public function testPutSetsCorrectMethod(): void
{
$this->request->put('http://example.com');
- $this->assertSame('put', $this->request->getMethod());
+ $this->assertSame('PUT', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -322,19 +322,19 @@ public function testCustomMethodSetsCorrectMethod(): void
$options = $this->request->curl_options;
$this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options);
- $this->assertSame('CUSTOM', $options[CURLOPT_CUSTOMREQUEST]);
+ $this->assertSame('custom', $options[CURLOPT_CUSTOMREQUEST]);
}
public function testRequestMethodGetsSanitized(): void
{
$this->request->request('', 'http://example.com');
- $this->assertSame('custom', $this->request->getMethod());
+ $this->assertSame('Custom', $this->request->getMethod());
$options = $this->request->curl_options;
$this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options);
- $this->assertSame('CUSTOM', $options[CURLOPT_CUSTOMREQUEST]);
+ $this->assertSame('Custom', $options[CURLOPT_CUSTOMREQUEST]);
}
public function testRequestSetsBasicCurlOptions(): void
@@ -951,7 +951,7 @@ public function testPostFormEncoded(): void
'form_params' => $params,
]);
- $this->assertSame('post', $this->request->getMethod());
+ $this->assertSame('POST', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -974,7 +974,7 @@ public function testPostFormMultipart(): void
'multipart' => $params,
]);
- $this->assertSame('post', $this->request->getMethod());
+ $this->assertSame('POST', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -1022,7 +1022,7 @@ public function testJSONData(): void
'json' => $params,
]);
- $this->assertSame('post', $this->request->getMethod());
+ $this->assertSame('POST', $this->request->getMethod());
$expected = json_encode($params);
$this->assertSame(
diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php
index 186284da6ba6..2ca18aa87282 100644
--- a/tests/system/HTTP/CURLRequestTest.php
+++ b/tests/system/HTTP/CURLRequestTest.php
@@ -103,7 +103,7 @@ public function testGetSetsCorrectMethod(): void
{
$this->request->get('http://example.com');
- $this->assertSame('get', $this->request->getMethod());
+ $this->assertSame('GET', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -115,7 +115,7 @@ public function testDeleteSetsCorrectMethod(): void
{
$this->request->delete('http://example.com');
- $this->assertSame('delete', $this->request->getMethod());
+ $this->assertSame('DELETE', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -127,7 +127,7 @@ public function testHeadSetsCorrectMethod(): void
{
$this->request->head('http://example.com');
- $this->assertSame('head', $this->request->getMethod());
+ $this->assertSame('HEAD', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -139,7 +139,7 @@ public function testOptionsSetsCorrectMethod(): void
{
$this->request->options('http://example.com');
- $this->assertSame('options', $this->request->getMethod());
+ $this->assertSame('OPTIONS', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -264,7 +264,7 @@ public function testPatchSetsCorrectMethod(): void
{
$this->request->patch('http://example.com');
- $this->assertSame('patch', $this->request->getMethod());
+ $this->assertSame('PATCH', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -276,7 +276,7 @@ public function testPostSetsCorrectMethod(): void
{
$this->request->post('http://example.com');
- $this->assertSame('post', $this->request->getMethod());
+ $this->assertSame('POST', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -288,7 +288,7 @@ public function testPutSetsCorrectMethod(): void
{
$this->request->put('http://example.com');
- $this->assertSame('put', $this->request->getMethod());
+ $this->assertSame('PUT', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -305,19 +305,19 @@ public function testCustomMethodSetsCorrectMethod(): void
$options = $this->request->curl_options;
$this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options);
- $this->assertSame('CUSTOM', $options[CURLOPT_CUSTOMREQUEST]);
+ $this->assertSame('custom', $options[CURLOPT_CUSTOMREQUEST]);
}
public function testRequestMethodGetsSanitized(): void
{
$this->request->request('', 'http://example.com');
- $this->assertSame('custom', $this->request->getMethod());
+ $this->assertSame('Custom', $this->request->getMethod());
$options = $this->request->curl_options;
$this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options);
- $this->assertSame('CUSTOM', $options[CURLOPT_CUSTOMREQUEST]);
+ $this->assertSame('Custom', $options[CURLOPT_CUSTOMREQUEST]);
}
public function testRequestSetsBasicCurlOptions(): void
@@ -934,7 +934,7 @@ public function testPostFormEncoded(): void
'form_params' => $params,
]);
- $this->assertSame('post', $this->request->getMethod());
+ $this->assertSame('POST', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -957,7 +957,7 @@ public function testPostFormMultipart(): void
'multipart' => $params,
]);
- $this->assertSame('post', $this->request->getMethod());
+ $this->assertSame('POST', $this->request->getMethod());
$options = $this->request->curl_options;
@@ -1005,7 +1005,7 @@ public function testJSONData(): void
'json' => $params,
]);
- $this->assertSame('post', $this->request->getMethod());
+ $this->assertSame('POST', $this->request->getMethod());
$expected = json_encode($params);
$this->assertSame($expected, $this->request->getBody());
diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php
index 9f6114f4875e..1681d946afc0 100644
--- a/tests/system/HTTP/IncomingRequestTest.php
+++ b/tests/system/HTTP/IncomingRequestTest.php
@@ -813,7 +813,7 @@ public function testGetFile(): void
public function testSpoofing(): void
{
$this->request->setMethod('WINK');
- $this->assertSame('wink', $this->request->getMethod());
+ $this->assertSame('WINK', $this->request->getMethod());
}
/**
diff --git a/tests/system/HTTP/RequestTest.php b/tests/system/HTTP/RequestTest.php
index be20b4ff8f5b..269156fc1982 100644
--- a/tests/system/HTTP/RequestTest.php
+++ b/tests/system/HTTP/RequestTest.php
@@ -639,7 +639,6 @@ public function testGetIPAddressThruProxyOutofSubnet(): void
public function testMethodReturnsRightStuff(): void
{
// Defaults method to GET now.
- $this->assertSame('get', $this->request->getMethod());
- $this->assertSame('GET', $this->request->getMethod(true));
+ $this->assertSame('GET', $this->request->getMethod());
}
}
diff --git a/tests/system/Test/ControllerTestTraitTest.php b/tests/system/Test/ControllerTestTraitTest.php
index ab45c6372d41..ac470ce3ce56 100644
--- a/tests/system/Test/ControllerTestTraitTest.php
+++ b/tests/system/Test/ControllerTestTraitTest.php
@@ -150,7 +150,7 @@ public function testRequestPassthrough(): void
->execute('popper');
$req = $result->request();
- $this->assertSame('get', $req->getMethod());
+ $this->assertSame('GET', $req->getMethod());
}
public function testFailureResponse(): void
diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php
index 0b7ad6faddd1..3ed0471fcbf1 100644
--- a/tests/system/Validation/ValidationTest.php
+++ b/tests/system/Validation/ValidationTest.php
@@ -848,7 +848,7 @@ public function testRawInput(): void
$rules = [
'role' => 'required|min_length[5]',
];
- $result = $this->validation->withRequest($request->withMethod('patch'))->setRules($rules)->run();
+ $result = $this->validation->withRequest($request->withMethod('PATCH'))->setRules($rules)->run();
$this->assertTrue($result);
$this->assertSame([], $this->validation->getErrors());
@@ -873,7 +873,7 @@ public function testJsonInput(): void
'role' => 'required|min_length[5]',
];
$result = $this->validation
- ->withRequest($request->withMethod('patch'))
+ ->withRequest($request->withMethod('PATCH'))
->setRules($rules)
->run();
@@ -910,7 +910,7 @@ public function testJsonInputObjectArray(): void
'p' => 'required|array_count[2]',
];
$result = $this->validation
- ->withRequest($request->withMethod('patch'))
+ ->withRequest($request->withMethod('PATCH'))
->setRules($rules)
->run();
@@ -1093,7 +1093,7 @@ public function testRulesForArrayField(array $body, array $rules, array $results
$request = new IncomingRequest($config, new URI(), http_build_query($body), new UserAgent());
$this->validation->setRules($rules);
- $this->validation->withRequest($request->withMethod('post'))->run($body);
+ $this->validation->withRequest($request->withMethod('POST'))->run($body);
$this->assertSame($results, $this->validation->getErrors());
}
@@ -1176,7 +1176,7 @@ public function testRulesForSingleRuleWithAsteriskWillReturnNoError(): void
'name_user.*' => 'alpha_numeric',
]);
- $this->validation->withRequest($request->withMethod('post'))->run();
+ $this->validation->withRequest($request->withMethod('POST'))->run();
$this->assertSame([], $this->validation->getErrors());
}
@@ -1211,7 +1211,7 @@ public function testRulesForSingleRuleWithAsteriskWillReturnError(): void
'contacts.friends.*.name' => 'required',
]);
- $this->validation->withRequest($request->withMethod('post'))->run();
+ $this->validation->withRequest($request->withMethod('POST'))->run();
$this->assertSame([
'id_user.0' => 'The id_user.* field must contain only numbers.',
'name_user.0' => 'The name_user.* field may only contain alphabetical characters.',
@@ -1245,7 +1245,7 @@ public function testRulesForSingleRuleWithSingleValue(): void
'id_user' => 'numeric',
]);
- $this->validation->withRequest($request->withMethod('post'))->run();
+ $this->validation->withRequest($request->withMethod('POST'))->run();
$this->assertSame([
'id_user' => 'The id_user field must contain only numbers.',
], $this->validation->getErrors());