Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: filter except empty #7823

Merged
merged 10 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 44 additions & 5 deletions system/Filters/Filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ public function setResponse(ResponseInterface $response)
* Runs through all of the filters for the specified
* uri and position.
*
* @return mixed|RequestInterface|ResponseInterface
* @param string $uri URI path relative to baseURL
*
* @return RequestInterface|ResponseInterface|string|null
*
* @throws FilterException
*/
Expand Down Expand Up @@ -221,6 +223,8 @@ public function run(string $uri, string $position = 'before')
* run through both a before and after and don't want to double
* process the rows.
*
* @param string|null $uri URI path relative to baseURL (all lowercase)
*
* @return Filters
*/
public function initialize(?string $uri = null)
Expand Down Expand Up @@ -391,7 +395,7 @@ public function getArguments(?string $key = null)
/**
* Add any applicable (not excluded) global filter settings to the mix.
*
* @param string $uri
* @param string|null $uri URI path relative to baseURL (all lowercase)
*
* @return void
*/
Expand All @@ -416,7 +420,7 @@ protected function processGlobals(?string $uri = null)
if (isset($rules['except'])) {
// grab the exclusion rules
$check = $rules['except'];
if ($this->pathApplies($uri, $check)) {
if ($this->checkExcept($uri, $check)) {
$keep = false;
}
}
Expand Down Expand Up @@ -454,7 +458,7 @@ protected function processMethods()
/**
* Add any applicable configured filters to the mix.
*
* @param string $uri
* @param string|null $uri URI path relative to baseURL (all lowercase)
*
* @return void
*/
Expand Down Expand Up @@ -536,12 +540,47 @@ private function pathApplies(string $uri, $paths)
$paths = [$paths];
}

// treat each paths as pseudo-regex
return $this->checkPseudoRegex($uri, $paths);
}

/**
* Check except paths
*
* @param string $uri URI path relative to baseURL (all lowercase)
* @param array|string $paths The except path patterns
*
* @return bool True if the URI matches except paths.
*/
private function checkExcept(string $uri, $paths): bool
{
// empty array does not match anything
if ($paths === []) {
return false;
}

// make sure the paths are iterable
if (is_string($paths)) {
$paths = [$paths];
}

return $this->checkPseudoRegex($uri, $paths);
}

/**
* Check the URI path as pseudo-regex
*
* @param string $uri URI path relative to baseURL (all lowercase)
* @param array $paths The except path patterns
*/
private function checkPseudoRegex(string $uri, array $paths): bool
{
// treat each path as pseudo-regex
foreach ($paths as $path) {
// need to escape path separators
$path = str_replace('/', '\/', trim($path, '/ '));
// need to make pseudo wildcard real
$path = strtolower(str_replace('*', '.*', $path));

// Does this rule apply here?
if (preg_match('#^' . $path . '$#', $uri, $match) === 1) {
return true;
Expand Down
128 changes: 92 additions & 36 deletions tests/system/Filters/FiltersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -215,15 +215,23 @@ public static function provideProcessMethodProcessGlobalsWithExcept(): iterable
['admin/*'],
],
[
[],
['admin/*', 'foo/*'],
],
[
['*'],
],
[
'admin/*',
],
];
}

/**
* @dataProvider provideProcessMethodProcessGlobalsWithExcept
*
* @param array|string $except
*/
public function testProcessMethodProcessGlobalsWithExcept(array $except): void
public function testProcessMethodProcessGlobalsWithExcept($except): void
{
$_SERVER['REQUEST_METHOD'] = 'GET';

Expand Down Expand Up @@ -572,7 +580,12 @@ public function testOtherResult(): void
$this->assertSame('This is curious', $response);
}

public function testBeforeExceptString(): void
/**
* @dataProvider provideBeforeExcept
*
* @param array|string $except
*/
public function testBeforeExcept(string $uri, $except, array $expected): void
{
$_SERVER['REQUEST_METHOD'] = 'GET';

Expand All @@ -584,7 +597,7 @@ public function testBeforeExceptString(): void
],
'globals' => [
'before' => [
'foo' => ['except' => 'admin/*'],
'foo' => ['except' => $except],
'bar',
],
'after' => [
Expand All @@ -595,48 +608,91 @@ public function testBeforeExceptString(): void
$filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
$filters = $this->createFilters($filtersConfig);

$uri = 'admin/foo/bar';
$expected = [
'before' => [
'bar',
],
'after' => ['baz'],
];
$this->assertSame($expected, $filters->initialize($uri)->getFilters());
}

public function testBeforeExceptInapplicable(): void
public static function provideBeforeExcept(): iterable
{
$_SERVER['REQUEST_METHOD'] = 'GET';

$config = [
'aliases' => [
'foo' => '',
'bar' => '',
'baz' => '',
return [
'string exclude' => [
'admin/foo/bar',
'admin/*',
[
'before' => [
'bar',
],
'after' => ['baz'],
],
],
'globals' => [
'before' => [
'foo' => ['except' => 'george/*'],
'bar',
'string not exclude' => [
'admin/foo/bar',
'george/*',
[
'before' => [
'foo',
'bar',
],
'after' => ['baz'],
],
'after' => [
'baz',
],
'empty array not exclude' => [
'admin/foo/bar',
[],
[
'before' => [
'foo',
'bar',
],
'after' => ['baz'],
],
],
];
$filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
$filters = $this->createFilters($filtersConfig);

$uri = 'admin/foo/bar';
$expected = [
'before' => [
'foo',
'bar',
'empty string not exclude' => [
'admin/foo/bar',
// The URI path '' means the baseURL.
'',
[
'before' => [
'foo',
'bar',
],
'after' => ['baz'],
],
],
'empty string exclude' => [
// The URI path '' means the baseURL.
'',
// So this setting excludes `foo` filter only to the baseURL.
'',
[
'before' => [
'bar',
],
'after' => ['baz'],
],
],
'slash not exclude' => [
'admin/foo/bar',
'/',
[
'before' => [
'foo',
'bar',
],
'after' => ['baz'],
],
],
'slash exclude' => [
// The URI path '' means the baseURL.
'',
'/',
[
'before' => [
'bar',
],
'after' => ['baz'],
],
],
'after' => ['baz'],
];
$this->assertSame($expected, $filters->initialize($uri)->getFilters());
}

public function testAfterExceptString(): void
Expand Down
6 changes: 6 additions & 0 deletions user_guide_src/source/changelogs/v4.3.8.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ Deprecations
Bugs Fixed
**********

- **Controller Filters:** In previous versions, ``['except' => []]`` or ``['except' => '']``
meant "except all". The bug has been fixed, and now

- ``['except' => []]`` means to exclude nothing.
- ``['except' => '']`` means to exclude the baseURL only.

See the repo's
`CHANGELOG.md <https://github.com/codeigniter4/CodeIgniter4/blob/develop/CHANGELOG.md>`_
for a complete list of bugs fixed.