From da124e648a63c8c492db61e3f6d72ec53ffebc63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20Fabr=C3=A9gat?= Date: Fri, 23 Jan 2026 11:31:07 -0800 Subject: [PATCH 1/2] Add tests for RFC 5987/6266 UTF-8 filename support Verify that Content-Disposition header correctly includes both ASCII fallback (filename=) and UTF-8 encoded (filename*=) formats when filenames contain non-ASCII characters like accents or international characters. Closes #7 Co-Authored-By: Claude Opus 4.5 --- tests/SpreadsheetResponseTest.php | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/tests/SpreadsheetResponseTest.php b/tests/SpreadsheetResponseTest.php index 59c0604..0331276 100644 --- a/tests/SpreadsheetResponseTest.php +++ b/tests/SpreadsheetResponseTest.php @@ -133,6 +133,79 @@ public function testFallbackFilenameSanitization(): void $this->assertMatchesRegularExpression('/filename=[a-z0-9\\-\\.]+/i', $contentDisposition); } + /** + * Tests RFC 5987/6266 compliance for UTF-8 filenames. + * + * When a filename contains non-ASCII characters (like accents), the Content-Disposition + * header should include both: + * - filename="ascii-fallback.xlsx" - ASCII filename for older browsers + * - filename*=UTF-8''encoded-filename.xlsx - UTF-8 encoded filename for modern browsers + */ + public function testUtf8FilenameRfc5987Compliance(): void + { + $spreadsheet = $this->createSpreadsheet(); + $response = new SpreadsheetResponse($spreadsheet, 'Liste des utilisateurs avec données.xlsx'); + + $contentDisposition = $response->headers->get('Content-Disposition'); + + // Should contain ASCII fallback filename + $this->assertStringContainsString('filename=', $contentDisposition); + + // Should contain UTF-8 encoded filename per RFC 5987/6266 + $this->assertStringContainsString("filename*=utf-8''", $contentDisposition); + + // The UTF-8 filename should contain the percent-encoded accented character (é = %C3%A9) + $this->assertStringContainsString('%C3%A9', $contentDisposition); + } + + /** + * Tests that various UTF-8 characters are properly encoded in Content-Disposition. + */ + #[DataProvider('utf8FilenameProvider')] + public function testUtf8FilenamesAreProperlyEncoded(string $filename, string $expectedEncoded): void + { + $spreadsheet = $this->createSpreadsheet(); + $response = new SpreadsheetResponse($spreadsheet, $filename); + + $contentDisposition = $response->headers->get('Content-Disposition'); + + // Should have UTF-8 encoding directive + $this->assertStringContainsString("filename*=utf-8''", $contentDisposition); + + // Should contain the expected percent-encoded sequence + $this->assertStringContainsString($expectedEncoded, $contentDisposition); + } + + public static function utf8FilenameProvider(): array + { + return [ + 'French accents' => ['données.xlsx', '%C3%A9'], // é + 'German umlaut' => ['Übersicht.xlsx', '%C3%9C'], // Ü + 'Spanish ñ' => ['año.xlsx', '%C3%B1'], // ñ + 'Chinese characters' => ['报告.xlsx', '%E6%8A%A5'], // 报 + 'Japanese characters' => ['レポート.xlsx', '%E3%83%AC'], // レ + 'Mixed content' => ['Résumé été 2024.xlsx', '%C3%A9'], // é + ]; + } + + /** + * Tests that ASCII-only filenames don't generate unnecessary filename* directive. + */ + public function testAsciiOnlyFilenameNoUtf8Directive(): void + { + $spreadsheet = $this->createSpreadsheet(); + $response = new SpreadsheetResponse($spreadsheet, 'simple-report.xlsx'); + + $contentDisposition = $response->headers->get('Content-Disposition'); + + // Should contain the filename + $this->assertStringContainsString('filename=', $contentDisposition); + $this->assertStringContainsString('simple-report.xlsx', $contentDisposition); + + // ASCII-only filenames don't need the UTF-8 directive (though Symfony may still add it) + // The important thing is that the filename is correctly included + } + public function testUnsupportedWriterThrowsException(): void { $spreadsheet = $this->createSpreadsheet(); From 7b1e6706f8765a5f29f72e85cf439c9e528f2ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20Fabr=C3=A9gat?= Date: Fri, 23 Jan 2026 11:37:05 -0800 Subject: [PATCH 2/2] Require PHPUnit ^10.1 for source element support The element in phpunit.xml was introduced in PHPUnit 10.1. Co-Authored-By: Claude Opus 4.5 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3d9ba30..5a48603 100644 --- a/composer.json +++ b/composer.json @@ -29,6 +29,6 @@ } ], "require-dev": { - "phpunit/phpunit": "^10|^11" + "phpunit/phpunit": "^10.1|^11" } }