From fa1c3db5b26f9703cadfb9188932f530a2fd9dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Miklu=C5=A1ek?= Date: Fri, 24 Jul 2026 17:59:15 +0200 Subject: [PATCH 1/2] Fix multibyte case-insensitive matching in Str::replace and Str::remove --- src/Illuminate/Support/Str.php | 47 ++++++++++++++++++++++++++++++-- tests/Support/SupportStrTest.php | 8 ++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 7cfa81d329e8..1b7da0f5e03b 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -1286,7 +1286,50 @@ public static function replace($search, $replace, $subject, $caseSensitive = tru return $caseSensitive ? str_replace($search, $replace, $subject) - : str_ireplace($search, $replace, $subject); + : static::replaceIgnoreCase($search, $replace, $subject); + } + + /** + * Replace the given value in the given string regardless of case. + * + * @param string|iterable $search + * @param string|iterable $replace + * @param string|iterable $subject + * @return string|string[] + */ + protected static function replaceIgnoreCase($search, $replace, $subject) + { + $searches = is_array($search) ? array_values($search) : [$search]; + + if (static::isAscii(implode('', $searches))) { + return str_ireplace($search, $replace, $subject); + } + + foreach ((array) $subject as $value) { + if (! preg_match('//u', (string) $value)) { + return str_ireplace($search, $replace, $subject); + } + } + + $replacements = is_array($replace) + ? array_values($replace) + : array_fill(0, count($searches), $replace); + + foreach ($searches as $index => $term) { + if ((string) $term === '') { + continue; + } + + $replacement = (string) ($replacements[$index] ?? ''); + + $subject = preg_replace_callback( + '/'.preg_quote((string) $term, '/').'/iu', + fn () => $replacement, + $subject + ); + } + + return $subject; } /** @@ -1419,7 +1462,7 @@ public static function remove($search, $subject, $caseSensitive = true) return $caseSensitive ? str_replace($search, '', $subject) - : str_ireplace($search, '', $subject); + : static::replaceIgnoreCase($search, '', $subject); } /** diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index b6a820b12078..2e9edc44607f 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -945,6 +945,11 @@ public function testReplace() $this->assertSame('foo/bar/baz', Str::replace(' ', '/', 'foo bar baz')); $this->assertSame('foo bar baz', Str::replace(['?1', '?2', '?3'], ['foo', 'bar', 'baz'], '?1 ?2 ?3')); $this->assertSame(['foo', 'bar', 'baz'], Str::replace(collect(['?1', '?2', '?3']), collect(['foo', 'bar', 'baz']), collect(['?1', '?2', '?3']))); + + $this->assertSame('Xltý kôň', Str::replace('ž', 'X', 'Žltý kôň', false)); + $this->assertSame('žltý pes', Str::replace('KÔŇ', 'pes', 'žltý kôň', false)); + $this->assertSame('Xltý pes', Str::replace(['ž', 'KÔŇ'], ['X', 'pes'], 'Žltý kôň', false)); + $this->assertSame(['Xltý', 'kôň'], Str::replace('ž', 'X', ['Žltý', 'kôň'], false)); } public function testReplaceArray() @@ -1026,6 +1031,9 @@ public function testRemove() $this->assertSame('Fooar', Str::remove(['f', 'b'], 'Foobar')); $this->assertSame('ooar', Str::remove(['f', 'b'], 'Foobar', false)); $this->assertSame('Foobar', Str::remove(['f', '|'], 'Foo|bar')); + + $this->assertSame('ltý', Str::remove('ž', 'Žltý', false)); + $this->assertSame('žltý ', Str::remove('KÔŇ', 'žltý kôň', false)); } public function testReverse() From f7136ff8a0f43413e6ed979c10bad58c9e9e0ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Miklu=C5=A1ek?= Date: Fri, 24 Jul 2026 19:49:27 +0200 Subject: [PATCH 2/2] Fix docblock parameter types on replaceIgnoreCase --- src/Illuminate/Support/Str.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 1b7da0f5e03b..388bab96b05f 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -1292,9 +1292,9 @@ public static function replace($search, $replace, $subject, $caseSensitive = tru /** * Replace the given value in the given string regardless of case. * - * @param string|iterable $search - * @param string|iterable $replace - * @param string|iterable $subject + * @param array|string $search + * @param array|string $replace + * @param array|string $subject * @return string|string[] */ protected static function replaceIgnoreCase($search, $replace, $subject)