From 005cbbadbd9c2706d556042e6b07e1b2c6d480e2 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Sun, 21 Jun 2026 23:58:37 +0200 Subject: [PATCH 1/6] refactor(HTTP): optimize download() file path processing and add extreme filename test --- system/HTTP/ResponseTrait.php | 15 +++++--------- tests/system/HTTP/ResponseTest.php | 32 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index 3063e44116fb..265a62fb0a1f 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -733,20 +733,15 @@ public function download(string $filename = '', $data = '', bool $setMime = fals return null; } - $filepath = ''; if ($data === null) { - $filepath = $filename; - $filename = explode('/', str_replace(DIRECTORY_SEPARATOR, '/', $filename)); - $filename = end($filename); + $response = new DownloadResponse(basename($filename), $setMime); + $response->setFilePath($filename); + + return $response; } $response = new DownloadResponse($filename, $setMime); - - if ($filepath !== '') { - $response->setFilePath($filepath); - } elseif ($data !== null) { - $response->setBinary($data); - } + $response->setBinary($data); return $response; } diff --git a/tests/system/HTTP/ResponseTest.php b/tests/system/HTTP/ResponseTest.php index 38c349117cbb..8eb0432bd31d 100644 --- a/tests/system/HTTP/ResponseTest.php +++ b/tests/system/HTTP/ResponseTest.php @@ -494,6 +494,38 @@ public function testGetDownloadResponseByFilePath(): void $this->assertSame(file_get_contents(__FILE__), $actualOutput); } + public function testGetDownloadResponseByExtremeFilePath(): void + { + $response = new Response(new App()); + + $tempDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'ci4_test_dir'; + @mkdir($tempDir); + $extremeName = 'my_extreme_file_!@#$%.txt'; + $extremePath = $tempDir . DIRECTORY_SEPARATOR . $extremeName; + file_put_contents($extremePath, 'extreme data'); + + $actual = $response->download($extremePath, null); + + $this->assertInstanceOf(DownloadResponse::class, $actual); + $actual->buildHeaders(); + + $expectedBasename = basename($extremePath); + $this->assertSame( + 'attachment; filename="' . addslashes($expectedBasename) . '"; filename*=UTF-8\'\'' . rawurlencode($expectedBasename), + $actual->getHeaderLine('Content-Disposition'), + ); + + ob_start(); + $actual->sendBody(); + $actualOutput = ob_get_contents(); + ob_end_clean(); + + $this->assertSame('extreme data', $actualOutput); + + unlink($extremePath); + rmdir($tempDir); + } + public function testVagueDownload(): void { $response = new Response(new App()); From b6de5c4ea1c22fc4a7b22159edd6e84721774de4 Mon Sep 17 00:00:00 2001 From: Bogdan Lambarski Date: Tue, 23 Jun 2026 23:28:55 +0200 Subject: [PATCH 2/6] Update tests/system/HTTP/ResponseTest.php Co-authored-by: Michal Sniatala --- tests/system/HTTP/ResponseTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/system/HTTP/ResponseTest.php b/tests/system/HTTP/ResponseTest.php index 8eb0432bd31d..eaa684217cf9 100644 --- a/tests/system/HTTP/ResponseTest.php +++ b/tests/system/HTTP/ResponseTest.php @@ -498,8 +498,9 @@ public function testGetDownloadResponseByExtremeFilePath(): void { $response = new Response(new App()); - $tempDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'ci4_test_dir'; - @mkdir($tempDir); + $tempDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'ci4_test_dir_' . bin2hex(random_bytes(8)); + + $this->assertTrue(mkdir($tempDir)); $extremeName = 'my_extreme_file_!@#$%.txt'; $extremePath = $tempDir . DIRECTORY_SEPARATOR . $extremeName; file_put_contents($extremePath, 'extreme data'); From 86fe1d852a580b7f0164123d4aae7be7c5ae92c8 Mon Sep 17 00:00:00 2001 From: Bogdan Lambarski Date: Tue, 23 Jun 2026 23:29:08 +0200 Subject: [PATCH 3/6] Update tests/system/HTTP/ResponseTest.php Co-authored-by: Michal Sniatala --- tests/system/HTTP/ResponseTest.php | 38 +++++++++++++++++------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/tests/system/HTTP/ResponseTest.php b/tests/system/HTTP/ResponseTest.php index eaa684217cf9..42e21d49eca0 100644 --- a/tests/system/HTTP/ResponseTest.php +++ b/tests/system/HTTP/ResponseTest.php @@ -498,33 +498,37 @@ public function testGetDownloadResponseByExtremeFilePath(): void { $response = new Response(new App()); + $tempDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'ci4_test_dir'; + @mkdir($tempDir); $tempDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'ci4_test_dir_' . bin2hex(random_bytes(8)); - $this->assertTrue(mkdir($tempDir)); $extremeName = 'my_extreme_file_!@#$%.txt'; $extremePath = $tempDir . DIRECTORY_SEPARATOR . $extremeName; - file_put_contents($extremePath, 'extreme data'); - $actual = $response->download($extremePath, null); + try { + file_put_contents($extremePath, 'extreme data'); - $this->assertInstanceOf(DownloadResponse::class, $actual); - $actual->buildHeaders(); + $actual = $response->download($extremePath, null); - $expectedBasename = basename($extremePath); - $this->assertSame( - 'attachment; filename="' . addslashes($expectedBasename) . '"; filename*=UTF-8\'\'' . rawurlencode($expectedBasename), - $actual->getHeaderLine('Content-Disposition'), - ); + $this->assertInstanceOf(DownloadResponse::class, $actual); + $actual->buildHeaders(); - ob_start(); - $actual->sendBody(); - $actualOutput = ob_get_contents(); - ob_end_clean(); + $expectedFilename = $extremeName; + $this->assertSame( + 'attachment; filename="' . addslashes($expectedFilename) . '"; filename*=UTF-8\'\'' . rawurlencode($expectedFilename), + $actual->getHeaderLine('Content-Disposition'), + ); - $this->assertSame('extreme data', $actualOutput); + ob_start(); + $actual->sendBody(); + $actualOutput = ob_get_contents(); + ob_end_clean(); - unlink($extremePath); - rmdir($tempDir); + $this->assertSame('extreme data', $actualOutput); + } finally { + @unlink($extremePath); + @rmdir($tempDir); + } } public function testVagueDownload(): void From 5323d584c8cb6b598933df1cf2db68451280f21f Mon Sep 17 00:00:00 2001 From: Bogdan Lambarski Date: Wed, 24 Jun 2026 20:16:48 +0200 Subject: [PATCH 4/6] Update tests/system/HTTP/ResponseTest.php Co-authored-by: Michal Sniatala --- tests/system/HTTP/ResponseTest.php | 4 ++-- user_guide_src/source/changelogs/v4.7.4.rst | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/system/HTTP/ResponseTest.php b/tests/system/HTTP/ResponseTest.php index 42e21d49eca0..9c44cb4b385a 100644 --- a/tests/system/HTTP/ResponseTest.php +++ b/tests/system/HTTP/ResponseTest.php @@ -498,8 +498,8 @@ public function testGetDownloadResponseByExtremeFilePath(): void { $response = new Response(new App()); - $tempDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'ci4_test_dir'; - @mkdir($tempDir); + $tempDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'ci4_test_dir_' . bin2hex(random_bytes(8)); + $this->assertTrue(mkdir($tempDir)); $tempDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'ci4_test_dir_' . bin2hex(random_bytes(8)); $this->assertTrue(mkdir($tempDir)); $extremeName = 'my_extreme_file_!@#$%.txt'; diff --git a/user_guide_src/source/changelogs/v4.7.4.rst b/user_guide_src/source/changelogs/v4.7.4.rst index 1cf22169f347..eba5788e0659 100644 --- a/user_guide_src/source/changelogs/v4.7.4.rst +++ b/user_guide_src/source/changelogs/v4.7.4.rst @@ -22,6 +22,8 @@ Message Changes Changes ******* +- **HTTP:** Optimized ``ResponseTrait::download()`` to use ``basename()`` for filename extraction instead of string replacement and array explosion, improving performance. + ************ Deprecations ************ From 576b606546371a3c51c428d50009cf29e35c0c38 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Wed, 24 Jun 2026 21:20:00 +0200 Subject: [PATCH 5/6] chore(changelog): remove download optimization entry as it is a refactoring --- user_guide_src/source/changelogs/v4.7.4.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.7.4.rst b/user_guide_src/source/changelogs/v4.7.4.rst index eba5788e0659..1cf22169f347 100644 --- a/user_guide_src/source/changelogs/v4.7.4.rst +++ b/user_guide_src/source/changelogs/v4.7.4.rst @@ -22,8 +22,6 @@ Message Changes Changes ******* -- **HTTP:** Optimized ``ResponseTrait::download()`` to use ``basename()`` for filename extraction instead of string replacement and array explosion, improving performance. - ************ Deprecations ************ From c661ee3d771110448b4990314f5ab3b90f1f61c6 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Thu, 25 Jun 2026 22:24:25 +0200 Subject: [PATCH 6/6] fix: remove duplicated temporary directory creation in test --- tests/system/HTTP/ResponseTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/system/HTTP/ResponseTest.php b/tests/system/HTTP/ResponseTest.php index 9c44cb4b385a..17d1b4191134 100644 --- a/tests/system/HTTP/ResponseTest.php +++ b/tests/system/HTTP/ResponseTest.php @@ -498,8 +498,6 @@ public function testGetDownloadResponseByExtremeFilePath(): void { $response = new Response(new App()); - $tempDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'ci4_test_dir_' . bin2hex(random_bytes(8)); - $this->assertTrue(mkdir($tempDir)); $tempDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'ci4_test_dir_' . bin2hex(random_bytes(8)); $this->assertTrue(mkdir($tempDir)); $extremeName = 'my_extreme_file_!@#$%.txt';