diff --git a/apps/files_trashbin/lib/Trashbin.php b/apps/files_trashbin/lib/Trashbin.php index bdd7323d4a2a5..eef6e9c2fd4ce 100644 --- a/apps/files_trashbin/lib/Trashbin.php +++ b/apps/files_trashbin/lib/Trashbin.php @@ -1211,12 +1211,13 @@ public static function getTrashFilename(string $filename, int $timestamp): strin // oc_filecache `name` column has a limit of 250 chars $maxLength = 250; if ($length > $maxLength) { - $trashFilename = substr_replace( - $trashFilename, - '', - $maxLength / 2, - $length - $maxLength - ); + // truncate at the middle, since the last characters are fairly likely to have meaningful information such as version numbering + + $charsToRemove = $length - $maxLength + 1; + $charLength = mb_strlen($trashFilename); + $start = mb_substr($trashFilename, 0, floor(($charLength / 2) - $charsToRemove)); + $end = mb_substr($trashFilename, floor($charLength / 2)); + return $start . '_' . $end; } return $trashFilename; } diff --git a/apps/files_trashbin/tests/TrashbinTest.php b/apps/files_trashbin/tests/TrashbinTest.php index b6bb552517773..b2233bc2509ac 100644 --- a/apps/files_trashbin/tests/TrashbinTest.php +++ b/apps/files_trashbin/tests/TrashbinTest.php @@ -32,6 +32,7 @@ use OCP\IUserManager; use OCP\Server; use OCP\Share\IShare; +use PHPUnit\Framework\Attributes\DataProvider; /** * Class Test_Encryption @@ -706,6 +707,33 @@ public static function loginHelper($user, $create = false) { \OC_Util::setupFS($user); Server::get(IRootFolder::class)->getUserFolder($user); } + + public static function trashFilenameProvider(): array { + return [ + ['foo.txt', 'foo.txt.d1234'], + [ + 'a_very_long_filename_with_a_lot_a_characters_such_that_it_reaches_the_file_length_limit_and_would_cause_issues_if_we_just_appended_the_' . + 'timestamp_because_then_the_combined_length_would_overflow_the_column_limit_of_the_filecache_and_truncate_in_db.txt', + 'a_very_long_filename_with_a_lot_a_characters_such_that_it_reaches_the_file_length_limit_and_would_cause_issues_if_we_just_ded_the_' . + 'timestamp_because_then_the_combined_length_would_overflow_the_column_limit_of_the_filecache_and_truncate_in_db.txt.d1234' + ], + [ + 'a_very_long_filename_with_a_lot_a_characters_such_that_it_reaches_the_file_length_limit_and_would_cause_issues_if_we_just_äøšá_the_' . + 'timestamp_because_then_the_combined_length_would_overflow_the_column_limit_of_the_filecache_and_truncate_in_db.txt', + 'a_very_long_filename_with_a_lot_a_characters_such_that_it_reaches_the_file_length_limit_and_would_cause_issues_if_we_ju_á_the_' . + 'timestamp_because_then_the_combined_length_would_overflow_the_column_limit_of_the_filecache_and_truncate_in_db.txt.d1234' + ], + ]; + } + + + #[DataProvider(methodName: 'trashFilenameProvider')] + public function testGetTrashFilename(string $filename, string $expected): void { + $result = Trashbin::getTrashFilename($filename, 1234); + $this->assertTrue(mb_check_encoding($result, 'UTF-8')); + $this->assertEquals($expected, $result); + $this->assertTrue(strlen($result) <= 250); + } } // just a dummy class to make protected methods available for testing