8000 [Filesystem] Add Path::normalizeForCurrentOs() for platform-aware normalization by Exsol · Pull Request #63216 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content
Closed
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
[Filesystem] Add Path::normalizeForCurrentOs() for platform-aware nor…
…malization

On Unix-like systems, backslash is a valid character in filenames, not a
directory separator. The existing normalize() method always replaces
backslashes for cross-platform compatibility.

This adds a new method that only normalizes backslashes on Windows,
preserving them on Unix where they may be part of filenames.
  • Loading branch information
Exsol committed Jan 27, 2026
commit 7f41c4154098f50273a30b1ad4be33f590943d96
5 changes: 5 additions & 0 deletions src/Symfony/Component/Filesystem/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

6.4
---

* Add `Path::normalizeForCurrentOs()` to normalize paths according to the current OS conventions

5.4
---

Expand Down
27 changes: 27 additions & 0 deletions src/Symfony/Component/Filesystem/Path.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,39 @@ public static function canonicalize(string $path): string
* path.
*
* This method is able to deal with both UNIX and Windows paths.
*
* @see normalizeForCurrentOs() for platform-aware normalization
*/
public static function normalize(string $path): string
{
return str_replace('\\', '/', $path);
}

/**
* Normalizes the given path for the current operating system.
*
* On Windows, backslashes are replaced by forward slashes.
* On Unix-like systems, the path is returned unchanged because backslash
* is a valid character in filenames, not a directory separator.
*
* Use this method when working with paths from the local filesystem.
* Use {@link normalize()} for cross-platform path handling.
*
* ```php
* // On Unix: filenames can contain backslashes
* Path::normalizeForCurrentOs('foo\\bar');
* // => foo\bar (unchanged, valid filename)
*
* // On Windows: backslash is a directory separator
* Path::normalizeForCurrentOs('foo\\bar');
* // => foo/bar (normalized)
* ```
*/
public static function normalizeForCurrentOs(string $path): string
{
return '\\' === \DIRECTORY_SEPARATOR ? str_replace('\\', '/', $path) : $path;
}

/**
* Returns the directory part of the path.
*
Expand Down
39 changes: 39 additions & 0 deletions src/Symfony/Component/Filesystem/Tests/PathTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1056,4 +1056,43 @@ public function testNormalize()
{
$this->assertSame('C:/Foo/Bar/test', Path::normalize('C:\\Foo\\Bar/test'));
}

/**
* @dataProvider provideNormalizeForCurrentOsTests
*/
public function testNormalizeForCurrentOs(string $path, string $expectedOnWindows, string $expectedOnUnix)
{
$expected = '\\' === \DIRECTORY_SEPARATOR ? $expectedOnWindows : $expectedOnUnix;
$this->assertSame($expected, Path::normalizeForCurrentOs($path));
}

public static function provideNormalizeForCurrentOsTests(): \Generator
{
// [input, expected on Windows, expected on Unix]

// Forward slashes are never changed
yield ['foo/bar', 'foo/bar', 'foo/bar'];
yield ['/absolute/path', '/absolute/path', '/absolute/path'];

// Backslashes: converted on Windows, preserved on Unix
yield ['foo\\bar', 'foo/bar', 'foo\\bar'];
yield ['foo\\bar\\baz', 'foo/bar/baz', 'foo\\bar\\baz'];

// Mixed slashes
yield ['foo\\bar/baz', 'foo/bar/baz', 'foo\\bar/baz'];

// Windows absolute paths
yield ['C:\\Windows\\System32', 'C:/Windows/System32', 'C:\\Windows\\System32'];

// UNC paths
yield ['\\\\server\\share', '//server/share', '\\\\server\\share'];

// Empty and dot paths
yield ['', '', ''];
yield ['.', '.', '.'];
yield ['..', '..', '..'];

// Unix paths with backslash in filename (valid on Unix)
yield ['/path/to/file\\name', '/path/to/file/name', '/path/to/file\\name'];
}
}
0