Dealing with file paths usually involves some difficulties:
-
System Heterogeneity: File paths look different on different platforms. UNIX file paths start with a slash ("/"), while Windows file paths start with a system drive ("C:"). UNIX uses forward slashes, while Windows uses backslashes by default ("").
-
Absolute/Relative Paths: Web applications frequently need to deal with absolute and relative paths. Converting one to the other properly is tricky and repetitive.
This package provides few, but robust utility methods to simplify your life when dealing with file paths.
Canonicalization is the transformation of a path into a normalized (the
"canonical") format. You can canonicalize a path with Path::canonicalize()
:
echo Path::canonicalize('/var/www/vhost/webmozart/../config.ini');
// => /var/www/vhost/config.ini
The following modifications happen during canonicalization:
- "." segments are removed;
- ".." segments are resolved;
- backslashes ("") are converted into forward slashes ("/");
- root paths ("/" and "C:/") always terminate with a slash;
- non-root paths never terminate with a slash;
- schemes (such as "phar://") are kept;
- replace "~" with the user's home directory.
You can pass absolute paths and relative paths to canonicalize()
. When a
relative path is passed, ".." segments at the beginning of the path are kept:
echo Path::canonicalize('../uploads/../config/config.yml');
// => ../config/config.yml
Malformed paths are returned unchanged:
echo Path::canonicalize('C:Programs/PHP/php.ini');
// => C:Programs/PHP/php.ini
Absolute/relative paths can be converted with the methods Path::makeAbsolute()
and Path::makeRelative()
.
makeAbsolute()
expects a relative path and a base path to base that relative
path upon:
echo Path::makeAbsolute('config/config.yml', '/var/www/project');
// => /var/www/project/config/config.yml
If an absolute path is passed in the first argument, the absolute path is returned unchanged:
echo Path::makeAbsolute('/usr/share/lib/config.ini', '/var/www/project');
// => /usr/share/lib/config.ini
The method resolves ".." segments, if there are any:
echo Path::makeAbsolute('../config/config.yml', '/var/www/project/uploads');
// => /var/www/project/config/config.yml
This method is very useful if you want to be able to accept relative paths (for example, relative to the root directory of your project) and absolute paths at the same time.
makeRelative()
is the inverse operation to makeAbsolute()
:
echo Path::makeRelative('/var/www/project/config/config.yml', '/var/www/project');
// => config/config.yml
If the path is not within the base path, the method will prepend ".." segments as necessary:
echo Path::makeRelative('/var/www/project/config/config.yml', '/var/www/project/uploads');
// => ../config/config.yml
Use isAbsolute()
and isRelative()
to check whether a path is absolute or
relative:
Path::isAbsolute('C:\Programs\PHP\php.ini')
// => true
All four methods internally canonicalize the passed path.
When you store absolute file paths on the file system, this leads to a lot of duplicated information:
return array(
'/var/www/vhosts/project/httpdocs/config/config.yml',
'/var/www/vhosts/project/httpdocs/config/routing.yml',
'/var/www/vhosts/project/httpdocs/config/services.yml',
'/var/www/vhosts/project/httpdocs/images/banana.gif',
'/var/www/vhosts/project/httpdocs/uploads/images/nicer-banana.gif',
);
Especially when storing many paths, the amount of duplicated information is
noticeable. You can use Path::getLongestCommonBasePath()
to check a list of
paths for a common base path:
$paths = array(
'/var/www/vhosts/project/httpdocs/config/config.yml',
'/var/www/vhosts/project/httpdocs/config/routing.yml',
'/var/www/vhosts/project/httpdocs/config/services.yml',
'/var/www/vhosts/project/httpdocs/images/banana.gif',
'/var/www/vhosts/project/httpdocs/uploads/images/nicer-banana.gif',
);
Path::getLongestCommonBasePath($paths);
// => /var/www/vhosts/project/httpdocs
Use this path together with Path::makeRelative()
to shorten the stored paths:
$bp = '/var/www/vhosts/project/httpdocs';
return array(
$bp.'/config/config.yml',
$bp.'/config/routing.yml',
$bp.'/config/services.yml',
$bp.'/images/banana.gif',
$bp.'/uploads/images/nicer-banana.gif',
);
getLongestCommonBasePath()
always returns canonical paths.
Use Path::isBasePath()
to test whether a path is a base path of another path:
Path::isBasePath("/var/www", "/var/www/project");
// => true
Path::isBasePath("/var/www", "/var/www/project/..");
// => true
Path::isBasePath("/var/www", "/var/www/project/../..");
// => false
PHP offers the function dirname()
to obtain the directory path of a file path.
This method has a few quirks:
dirname()
does not accept backslashes on UNIXdirname("C:/Programs")
returns "C:", not "C:/"dirname("C:/")
returns ".", not "C:/"dirname("C:")
returns ".", not "C:/"dirname("Programs")
returns ".", not ""dirname()
does not canonicalize the result
Path::getDirectory()
fixes these shortcomings:
echo Path::getDirectory("C:\Programs");
// => C:/
Additionally, you can use Path::getRoot()
to obtain the root of a path:
echo Path::getRoot("/etc/apache2/sites-available");
// => /
echo Path::getRoot("C:\Programs\Apache\Config");
// => C:/