Question
I want to get a file's extension in PHP.
I have seen many different approaches online, such as:
$ext = end(explode('.', $filename));
$ext = substr(strrchr($filename, '.'), 1);
$ext = substr($filename, strrpos($filename, '.') + 1);
$ext = preg_replace('/^.*\.([^.]+)$/D', '$1', $filename);
$exts = split("[/\\.]", $filename);
$n = count($exts) - 1;
$ext = $exts[$n];
Since there are multiple ways to do it, what is the best and most reliable way to get a file extension in PHP?
Short Answer
By the end of this page, you will understand how file extensions are typically extracted in PHP, why pathinfo() is usually the best choice, how it behaves with edge cases, and when you should avoid relying on extensions alone for file validation.
Concept
In PHP, a file extension is usually the part of a filename after the last dot. For example, the extension of photo.jpg is jpg.
The main concept behind this question is string parsing for file paths, but in PHP there is already a built-in function designed for this job: pathinfo().
$extension = pathinfo($filename, PATHINFO_EXTENSION);
This matters because:
- it is clearer than manual string slicing
- it is built into PHP and intended for working with paths
- it handles common filename cases better than many custom solutions
- it makes your code easier to read and maintain
A key practical point: a file extension is just part of the filename. It does not guarantee the actual file type. For example, virus.jpg.exe and photo.jpg are very different files even though both contain .jpg somewhere. In real applications, extensions are helpful for display and simple checks, but not enough for security-sensitive validation.
Mental Model
Think of a filename like a label on a box:
report.pdf→ the label says it is a PDFimage.png→ the label says it is a PNG
The extension is just the last tag after the final dot.
pathinfo() is like asking PHP: "Please break this path into its known parts for me."
Instead of manually cutting the string with knives like substr(), explode(), or regular expressions, you use the tool made specifically for filenames.
Syntax and Examples
The most common and recommended syntax is:
$extension = pathinfo($filename, PATHINFO_EXTENSION);
Basic example
<?php
$filename = 'document.pdf';
$extension = pathinfo($filename, PATHINFO_EXTENSION);
echo $extension; // pdf
PHP looks at the path and returns the part after the last dot.
Example with a full path
<?php
$filename = '/var/www/uploads/photo.jpg';
$extension = pathinfo($filename, PATHINFO_EXTENSION);
echo $extension; // jpg
Example with no extension
<?php
$filename = 'README';
$extension = pathinfo($filename, PATHINFO_EXTENSION);
var_dump($extension); // string("")
If there is no extension, PHP returns an empty string.
Normalizing case
Extensions may come in uppercase or mixed case. You often want lowercase:
<?php
$filename = 'PROFILE.PNG';
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
echo $extension; // png
Safe helper function
<?php
function getFileExtension(string $filename): string
{
return strtolower(pathinfo($filename, PATHINFO_EXTENSION));
}
echo getFileExtension('archive.ZIP'); // zip
This keeps the logic in one place and makes the rest of your code cleaner.
Step by Step Execution
Consider this example:
<?php
$filename = 'backup.archive.tar.gz';
$extension = pathinfo($filename, PATHINFO_EXTENSION);
echo $extension;
Step by step:
$filenameis set to'backup.archive.tar.gz'.pathinfo($filename, PATHINFO_EXTENSION)examines the filename.- PHP finds the last dot in the string.
- Everything after that last dot is treated as the extension.
- The result is
'gz'. echo $extension;printsgz.
So even though the filename contains multiple dots, PHP returns only the final extension.
Another trace
<?php
$filename = 'notes.txt';
$extension = pathinfo($filename, PATHINFO_EXTENSION);
Execution:
- filename is
notes.txt - last dot is before
txt - returned extension is
txt
Hidden file example
<?php
$filename = '.htaccess';
$extension = pathinfo($filename, PATHINFO_EXTENSION);
var_dump($extension);
This is an important edge case. Files that begin with a dot are hidden files on many systems. The result may not behave the way beginners first expect, so always test special filenames when your application depends on them.
Real World Use Cases
Getting a file extension is common in many PHP applications.
File uploads
You may want to check whether a user uploaded something that looks like an image:
<?php
$allowed = ['jpg', 'jpeg', 'png', 'gif'];
$ext = strtolower(pathinfo($_FILES['upload']['name'], PATHINFO_EXTENSION));
if (!in_array($ext, $allowed, true)) {
echo 'Unsupported file type.';
}
Naming downloaded files
You might generate a new filename while preserving the original extension:
<?php
$ext = pathinfo($originalName, PATHINFO_EXTENSION);
$newName = uniqid('file_', true) . '.' . $ext;
Displaying file type labels
<?php
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
echo "File type: $ext";
Routing files to different processing logic
<?php
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if ($ext === 'csv') {
// parse CSV
} elseif ($ext === 'json') {
// parse JSON
}
In all of these cases, the extension helps make a decision, but should not be your only trust signal if security matters.
Real Codebase Usage
In real projects, developers usually use pathinfo() together with a few common patterns.
1. Normalize the extension
<?php
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
This avoids bugs caused by JPG vs jpg.
2. Use guard clauses for validation
<?php
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if ($ext === '') {
throw new InvalidArgumentException('The file has no extension.');
}
This fails early and keeps the rest of the code simpler.
3. Check against an allowlist
<?php
$allowed = ['pdf', 'docx', 'txt'];
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if (!in_array($ext, $allowed, true)) {
throw new RuntimeException('File type not allowed.');
}
4. Combine extension checks with MIME validation
For uploaded files, developers often validate both:
- filename extension using
pathinfo() - actual file type using functions like
finfo_file()
This is much safer than checking only the name.
5. Wrap logic in a reusable helper
<?php
function hasAllowedExtension(string $filename, array $allowed): bool
{
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
return in_array($ext, $allowed, true);
}
This keeps validation consistent across a codebase.
Common Mistakes
1. Using explode() directly inside end()
You may see this pattern:
<?php
$ext = end(explode('.', $filename));
This is problematic because it is less readable and can lead to warnings or poor style depending on PHP version and context.
A better version is:
<?php
$ext = pathinfo($filename, PATHINFO_EXTENSION);
2. Assuming every filename has an extension
Broken assumption:
<?php
$filename = 'README';
$ext = pathinfo($filename, PATHINFO_EXTENSION);
echo $ext; // empty string
Avoid this by checking for an empty result.
3. Trusting the extension for security
Broken approach:
<?php
if ($ext === 'jpg') {
// assume it is a real image
}
A malicious file can be renamed. If security matters, inspect the file contents too.
4. Forgetting about case differences
Broken example:
<?php
$filename = 'photo.JPG';
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if ($ext === 'jpg') {
echo 'Image accepted';
}
This fails because JPG !== jpg.
Fix:
<?php
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
5. Misunderstanding multiple dots
<?php
$filename = 'archive.tar.gz';
$ext = pathinfo($filename, PATHINFO_EXTENSION);
echo $ext; // gz
If you need tar.gz as a combined suffix, pathinfo() alone is not enough. You must define custom logic for that case.
6. Using deprecated or outdated functions
Older code may use split(), which is deprecated and should not be used in modern PHP.
Prefer current built-in functions like pathinfo() or explode() when appropriate.
Comparisons
| Approach | Example | Good choice? | Notes |
|---|---|---|---|
pathinfo() | pathinfo($filename, PATHINFO_EXTENSION) | Yes | Clear, built-in, and intended for paths |
explode() + array access | explode('.', $filename) | Sometimes | Works, but needs extra handling for edge cases |
substr() + strrpos() | substr($filename, strrpos($filename, '.') + 1) | Sometimes | More manual and easier to get wrong |
| Regular expression | preg_replace(...) | Rarely | Usually harder to read than needed |
split() | split(...) | No | Deprecated/obsolete |
pathinfo() vs manual string methods
- Use
pathinfo()when you are working with filenames or paths. - Use manual string methods only when you need custom behavior.
Extension vs MIME type
| Check | What it tells you | Reliable for security? |
|---|---|---|
| File extension | What the filename says | No |
| MIME type / file content | What the file actually appears to be | Much better |
This is why upload validation often uses both.
Cheat Sheet
// Recommended way
$ext = pathinfo($filename, PATHINFO_EXTENSION);
// Common real-world version
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
Rules to remember
- The extension is the part after the last dot.
pathinfo(..., PATHINFO_EXTENSION)returns a string.- If there is no extension, it returns an empty string.
- Normalize with
strtolower()if you need case-insensitive checks. - Do not trust extensions alone for upload security.
Examples
pathinfo('photo.jpg', PATHINFO_EXTENSION); // jpg
pathinfo('archive.tar.gz', PATHINFO_EXTENSION); // gz
pathinfo('README', PATHINFO_EXTENSION); // ''
Safe validation pattern
<?php
$allowed = ['jpg', 'png', 'pdf'];
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if ($ext === '' || !in_array($ext, $allowed, true)) {
// invalid extension
}
Best practice
- Use
pathinfo()for extraction. - Use an allowlist for accepted extensions.
- Use MIME/content checks for real validation.
FAQ
What is the best way to get a file extension in PHP?
Use pathinfo($filename, PATHINFO_EXTENSION). It is the clearest built-in solution for working with file paths.
Does pathinfo() return the dot too?
No. It returns only the extension text, such as jpg, not .jpg.
What happens if a file has no extension?
pathinfo($filename, PATHINFO_EXTENSION) returns an empty string.
How do I make extension checks case-insensitive?
Convert the result to lowercase:
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
What about filenames with multiple dots like archive.tar.gz?
pathinfo() returns only the final part: gz.
Is checking the extension enough for file upload security?
No. A filename can be changed easily. For secure validation, also inspect the file's MIME type or contents.
Should I use split() to get the extension?
No. split() is outdated and should not be used in modern PHP code.
Can I use explode() instead of pathinfo()?
You can, but pathinfo() is usually better because it is more readable and built specifically for file paths.
Mini Project
Description
Build a small PHP file-checking utility that reads a list of filenames, extracts each extension, normalizes it to lowercase, and reports whether the extension is allowed. This demonstrates the practical use of pathinfo() for validation and decision-making.
Goal
Create a PHP script that classifies filenames as allowed or rejected based on their extension.
Requirements
- Create an array of sample filenames with mixed-case extensions and some files without extensions.
- Extract each file extension using
pathinfo(). - Convert extensions to lowercase before checking them.
- Compare the extension against an allowlist such as
jpg,png, andpdf. - Print a clear message for each filename showing its extension and whether it is allowed.
Keep learning
Related questions
Are PDO Prepared Statements Enough to Prevent SQL Injection in PHP?
Learn how PDO prepared statements prevent SQL injection in PHP, what they protect, and the mistakes that still leave MySQL apps vulnerable.
Can You Bind an Array to an IN Clause in PHP PDO?
Learn how PDO handles placeholders in IN() clauses, why arrays cannot be bound directly, and the safe PHP pattern to build dynamic queries.
Choosing the Right MySQL Collation for PHP and UTF-8
Learn how MySQL character sets and collations work with PHP, and how to choose a practical UTF-8 setup for web applications.