Proper path manipulation in PHP - php

Here are some things I have done in PHP:
$normalizedPath = rtrim($path, '/');
$fullPath = $path . '/' . $basename;
Is there a better class or function to do this where I do not need to hardcode / into my application? Hopefully this will work with unicode and CJK characters.

You should use realpath() function.
Check pathinfo function too, it may be useful

No there are no functions to assemble a path.
Since PHP supports both, the Windows style paths and the UNIX style paths, the rtrim() statement will not work if $path is a Windows style path. You can use realpath() to work around this, but realpath() has the drawback that it returns an absolute path which might be not desired and it returns false for non existing paths, which might be a problem as well in cases were you build a path for something that should be created but does not already exist.

Related

php can't find class [duplicate]

require_once dirname(__FILE__).DIRECTORY_SEPARATOR . './../../../wp-config.php';
require_once dirname(__FILE__).DIRECTORY_SEPARATOR.'inc/options.php';
The above code is from a plugin from the Wordpress.
I don't understand why half of it uses DIRECTORY_SEPARATOR, but the other half uses "/" ?
Because in different OS there is different directory separator. In Windows it's \ in Linux it's /. DIRECTORY_SEPARATOR is constant with that OS directory separator. Use it every time in paths.
In you code snippet we clearly see bad practice code. If framework/cms are widely used it doesn't mean that it's using best practice code.
All of the PHP IO functions will internally convert slashes to the appropriate character, so it's not a huge deal which method you use. Below are some things to consider.
It can look ugly and confusing when you print out your file paths and there is a mix of \ and /. This won't ever happen if DIRECTORY_SEPARATOR is used
Using something such as $generated_css = DIRECTORY_SEPARATOR.'minified.css'; will work all fine and dandy for file IO, but if a developer unknowingly references it in a URL such as echo "<link rel='stylesheet'href='https:​//example.com$generated_css'>";, a bug was just created. Did you catch it? While this will work on Windows, for everyone else a forward slash, instead of a backslash, will be in $generated_css, resulting in the percent encoded, non-existant, URL https://example.com%5cgenerated_css! When using a DIRECTORY_SEPARATOR you have to take special care to make sure your filepath variables never end up in a URL.
And lastly, in the unlikely scenario your filepath is used by non-PHP code — for example, in a shell_exec call — you won't be able to mix slashes and will need to either construct the filepath with DIRECTORY_SEPARATOR or use realpath.
I learned from distributing code that the best way for your application to run on both Linux and Windows is to never use DIRECTORY_SEPARATOR, or backslashes \\, and to ONLY use forward slashes /.
Why? Because a backslash directory separator ONLY works on Windows. And forward slashes works on ALL (Linux, Windows, Mac altogether).
Using the constant DIRECTORY_SEPARATOR or escaping your backslashes \\ quickly becomes messy. I mean look at it:
$file = 'path' . DIRECTORY_SEPARATOR . 'to' . DIRECTORY_SEPARATOR . 'file';
$file = str_replace('/', DIRECTORY_SEPARATOR, 'path/to/file';
$file = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? 'path\\to\\file' : 'path/to/file';
When you can just do this:
$file = 'path/to/file';
The only downside is that on Windows; PHP will return backslashes for all file references from functions like realpath(), glob(), and magic constants like __FILE__ and __DIR__. So you might need to str_replace() them into forward slashes to keep it consistant.
$dir = str_replace('\\', '/', realpath('../'));
I wish there was a php.ini setting to always return forward slashes.
Do not use your own folder separators. Always use DIRECTORY_SEPARATOR, because:
In some special cases you really need the correct path delimiter
The OS might handle it correctly, but many 3rd party applications can't and might fail!
Some operating systems do not use / or \ as separators but something different
Don't forget: Use the constant only on the remote system - don't use it for URIs or anything else that you want to send to the client (except you really need it, like a "remote browser").

realpath vs str_replace to normalize slashes

Say I have a badly formatted path /public/var/www/html/images\uploads\
Are there any performance benefits between these two methods to "normalize" the slashes, or is it just a different way of doing things?
realpath($path) . DIRECTORY_SEPARATOR
str_replace('\\', '/', $path);
realpath() might and probably does take a tad more computation but it is doing more than str_replace() would. As to which you would use is up to you and depends on the application. realpath() will not only fix the format of strings.. but will also verify that a file exists by that name. Also, using realpath() will, in most cases, make your code more readable and easier to understand because it's naming better corresponds to it's functionality here (depending, again, on the application).
realpath()

When to use DIRECTORY_SEPARATOR in PHP code?

require_once dirname(__FILE__).DIRECTORY_SEPARATOR . './../../../wp-config.php';
require_once dirname(__FILE__).DIRECTORY_SEPARATOR.'inc/options.php';
The above code is from a plugin from the Wordpress.
I don't understand why half of it uses DIRECTORY_SEPARATOR, but the other half uses "/" ?
Because in different OS there is different directory separator. In Windows it's \ in Linux it's /. DIRECTORY_SEPARATOR is constant with that OS directory separator. Use it every time in paths.
In you code snippet we clearly see bad practice code. If framework/cms are widely used it doesn't mean that it's using best practice code.
All of the PHP IO functions will internally convert slashes to the appropriate character, so it's not a huge deal which method you use. Below are some things to consider.
It can look ugly and confusing when you print out your file paths and there is a mix of \ and /. This won't ever happen if DIRECTORY_SEPARATOR is used
Using something such as $generated_css = DIRECTORY_SEPARATOR.'minified.css'; will work all fine and dandy for file IO, but if a developer unknowingly references it in a URL such as echo "<link rel='stylesheet'href='https:​//example.com$generated_css'>";, a bug was just created. Did you catch it? While this will work on Windows, for everyone else a forward slash, instead of a backslash, will be in $generated_css, resulting in the percent encoded, non-existant, URL https://example.com%5cgenerated_css! When using a DIRECTORY_SEPARATOR you have to take special care to make sure your filepath variables never end up in a URL.
And lastly, in the unlikely scenario your filepath is used by non-PHP code — for example, in a shell_exec call — you won't be able to mix slashes and will need to either construct the filepath with DIRECTORY_SEPARATOR or use realpath.
I learned from distributing code that the best way for your application to run on both Linux and Windows is to never use DIRECTORY_SEPARATOR, or backslashes \\, and to ONLY use forward slashes /.
Why? Because a backslash directory separator ONLY works on Windows. And forward slashes works on ALL (Linux, Windows, Mac altogether).
Using the constant DIRECTORY_SEPARATOR or escaping your backslashes \\ quickly becomes messy. I mean look at it:
$file = 'path' . DIRECTORY_SEPARATOR . 'to' . DIRECTORY_SEPARATOR . 'file';
$file = str_replace('/', DIRECTORY_SEPARATOR, 'path/to/file';
$file = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? 'path\\to\\file' : 'path/to/file';
When you can just do this:
$file = 'path/to/file';
The only downside is that on Windows; PHP will return backslashes for all file references from functions like realpath(), glob(), and magic constants like __FILE__ and __DIR__. So you might need to str_replace() them into forward slashes to keep it consistant.
$dir = str_replace('\\', '/', realpath('../'));
I wish there was a php.ini setting to always return forward slashes.
Do not use your own folder separators. Always use DIRECTORY_SEPARATOR, because:
In some special cases you really need the correct path delimiter
The OS might handle it correctly, but many 3rd party applications can't and might fail!
Some operating systems do not use / or \ as separators but something different
Don't forget: Use the constant only on the remote system - don't use it for URIs or anything else that you want to send to the client (except you really need it, like a "remote browser").

Slashes and backslashes uniformity on UNIX / Windows

I'm writing a PHP class, and I want it to be cross-platform compatible. I need to explode a path to find a particular folder name. What do I choose for the delimiter? The path will contain '/' on UNIX and '\' on Windows.
In this particular example, I want to get the name of the directory where an included file is stored. I use this :
private function find_lib_dir() {
$array_path = explode('/', __DIR__);
return $array_path[count($array_path)-1];
}
In this situation (and more generally), what can I do to make sure it will work on both Windows and UNIX?
Thanks!
You can use DIRECTORY_SEPARATOR as follows:
$array_path = explode(DIRECTORY_SEPARATOR, __DIR__);
Use basename() and dirname() for path manipulation instead of parsing it yourself.
I would do something like this:
private function find_lib_dir() {
// convert windows backslashes into forward slashes
$dir = str_replace("\\", "/", __DIR__);
$array_path = explode('/', $dir);
return $array_path[count($array_path)-1];
}
For your particular example, you could do what the other answers provided. However, if you are building strings yourself like:
__DIR__ . '/path/to/dir';
And then try to explode it, then you will have issues on UNIX vs Windows systems. In this situation, it would be best (imo) to replace all the backslashes to forward slashes (which is supported on both systems). And then explode based on forward slash.
You should use the DIRECTORY_SEPARATOR constant

How do I properly split a PATH variable in PHP?

I want to split
$path = getenv('PATH');
into its components. How do I determine the separator char in an os-dependent fashion?
You can use the PATH_SEPARATOR constant, then the DIRECTORY_SEPARATOR constant to split the path if needed.
See Directory Predefined Constants
Use the PATH_SEPARATOR constant.
I know this works for the include_path - not sure about getenv('PATH'):
$paths = split(PATH_SEPARATOR, getenv('PATH'));
I seem to remember that Windows will accept both forward- and back-slashes as a file-separator, so you may not have to worry about it.

Categories