39

How can I change a file's extension using PHP?

Ex: photo.jpg to photo.exe

cdeszaq
  • 30,869
  • 25
  • 117
  • 173
PHLAK
  • 22,023
  • 18
  • 49
  • 52

12 Answers12

62

In modern operating systems, filenames very well might contain periods long before the file extension, for instance:

my.file.name.jpg

PHP provides a way to find the filename without the extension that takes this into account, then just add the new extension:

function replace_extension($filename, $new_extension) {
    $info = pathinfo($filename);
    return $info['filename'] . '.' . $new_extension;
}
Tony Maro
  • 1,854
  • 17
  • 14
  • 5
    To me, this is the best answer because it's using a function in PHP for what it was designed for. It also does the computation in one single command, which means less C code in the guts of PHP. – Volomike Oct 28 '11 at 23:18
  • 22
    I think this should keep the path information: return $info['dirname']."/".$info['filename'] . '.' . $new_extension; – James T Snell Jan 02 '14 at 04:46
  • 1
    Without the path it possibly break your application! – Guilherme Sampaio Jul 31 '20 at 18:01
25
substr_replace($file , 'png', strrpos($file , '.') +1)

Will change any extension to what you want. Replace png with what ever your desired extension would be.

Matt
  • 1,062
  • 11
  • 21
19

Replace extension, keep path information

function replace_extension($filename, $new_extension) {
    $info = pathinfo($filename);
    return ($info['dirname'] ? $info['dirname'] . DIRECTORY_SEPARATOR : '') 
        . $info['filename'] 
        . '.' 
        . $new_extension;
}
mgutt
  • 5,867
  • 2
  • 50
  • 77
Alex
  • 32,506
  • 16
  • 106
  • 171
  • Best answer! Watch out, `DS` not fit in this situation – Thanh Trung Jul 03 '13 at 09:38
  • 1
    Oh my ... I am so used to Magento where they define `DS` = `DIRECTORY_SEPARATOR`. Edited my answer. Thanks. – Alex Jul 05 '13 at 20:47
  • May be it's not safe because it change not only extension. For example, on Windows it may be change one separator to another. – Enyby Feb 13 '15 at 15:05
  • @Enyby: what do you mean? Do you have a non-working example name? – Alex Feb 13 '15 at 15:11
  • 'c:\\windows\\system32/drivers/etc/some.file..png' - change to 'jpg' give next result: 'c:\\windows\\system32/drivers/etc\\some.file..jpg' - separator before filename changed. It may be cause some side effects in some cases. – Enyby Feb 13 '15 at 15:40
  • That is not a valid windows path you are passing. should all be backslashes - no forward slashes. Use DIRECTORY_SEPARATOR when creating your path. – Alex Feb 13 '15 at 16:08
  • Strictly speaking, you're right. But the fact is that - php allows you to mix the two separator for Windows. For example, is_dir('c:\\windows\\system32/drivers/etc') return true. Therefore, I warn about possible side effects. – Enyby Feb 13 '15 at 16:27
8

You may use the rename(string $from, string $to, ?resource $context = null) function.

Ryan M
  • 18,333
  • 31
  • 67
  • 74
Galen
  • 29,976
  • 9
  • 71
  • 89
7

Once you have the filename in a string, first use regex to replace the extension with an extension of your choice. Here's a small function that'll do that:

function replace_extension($filename, $new_extension) {
    return preg_replace('/\..+$/', '.' . $new_extension, $filename);
}

Then use the rename() function to rename the file with the new filename.

Paige Ruten
  • 172,675
  • 36
  • 177
  • 197
  • 2
    Actually this is a bad idea. In modern operating systems, filenames may contain periods within the name, for instance when chaning the extension to ".tif", "this.is.a.test.pdf" when used in this would strip it to "this.tif" Instead, use: $info = pathinfo($filename); return $info['filename'] . "." . $new_extension; – Tony Maro Sep 03 '11 at 22:19
  • 3
    `preg_replace('/\.[^.]+$/', '.' . $extension, $file)` to match the last found `.` but will not work if file has no extension – Thanh Trung Jul 03 '13 at 09:35
4

Just replace it with regexp:

$filename = preg_replace('"\.bmp$"', '.jpg', $filename);

You can also extend this code to remove other image extensions, not just bmp:

$filename = preg_replace('"\.(bmp|gif)$"', '.jpg', $filename);
niksmac
  • 2,667
  • 3
  • 34
  • 50
3

For regex fans, modified version of Thanh Trung's 'preg_replace' solution that will always contain the new extension (so that if you write a file conversion program, you won't accidentally overwrite the source file with the result) would be:

preg_replace('/\.[^.]+$/', '.', $file) . $extension
Chris Hadi
  • 39
  • 3
  • This is a clever solution. By using a regex to simply strip the extension and then using string concatenate to apply the new extension it works under more conditions then any of the other solutions provided. – Ryan Williams Nov 15 '16 at 00:47
2

Better way:

substr($filename, 0, -strlen(pathinfo($filename, PATHINFO_EXTENSION))).$new_extension

Changes made only on extension part. Leaves other info unchanged.

It's safe.

Enyby
  • 4,162
  • 2
  • 33
  • 42
1

You could use basename():

$oldname = 'path/photo.jpg';
$newname = (dirname($oldname) ? dirname($oldname) . DIRECTORY_SEPARATOR  : '') . basename($oldname, 'jpg') . 'exe';

Or for all extensions:

$newname = (dirname($oldname) ? dirname($oldname) . DIRECTORY_SEPARATOR  : '') . basename($oldname, pathinfo($path, PATHINFO_EXTENSION)) . 'exe';

Finally use rename():

rename($oldname, $newname);
mgutt
  • 5,867
  • 2
  • 50
  • 77
0

Many good answers have been suggested. I thought it would be helpful to evaluate and compare their performance. Here are the results:

  • answer by Tony Maro (pathinfo) took 0.000031040740966797 seconds. Note: It has the drawback for not including full path.
  • answer by Matt (substr_replace) took 0.000010013580322266 seconds.
  • answer by Jeremy Ruten (preg_replace) took 0.00070095062255859 seconds.

Therefore, I would suggest substr_replace, since it's simpler and faster than others.

Just as a note, There is the following solution too which took 0.000014066696166992 seconds. Still couldn't beat substr_replace:

$parts = explode('.', $inpath);
$parts[count( $parts ) - 1] = 'exe';
$outpath = implode('.', $parts);
Moradnejad
  • 3,466
  • 2
  • 30
  • 52
0

I like the strrpos() approach because it is very fast and straightforward — however, you must first check to ensure that the filename has any extension at all. Here's a function that is extremely performant and will replace an existing extension or add a new one if none exists:

function replace_extension($filename, $extension) {
    if (($pos = strrpos($filename , '.')) !== false) {
        $filename = substr($filename, 0, $pos);
    }
    return $filename . '.' . $extension;
}
-2

I needed this to change all images extensions withing a gallery to lowercase. I ended up doing the following:

// Converts image file extensions to all lowercase
$currentdir = opendir($gallerydir);
while(false !== ($file = readdir($currentdir))) {
  if(strpos($file,'.JPG',1) || strpos($file,'.GIF',1) || strpos($file,'.PNG',1)) {
    $srcfile = "$gallerydir/$file";
    $filearray = explode(".",$file);
    $count = count($filearray);
    $pos = $count - 1;
    $filearray[$pos] = strtolower($filearray[$pos]);
    $file = implode(".",$filearray);
    $dstfile = "$gallerydir/$file";
    rename($srcfile,$dstfile);
  }
}

This worked for my purposes.

PHLAK
  • 22,023
  • 18
  • 49
  • 52