How can I change a file's extension using PHP?
Ex: photo.jpg to photo.exe
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;
}
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.
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;
}
You may use the rename(string $from, string $to, ?resource $context = null) function.
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.
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);
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
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.
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);
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);
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;
}
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.
Related
I have a folder in a server with a lot of images and I would like to rename some images. Images that contain (1 example:
112345(1.jpg to 112345.jpg. How can I do this using regex in PHP? I have to mention that my knowledge of PHP is very limited and it's the only language that can effectively do the scripting.
preg_match('/\(1/', $entry) will help you.
Also, you need to pay attention to "what if the file has a duplicate after the rename".
$directory = "/path/to/images";
if ($handle = opendir($directory)) {
while (false !== ($entry = readdir($handle))) {
if ($entry != '.' && $entry != '..') {
// Check "(1"
if (preg_match('/\(1/', $entry)) {
// Rename file
$old = $directory . '/' . $entry;
$new = str_replace('(1', '', $old);
// Check duplicate
if (file_exists($new)) {
$extension = strrpos($new, '.');
$new = substr($new, 0, $extension) . rand() . substr($new, $extension); // Basic rand()
}
rename($old, $new);
}
}
}
closedir($handle);
}
If you want only remove some substring from images names you can do this without regex. Use str_replace function to replace substring to empty string.
As example:
$name = "112345(1.jpg";
$substring = "(1";
$result = str_replace($substring, "", $name);
You can use scandir and preg_grep to filter out the files that needs to be renamed.
$allfiles = scandir("folder"); // replace with folder with jpg files
$filesToRename = preg_grep("/\(1\.jpg/i", $allfiles);
Foreach($filesToRename as $file){
Echo $file . " " . Var_export(rename($file, str_replace("(1.", ".", $file));
}
This is untested code and in theory it should echo the filename and true/false if the rename worked or not.
Only use regex for this if you need to assert the position of the substring, e.g. if you have filenames like Copy (1)(1.23(1.jpg a simple string replacement will go wrong.
$re = '/^(.+)\(1(\.[^\\\\]+)$/';
$subst = '$1$2';
$directory = '/my/root/folder';
if ($handle = opendir($directory )) {
while (false !== ($fileName = readdir($handle))) {
$newName = preg_replace($re, $subst, $fileName);
rename($directory . $fileName, $directory . $newName);
}
closedir($handle);
}
The regular expression used searches for the part before and after the file extension, put the pieces into capturing groups, and glue them together again in the preg_replace without the (1.
The file name is known but the file extension is unknown. The images in thier folders do have an extension but in the database their names do not.
Example:
$ImagePath = "../images/2015/03/06/"; (Folders are based on date)
$ImageName = "lake-sunset_3";
Does not work - $Ext is empty:
$Ext = (new SplFileInfo($ImagePath))->getExtension();
echo $Ext;
Does not work either - $Ext is empty:
$Ext = (new SplFileInfo($ImagePath.$ImageName))->getExtension();
echo $Ext;
Does not work either - $Ext is still empty:
$Ext = (new SplFileInfo($ImagePath,$ImageName))->getExtension();
echo $Ext;
$Ext should produce ".jpg" or ".jpeg" or ".png" etc.
So my question is simple: What am I doing wrong?
Now, this is a bit of an ugly solution but it should work. Make sure that all your files have unique names else you'll have several of the same file, which could lead to your program obtaining the wrong one.
<?php
$dir = scandir($imagePath);
$length = strlen($ImageName);
$true_filename = '';
foreach ($dir as $k => $filename) {
$path = pathinfo($filename);
if ($ImageName === $path['filename']) {
break;
}
}
$Ext = $path['extension'];
?>
Maybe this might help you (another brute and ugly solution)-
$dir = '/path/to/your/dir';
$found = array();
$filename = 'your_desired_file';
$files = scandir($dir);
if( !empty( $files ) ){
foreach( $files as $file ){
if( $file == '.' || $file == '..' || $file == '' ){
continue;
}
$info = pathinfo( $file );
if( $info['filename'] == $filename ){
$found = $info;
break;
}
}
}
// if file name is matched, $found variable will contain the path, basename, filename and the extension of the file you are looking for
EDIT
If you just want the uri of your image then you need to take care of 2 things. First directory path and directory uri are not the same thing. If you need to work with file then you must use directory path. And to serve static files such as images then you must use directory uri. That means if you need to check files exists or what then you must use /absolute/path/to/your/image and in case of image [site_uri]/path/to/your/image/filename. See the differences? The $found variable form the example above is an array-
$found = array(
'dirname' => 'path/to/your/file',
'basename' => 'yourfilename.extension',
'filename' => 'yourfilename',
'extension' => 'fileextension'
);
// to retrieve the uri from the path.. if you use a CMS then you don't need to worry about that, just get the uri of that directory.
function path2url( $file, $Protocol='http://' ) {
return $Protocol.$_SERVER['HTTP_HOST'].str_replace($_SERVER['DOCUMENT_ROOT'], '', $file);
}
$image_url = path2url( $found['dirname'] . $found['basename'] ); // you should get the correct image url at this moment.
You are calling a file named lake-sunset_3. It has no extension.
SplFileInfo::getExtension() is not designed to do what you are requesting it to do.
From the php site:
Returns a string containing the file extension, or an empty string if the file has no extension.
http://php.net/manual/en/splfileinfo.getextension.php
Instead you can do something like this:
$path = $_FILES['image']['name'];
$ext = pathinfo($path, PATHINFO_EXTENSION);
getExtension() only returns the extension from the given path, which in your case of course doesn't have one.
In general, this is not possible. What if there is a file lake-sunset_3.jpg and a file lake-sunset_3.png?
The only thing you can do is scan the directory and look for a file with that name but any extension.
You're trying to call an incomplete path. You could try Digit's hack of looking through the directory for for a file that matches the name, or you could try looking for the file by adding the extensions to it, ie:
$basePath = $ImagePath . $ImageName;
if(file_exists($basePath . '.jpg'))
$Ext = '.jpg';
else if(file_exists($basePath . '.gif'))
$Ext = '.gif';
else if(file_exists($basePath . 'png'))
$Ext = '.png';
else
$Ext = false;
Ugly hacks aside, the question begging to be asked is why are you storing them without the extensions? It would be easier to strip off the extension if you need to than it is try and find the file without the extension
Need to remove user requested string from file name. This below is my function.
$directory = $_SERVER['DOCUMENT_ROOT'].'/path/to/files/';
$strString = $objArray['frmName']; // Name to remove which comes from an array.
function doActionOnRemoveStringFromFileName($strString, $directory) {
if ($handle = opendir($directory)) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") {
if(!strstr($file,$strString)) {
continue;
}
$newfilename = str_replace($strString,"",$file);
rename($directory . $file,$directory . $newfilename);
}
}
closedir($handle);
}
}
It works partially good. But the mistake what in this routine is, renaming action also takes on file's extensions. What i need is, Only to rename the file and it should not to be affect its file extensions. Any suggestions please. Thanks in advance :).
I have libraries written by myself that have some of those functions. Look:
//Returns the filename but ignores its extension
function getFileNameWithOutExtension($filename) {
$exploded = explode(".", $filename);
array_pop($exploded);
//Included a DOT as parameter in implode so, in case the
//filename contains DOT
return implode(".", $exploded);
}
//Returns the extension
function getFileExtension($file) {
$exploded = explode(".", $file);
$ext = end($exploded);
return $ext;
}
So you use
$replacedname = str_replace($strString,"", getFileNameWithOutExtension($file));
$newfilename = $replacedname.".".getFileExtension($file);
Check it working here:
http://codepad.org/CAKdCAA0
I have a long path like this - /home/user/www/domain.net/public_html/system/dir/file.php, and I want crop this to get something like - /system/dir/file.php.
Now I am using this code:
$filename = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $filename);
$filename = join(DIRECTORY_SEPARATOR, array_slice(explode(DIRECTORY_SEPARATOR, $filename), -3, 3));
And it works, but I think there is a better solution.. Anyone know?
Thanks in advance.
You can use regex instead. See this sample:
$sFileName = '/home/user/www/domain.net/public_html/system/dir/file.php';
$iCropCount = 3;
$sResult = preg_replace('#.*?((\/[^\/]+){'.$iCropCount.'})$#', '$1', $sFileName));
//var_dump($sResult);
Operations with DIRECTORY_SEPARATOR are omitted (since main sense of sample above are not in them)
I think you only need the web directory. So you can explode with /public_html as it is always going to be there.
E.g :
$filename = '/home/user/www/domain.net/public_html/system/dir/file.php';
$path = explode('/public_html', $filename);
echo $path[1];
I found other solution:
$filename = '/home/user/www/domain.net/public_html/system/dir/file.php';
explode($_SERVER['DOCUMENT_ROOT'], $filename);
$filename = end($filename);
I understand that using PHP's basename() function you can strip a known file extension from a path like so,
basename('path/to/file.php','.php')
but what if you didn't know what extension the file had or the length of that extension? How would I accomplish this?
Thanks in advance!
pathinfo() was already mentioned here, but I'd like to add that from PHP 5.2 it also has a simple way to access the filename WITHOUT the extension.
$filename = pathinfo('path/to/file.php', PATHINFO_FILENAME);
The value of $filename will be file.
You can extract the extension using pathinfo and cut it off.
// $filepath = '/path/to/some/file.txt';
$ext = pathinfo($filepath, PATHINFO_EXTENSION);
$basename = basename($filepath, ".$ext");
Note the . before $ext
$filename = preg_replace('#\.([^\.]+)$#', '', $filename);
You can try with this:
$filepath = 'path/to/file.extension';
$extension = strtolower(substr(strrchr($filepath, '.'), 1));
Try this:-
$path = 'path/to/file.php';
$pathParts = pathinfo( $path );
$pathWihoutExt = $pathParts['dirname'] . DIRECTORY_SEPARATOR . $pathParts['filename'];