src/Path.php
public static function makeRelative($path, $basePath)
    {
        Assert::string($basePath, 'The base path must be a string. Got: %s');

        $path = static::canonicalize($path);
        $basePath = static::canonicalize($basePath);

        list($root, $relativePath) = self::split($path);
        list($baseRoot, $relativeBasePath) = self::split($basePath);

        // If the base path is given as absolute path and the path is already
        // relative, consider it to be relative to the given absolute path
        // already
        if ('' === $root && '' !== $baseRoot) {
            // If base path is already in its root
            if ('' === $relativeBasePath) {
                $relativePath = ltrim($relativePath, './\\');
            }

            return $relativePath;
        }

        // If the passed path is absolute, but the base path is not, we
        // cannot generate a relative path
        if ('' !== $root && '' === $baseRoot) {
            throw new InvalidArgumentException(sprintf(
                'The absolute path "%s" cannot be made relative to the '.
                'relative path "%s". You should provide an absolute base '.
                'path instead.',
                $path,
                $basePath
            ));
        }

        // Fail if the roots of the two paths are different
        if ($baseRoot && $root !== $baseRoot) {
            throw new InvalidArgumentException(sprintf(
                'The path "%s" cannot be made relative to "%s", because they '.
                'have different roots ("%s" and "%s").',
                $path,
                $basePath,
                $root,
                $baseRoot
            ));
        }

        if ('' === $relativeBasePath) {
            return $relativePath;
        }

        // Build a "../../" prefix with as many "../" parts as necessary
        $parts = explode('/', $relativePath);
        $baseParts = explode('/', $relativeBasePath);
        $dotDotPrefix = '';

        // Once we found a non-matching part in the prefix, we need to add
        // "../" parts for all remaining parts
        $match = true;

        foreach ($baseParts as $i => $basePart) {
            if ($match && isset($parts[$i]) && $basePart === $parts[$i]) {
                unset($parts[$i]);

                continue;
            }

            $match = false;
            $dotDotPrefix .= '../';
        }

        return rtrim($dotDotPrefix.implode('/', $parts), '/');
    }
public static function makeRelative($path, $basePath)
    {
        Assert::string($basePath, 'The base path must be a string. Got: %s');

        $path = static::canonicalize($path);
        $basePath = static::canonicalize($basePath);

        list($root, $relativePath) = self::split($path);
        list($baseRoot, $relativeBasePath) = self::split($basePath);

        // If the base path is given as absolute path and the path is already
        // relative, consider it to be relative to the given absolute path
        // already
        if ('' === $root && '' !== $baseRoot) {
            // If base path is already in its root
            if ('' === $relativeBasePath) {
                $relativePath = ltrim($relativePath, './\\');
            }

            return $relativePath;
        }

        // If the passed path is absolute, but the base path is not, we
        // cannot generate a relative path
        if ('' !== $root && '' === $baseRoot) {
            throw new InvalidArgumentException(sprintf(
                'The absolute path "%s" cannot be made relative to the '.
                'relative path "%s". You should provide an absolute base '.
                'path instead.',
                $path,
                $basePath
            ));
        }

        // Fail if the roots of the two paths are different
        if ($baseRoot && $root !== $baseRoot) {
            throw new InvalidArgumentException(sprintf(
                'The path "%s" cannot be made relative to "%s", because they '.
                'have different roots ("%s" and "%s").',
                $path,
                $basePath,
                $root,
                $baseRoot
            ));
        }

        if ('' === $relativeBasePath) {
            return $relativePath;
        }

        // Build a "../../" prefix with as many "../" parts as necessary
        $parts = explode('/', $relativePath);
        $baseParts = explode('/', $relativeBasePath);
        $dotDotPrefix = '';

        // Once we found a non-matching part in the prefix, we need to add
        // "../" parts for all remaining parts
        $match = true;

        foreach ($baseParts as $i => $basePart) {
            if ($match && isset($parts[$i]) && $basePart === $parts[$i]) {
                unset($parts[$i]);

                continue;
            }

            $match = false;
            $dotDotPrefix .= '../';
        }

        return rtrim($dotDotPrefix.implode('/', $parts), '/');
    }
public static function makeRelative ( $ path , $ basePath ) { Assert :: string ( $ basePath , 'The base path must be a string. Got: %s' ) ; $ path = static :: canonicalize ( $ path ) ; $ basePath = static :: canonicalize ( $ basePath ) ; list ( $ root , $ relativePath ) = self :: split ( $ path ) ; list ( $ baseRoot , $ relativeBasePath ) = self :: split ( $ basePath ) ; // If the base path is given as absolute path and the path is already // relative, consider it to be relative to the given absolute path // already if ( '' === $ root && '' !== $ baseRoot ) { // If base path is already in its root if ( '' === $ relativeBasePath ) { $ relativePath = ltrim ( $ relativePath , './\\' ) ; } return $ relativePath ; } // If the passed path is absolute, but the base path is not, we // cannot generate a relative path if ( '' !== $ root && '' === $ baseRoot ) { throw new InvalidArgumentException ( sprintf ( 'The absolute path "%s" cannot be made relative to the ' . 'relative path "%s". You should provide an absolute base ' . 'path instead.' , $ path , $ basePath ) ) ; } // Fail if the roots of the two paths are different if ( $ baseRoot && $ root !== $ baseRoot ) { throw new InvalidArgumentException ( sprintf ( 'The path "%s" cannot be made relative to "%s", because they ' . 'have different roots ("%s" and "%s").' , $ path , $ basePath , $ root , $ baseRoot ) ) ; } if ( '' === $ relativeBasePath ) { return $ relativePath ; } // Build a "../../" prefix with as many "../" parts as necessary $ parts = explode ( '/' , $ relativePath ) ; $ baseParts = explode ( '/' , $ relativeBasePath ) ; $ dotDotPrefix = '' ; // Once we found a non-matching part in the prefix, we need to add // "../" parts for all remaining parts $ match = true ; foreach ( $ baseParts as $ i => $ basePart ) { if ( $ match && isset ( $ parts [ $ i ] ) && $ basePart === $ parts [ $ i ] ) { unset ( $ parts [ $ i ] ) ; continue ; } $ match = false ; $ dotDotPrefix .= '../' ; } return rtrim ( $ dotDotPrefix . implode ( '/' , $ parts ) , '/' ) ; }
Turns a path into a relative path.

The relative path is created relative to the given base path:

```php
echo Path::makeRelative("/webmozart/style.css", "/webmozart/puli");
// => ../style.css
```

If a relative path is passed and the base path is absolute, the relative
path is returned unchanged:

```php
Path::makeRelative("style.css", "/webmozart/puli/css");
// => style.css
```

If both paths are relative, the relative path is created with the
assumption that both paths are relative to the same directory:

```php
Path::makeRelative("style.css", "webmozart/puli/css");
// => ../../../style.css
```

If both paths are absolute, their root directory must be the same,
otherwise an exception is thrown:

```php
Path::makeRelative("C:/webmozart/style.css", "/webmozart/puli");
// InvalidArgumentException
```

If the passed path is absolute, but the base path is not, an exception
is thrown as well:

```php
Path::makeRelative("/webmozart/style.css", "webmozart/puli");
// InvalidArgumentException
```

If the base path is not an absolute path, an exception is thrown.

The result is a canonical path.

@param string $path     A path to make relative.
@param string $basePath A base path.

@return string A relative path in canonical form.

@throws InvalidArgumentException If the base path is not absolute or if
the given path has a different root
than the base path.

@since 1.0 Added method.
@since 2.0 Method now fails if $path or $basePath is not a string.
Turns a path into a relative path .