How to Get Filename With Extension From a File Path in PHP?

Using basename()

We can use basename() to return the filename and extension from a file path, since the function returns the trailing component from a string containing a path to a file or directory. To demonstrate how this works, let's look at a few examples:

// normal file
echo basename('/var/www/html/index.php'); // 'index.php'
// dotfile
echo basename('/var/httpd/.htaccess'); // '.htaccess'
// file with two extensions
echo basename('/usr/john.doe/my-file.tar.gz'); // 'my-file.tar.gz'
// file with no extension
echo basename('/var/www/DockerFile'); // 'DockerFile'
// path with no file
echo basename('/path/to/directory/'); // 'directory'
// current directory
echo basename('.'); // '.'
// root directory
echo basename('/'); // ''
// root directory with file
echo basename('/foo.txt'); // 'foo.txt'
// root directory with folder
echo basename('/foo/'); // 'foo'

Making basename() Work With Multibyte Characters:

Since basename() is locale-aware, it won't work with multibyte characters correctly till a matching locale is set first using the setlocale() function.

setlocale(LC_ALL, 'zh_CN.GBK');

echo basename('/var/www/字形.woff'); // '字形.woff'

Using pathinfo()

The pathinfo() function can be used to return information about a file path. Following are two ways in which we can retrieve the filename and extension from a file path using pathinfo():

echo pathinfo('/var/www/html/index.php', PATHINFO_BASENAME); // 'index.php'

We could have also used PATHINFO_FILENAME and PATHINFO_EXTENSION constants with pathinfo() to get filename and extension separately.

Or, the same can be written without passing an option as the second argument to pathinfo(), in which case it will return an associative array containing information about the file path. For example:

$pathInfo = pathinfo('/var/www/html/index.php');

echo $pathInfo['basename']; // 'index.php'

echo $pathInfo['filename']; // 'index'
echo $pathInfo['extension']; // 'php'

We could have also used $pathInfo['filename'] and $pathInfo['extension'] with pathinfo() to get filename and extension individually.

Let's take a look at few more examples:

// dotfile
$pathInfo = pathinfo('/var/httpd/.htaccess');

echo $pathInfo['basename']; // '.htaccess'

echo $pathInfo['filename']; // ''
echo $pathInfo['extension']; // 'htaccess'
// file with two extensions
$pathInfo = pathinfo('/usr/john.doe/my-file.tar.gz');

echo $pathInfo['basename']; // 'my-file.tar.gz'

echo $pathInfo['filename']; // 'my-file.tar'
echo $pathInfo['extension']; // 'gz'
// file with no extension
$pathInfo = pathinfo('/var/www/DockerFile');

echo $pathInfo['basename']; // 'DockerFile'

echo $pathInfo['filename']; // 'DockerFile'
echo $pathInfo['extension']; // ''
// path with no file
$pathInfo = pathinfo('/path/to/directory/');

echo $pathInfo['basename']; // 'directory'

echo $pathInfo['filename']; // 'directory'
echo $pathInfo['extension']; // ''
// current directory
$pathInfo = pathinfo('.');

echo $pathInfo['basename']; // '.'

echo $pathInfo['filename']; // ''
echo $pathInfo['extension']; // ''

In the example above, notice how basename returns . but neither filename nor extension do the same.

// root directory
$pathInfo = pathinfo('/');

echo $pathInfo['basename']; // ''

echo $pathInfo['filename']; // ''
echo $pathInfo['extension']; // ''
// root directory with file
$pathInfo = pathinfo('/foo.txt');

echo $pathInfo['basename']; // 'foo.txt'

echo $pathInfo['filename']; // 'foo'
echo $pathInfo['extension']; // 'txt'
// root directory with folder
$pathInfo = pathinfo('/foo/');

echo $pathInfo['basename']; // 'foo'

echo $pathInfo['filename']; // 'foo'
echo $pathInfo['extension']; // ''

Making pathinfo() Work With Multibyte Characters:

Since pathinfo() is locale-aware, it won't work with multibyte characters correctly till a matching locale is set first using the setlocale() function.

setlocale(LC_ALL, 'zh_CN.GBK');

$pathInfo = pathinfo('/var/www/字形.woff');

echo $pathInfo['basename']; // '字形.woff'

echo $pathInfo['filename']; // '字形'
echo $pathInfo['extension']; // 'woff'

Using explode() With DIRECTORY_SEPARATOR

Another clever way to get the filename with extension could be to only get the trailing component of the file path string by splitting it into an array by the directory separator. To see how this is done, let's consider the following examples:

// normal file
$pathChunks = explode(DIRECTORY_SEPARATOR, '/var/www/html/index.php');

echo end($pathChunks); // 'index.php'
// dotfile
$pathChunks = explode(DIRECTORY_SEPARATOR, '/var/httpd/.htaccess');

echo end($pathChunks); // '.htaccess'
// file with two extensions
$pathChunks = explode(DIRECTORY_SEPARATOR, '/usr/john.doe/my-file.tar.gz');

echo end($pathChunks); // 'my-file.tar.gz'
// file with no extension
$pathChunks = explode(DIRECTORY_SEPARATOR, '/var/www/DockerFile');

echo end($pathChunks); // 'DockerFile'
// path with no file
$pathChunks = explode(DIRECTORY_SEPARATOR, '/path/to/directory/');

echo end($pathChunks); // ''

The key difference of using explode() (for the purpose of getting the filename with extension) is the example above. Notice how this returns an empty string for a path ending with a directory separator. From the perspective of getting filename with an extension, this is presumably the correct behavior — i.e. returning the trailing component when string does not end with a directory separator and empty otherwise.

// current directory
$pathChunks = explode(DIRECTORY_SEPARATOR, '.');

echo end($pathChunks); // '.'
// root directory
$pathChunks = explode(DIRECTORY_SEPARATOR, '/');

echo end($pathChunks); // ''
// root directory with file
$pathChunks = explode(DIRECTORY_SEPARATOR, '/foo.txt');

echo end($pathChunks); // 'foo.txt'
// root directory with folder
$pathChunks = explode(DIRECTORY_SEPARATOR, '/foo/');

echo end($pathChunks); // ''

Working With Multibyte Characters:

Multibyte characters should work fine with explode() as long as the string contains well-formed multibyte sequences. However, if possible, it is always a better option to use locale aware or multibyte string functions when working with multibyte strings. In case of explode() you could potentially substitute it with mb_split().

$pathChunks = explode(DIRECTORY_SEPARATOR, '/var/www/字形.woff');

echo end($pathChunks); // '字形.woff'

Using the SplFileInfo Class

In the SplFileInfo class we have two methods that we can use to get the filename with extension:

  1. SplFileInfo::getBasename()
  2. SplFileInfo::getFilename()

While using either one, be cautious about the differences between the two as shown in some of the following examples:

// normal file
$info = new SplFileInfo('/var/www/html/index.php');

echo $info->getBasename(); // 'index.php'

echo $info->getFilename(); // 'index.php'
// dotfile
$info = new SplFileInfo('/var/httpd/.htaccess');

echo $info->getBasename(); // '.htaccess'

echo $info->getFilename(); // '.htaccess'
// file with two extensions
$info = new SplFileInfo('/usr/john.doe/my-file.tar.gz');

echo $info->getBasename(); // 'my-file.tar.gz'

echo $info->getFilename(); // 'my-file.tar.gz'
// file with no extension
$info = new SplFileInfo('/var/www/DockerFile');

echo $info->getBasename(); // 'DockerFile'

echo $info->getFilename(); // 'DockerFile'
// path with no file
$info = new SplFileInfo('/path/to/directory/');

echo $info->getBasename(); // 'directory'

echo $info->getFilename(); // 'directory'
// current directory
$info = new SplFileInfo('.');

echo $info->getBasename(); // '.'

echo $info->getFilename(); // '.'

For the following cases, notice how with getFilename() method there's a leading slash while with getBasename() there is none:

// root directory
$info = new SplFileInfo('/');

echo $info->getBasename(); // ''

echo $info->getFilename(); // '/'
// root directory with file
$info = new SplFileInfo('/foo.txt');

echo $info->getBasename(); // 'foo.txt'

echo $info->getFilename(); // '/foo.txt'
// root directory with folder
$info = new SplFileInfo('/foo/');

echo $info->getBasename(); // 'foo'

echo $info->getFilename(); // '/foo'

Making SplFileInfo Methods Work With Multibyte Characters:

According to the docs, SplFileInfo::getBasename() is locale-aware while SplFileInfo::getFilename() is not. This means that for SplFileInfo::getBasename() to work properly with multibyte characters, a matching locale needs to be set first using the setlocale() function.

setlocale(LC_ALL, 'zh_CN.GBK');

$info = new SplFileInfo('/var/www/字形.woff');

echo $info->getBasename(); // '字形.woff'
$info = new SplFileInfo('/var/www/字形.woff');

echo $info->getFilename(); // '字形.woff'

While the getFilename() method would work with some/most multibyte character encodings (i.e. as long as the string contains well-formed multibyte sequences), it might not yield the right results at times. Therefore, it is always a better option to use locale aware or multibyte string functions when working with multibyte strings.


This post was published by Daniyal Hamid. Daniyal currently works as the Head of Engineering in Germany and has 20+ years of experience in software engineering, design and marketing. Please show your love and support by sharing this post.