diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 1b6721bec4..8bf81c9da4 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -302,21 +302,28 @@ class Filesystem $startPath = strtr($startPath, '\\', '/'); } - // Find for which character the the common path stops - $offset = 0; - while (isset($startPath[$offset]) && isset($endPath[$offset]) && $startPath[$offset] === $endPath[$offset]) { - $offset++; + // Split the paths into arrays + $startPathArr = explode('/', trim($startPath, '/')); + $endPathArr = explode('/', trim($endPath, '/')); + + // Find for which directory the common path stops + $index = 0; + while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) { + $index++; } // Determine how deep the start path is relative to the common path (ie, "web/bundles" = 2 levels) - $diffPath = trim(substr($startPath, $offset), '/'); - $depth = strlen($diffPath) > 0 ? substr_count($diffPath, '/') + 1 : 0; + $depth = count($startPathArr) - $index; // Repeated "../" for each level need to reach the common path $traverser = str_repeat('../', $depth); + $endPathRemainder = implode('/', array_slice($endPathArr, $index)); + // Construct $endPath from traversing to the common path, then to the remaining $endPath - return $traverser.substr($endPath, $offset); + $relativePath = $traverser . (strlen($endPathRemainder) > 0 ? $endPathRemainder . '/' : ''); + + return (strlen($relativePath) === 0) ? './' : $relativePath; } /** diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index a29155c4bd..3a935e1885 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -733,6 +733,22 @@ class FilesystemTest extends \PHPUnit_Framework_TestCase array('var/lib/symfony/', 'var/lib/symfony/src/Symfony/Component', '../../../'), array('/usr/lib/symfony/', '/var/lib/symfony/src/Symfony/Component', '../../../../../../usr/lib/symfony/'), array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/', 'src/Symfony/'), + array('/aa/bb', '/aa/bb', './'), + array('/aa/bb', '/aa/bb/', './'), + array('/aa/bb/', '/aa/bb', './'), + array('/aa/bb/', '/aa/bb/', './'), + array('/aa/bb/cc', '/aa/bb/cc/dd', '../'), + array('/aa/bb/cc', '/aa/bb/cc/dd/', '../'), + array('/aa/bb/cc/', '/aa/bb/cc/dd', '../'), + array('/aa/bb/cc/', '/aa/bb/cc/dd/', '../'), + array('/aa/bb/cc', '/aa', 'bb/cc/'), + array('/aa/bb/cc', '/aa/', 'bb/cc/'), + array('/aa/bb/cc/', '/aa', 'bb/cc/'), + array('/aa/bb/cc/', '/aa/', 'bb/cc/'), + array('/a/aab/bb', '/a/aa', '../aab/bb/'), + array('/a/aab/bb', '/a/aa/', '../aab/bb/'), + array('/a/aab/bb/', '/a/aa', '../aab/bb/'), + array('/a/aab/bb/', '/a/aa/', '../aab/bb/'), ); if (defined('PHP_WINDOWS_VERSION_MAJOR')) {