pathinfo
Splits a file path into its directory, base name, extension and file name components.
pathinfo(string $path, int $flags = PATHINFO_ALL): array|string- Added in PHP 4.0.3
Parameters
| Parameter | Type | Description |
|---|---|---|
$path | string | The path to parse. It is treated as text only — the file does not need to exist. |
$flagsoptional | int= PATHINFO_ALL | PATHINFO_DIRNAME, PATHINFO_BASENAME, PATHINFO_EXTENSION or PATHINFO_FILENAME to return just that component; PATHINFO_ALL returns the full array. |
Return value
array|stringAn associative array with dirname, basename, extension (only if one is present) and filename keys; a single string when one PATHINFO_* flag is given.
Errors
Does not throw and does not touch the filesystem.
pathinfo() is pure string surgery. It never opens the file, never checks that it exists, and never resolves symlinks — it just splits the text at the last directory separator and the last dot.
When to reach for it
Reach for it when you need an extension to route a file through the right handler, a base name to display in a UI, or a stem to build a derived name such as photo.jpg to photo-thumb.jpg. The filename key (base name minus the last extension) is the piece that basename() alone will not give you.
What trips people up
The extension key is absent from the array when the base name has no dot, so $info['extension'] emits an undefined-key warning on a name like README. Always write $info['extension'] ?? ''. Dotfiles behave the opposite way: when the base name starts with a dot, the characters after it are treated as the extension, so .gitignore gives extension gitignore and an empty filename.
Only the last extension is recognised: archive.tar.gz gives extension gz and filename archive.tar. And the result is locale- and byte-sensitive — for multibyte names, pathinfo() may split oddly unless the locale is set appropriately with setlocale().
Most importantly, an extension proves nothing about content. A file named invoice.pdf can hold PHP source. For uploads, use finfo to determine the real type and treat the extension as a display detail only.
Example
When to use it
- Pick a parser based on a file's extension when importing csv, json or xml drops.
- Build a derived filename such as report-2026.pdf to report-2026-signed.pdf.
- Show a friendly base name in a download list while storing a hashed path on disk.
Frequently asked questions
How do I get a filename without its extension in PHP?
Use pathinfo($path, PATHINFO_FILENAME), which returns the base name with the last extension stripped. For archive.tar.gz it returns archive.tar, since only one extension is removed.
Why does pathinfo give an undefined array key warning for extension?
Because the extension key is only present when the path contains a dot after the last separator. Use $info['extension'] ?? '' or call pathinfo($path, PATHINFO_EXTENSION), which returns an empty string instead.
Does pathinfo check that the file exists?
No. It parses the string and never touches the filesystem, so it works on paths, URLs-shaped strings and names that were never on disk. Use file_exists() or realpath() if existence matters.
More examples
Safely reading the extension
README yields an empty extension, and .gitignore is treated as an extension with an empty filename — a classic surprise. Lower-casing the extension matters because report.PDF and report.pdf are different strings.
<?php
$paths = ['report.PDF', 'README', '.gitignore', 'a/b/data.csv'];
foreach ($paths as $p) {
$ext = strtolower(pathinfo($p, PATHINFO_EXTENSION));
printf("%-14s ext=%-5s name=%s\n", $p, $ext === '' ? '-' : $ext, pathinfo($p, PATHINFO_FILENAME));
}Building a derived filename
Splitting on filename and extension keeps the suffix before the dot, which is what image and backup pipelines expect. The dump.tar.gz case shows that only the final extension is preserved, so the result is dump.tar.bak.gz.
<?php
function suffixed(string $path, string $suffix): string {
$i = pathinfo($path);
$ext = isset($i['extension']) ? '.' . $i['extension'] : '';
return $i['dirname'] . DIRECTORY_SEPARATOR . $i['filename'] . $suffix . $ext;
}
echo suffixed('uploads/photo.jpg', '-thumb'), "\n";
echo suffixed('/srv/data/dump.tar.gz', '.bak'), "\n";
echo suffixed('LICENSE', '-old'), "\n";Routing an import by extension
The match arm chosen by the extension parses the file into rows. This is fine for trusted internal drops; for user uploads, verify the real type with finfo rather than trusting the name.
<?php
file_put_contents('drop.csv', "id,name\n1,ada\n");
$ext = strtolower(pathinfo('drop.csv', PATHINFO_EXTENSION));
$rows = match ($ext) {
'csv' => array_map('str_getcsv', file('drop.csv', FILE_IGNORE_NEW_LINES)),
'json' => json_decode(file_get_contents('drop.csv'), true),
default => throw new RuntimeException("Unsupported: $ext"),
};
print_r($rows);
unlink('drop.csv');
Discussion