34

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

Ex: photo.jpg to photo.exe

cdeszaq
  • 30,043
  • 25
  • 112
  • 172
PHLAK
  • 21,185
  • 18
  • 48
  • 52

11 Answers11

57

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,786
  • 16
  • 14
  • 4
    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
  • 19
    I think this should keep the path information: return $info['dirname']."/".$info['filename'] . '.' . $new_extension; – James T Snell Jan 02 '14 at 04:46
  • 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,042
  • 10
  • 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,377
  • 2
  • 49
  • 71
Alex
  • 29,618
  • 13
  • 100
  • 157
  • 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

http://www.php.net/rename

Galen
  • 29,682
  • 9
  • 70
  • 89
  • What if you're using a variable as the file name? – PHLAK Oct 11 '08 at 07:42
  • The function takes strings, it doesn't matter if those strings are string literals or string variables. – Quentin Oct 11 '08 at 09:05
  • @me_ — Why are you complaining about this not being an answer *to me*? I just **commented** on it almost a **decade** ago. – Quentin Jan 30 '18 at 18:54
  • @me_ — That the OP doesn't understand fundamental basics of a programming language before asking a question about a specific task doesn't make an answer that assumes that knowledge bad. If it did, then every answer would have to include an introductory programming tutorial. – Quentin Jan 30 '18 at 19:26
  • @me_ — Which has nothing to do with the OP not knowing fundamentals like "A string is a string whether it comes from a string literal or a variable" – Quentin Jan 30 '18 at 20:07
  • @me_ — This just brings us back full circle to my earlier comment. If you think this is a low-quality answer because it is a link only answer, why did you aim your comment at me for explaining something that this answer wouldn't have bothered explaining if it wasn't a link only answer? Aim your comment at the person who wrote the answer! Or just flag it as low quality and move on! – Quentin Jan 30 '18 at 20:16
  • @me_ — You prefixed the comment with "@Quentin". That directed it at me. – Quentin Jan 30 '18 at 20:41
  • @me_ — A decade ago. Let it rest. – Quentin Jan 30 '18 at 20:44
  • @me_ — Look at the date the answer was made. Look at the date I "expanded on an non-answer". Consider how much experience I had with Stackoverflow on that date. Consider that the guidelines for how to use StackOverflow might have changed since then. Then let it rest. – Quentin Jan 30 '18 at 20:49
  • What? That isn't what I said. I've asked you to drop this thread repeatedly. You haven't. I'm just going to ignore you from henceforth. – Quentin Jan 30 '18 at 20:55
  • nobody asked you to write a book on the matter, it was always a personal choice... – me_ Jan 30 '18 at 20:57
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
  • 165,471
  • 36
  • 174
  • 194
  • 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,559
  • 3
  • 29
  • 47
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
  • 3,807
  • 2
  • 29
  • 39
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,377
  • 2
  • 49
  • 71
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,007
  • 2
  • 26
  • 51
-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
  • 21,185
  • 18
  • 48
  • 52