Splitting a filename into name and extension

I have a php script which I’ve adapted from online tutorials.

<?php
// Where the file is going to be placed
$target_path="/var/savedfiles/".$subdirectory."/";

// rename file to remove web-unfriendly characters
$OriginalFilename = $FinalFilename = preg_replace('`[^a-z0-9-_.]`i','',$_FILES['uploadedfile']['name']);

// rename file if it already exists by prefixing an incrementing number
$FileCounter = 1;
// loop until an available filename is found
while (file_exists($target_path.$FinalFilename ))
$FinalFilename = $FileCounter++.'_'.$OriginalFilename;

// Add the original filename to our target path.
$target_path = $target_path . $FinalFilename;

if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
    echo "The file ".  $FinalFilename.
    " has been uploaded";
} else{
        echo "There was an error uploading ".  $OriginalFilename.
    ", your file may be greater than 1Gb. Please try again!";
}
?>

The above works well except for duplicate files it adds number in front e.g. 1_filename.extension

What I want is filename_1.extension

The following almost works but the filename is lost

<?php
// Where the file is going to be placed
$target_path="/var/savedfiles/".$subdirectory."/";

// rename file to remove web-unfriendly characters
$OriginalFilename = $FinalFilename = preg_replace('`[^a-z0-9-_.]`i','',$_FILES['uploadedfile']['name']);

$parts=pathinfo($FinalFilename);
$Extension = $parts['extension'];
$FileName = basename($parts,'.'.$Extension);

// rename file if it already exists by prefixing an incrementing number
$FileCounter = 1;
// loop until an available filename is found
while (file_exists($target_path.$FinalFilename ))
$FinalFilename = $FileName."_".$FileCounter++.".".$Extension;

// Add the original filename to our target path.
$target_path = $target_path . $FinalFilename;

if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
    echo "The file ".  $FinalFilename.
    " has been uploaded";
} else{
        echo "There was an error uploading ".  $OriginalFilename.
    ", your file may be greater than 1Gb. Please try again!";
}
?>

But the filename is lost so what I get is _1.extension

What am I doing wrong?

Try something like:

<?php

$filename = 'gm_script.user.js';
$file_name_and_extenstions = explode(".",$filename);

echo '<pre>'.var_dump($file_name_and_extenstions).'</pre>';
?>

That will split up a string in parts, spliting it wherever there is a . and it places each part as a seperate element of an array

$FileName = basename($parts,'.'.$Extension);  

First, $parts is an array; it does not make sense to try and get the base name of an array. This explains why the file name part goes missing from the $FinalFilename, basename() returns NULL when you give it input it doesn’t expect. When the NULL is converted to a string, it becomes an empty string.

Second, why use basename() at all, your $parts array will already hold the file name.

$FileName = $parts['filename'];

Finally, when developing, always make sure to have your error_reporting level turned as high as possible, -1 will do the trick, and that you’re displaying errors (display_errors = On). If you did this, you’d see the error message that PHP gives when trying to get the base name of that array: Warning: basename() expects parameter 1 to be string, array given in <filename> on line <number>.

Excellent this worked. I should have seen it early especially since I used the ‘extension’ code.

$FileName = $parts[‘filename’];

Thanks for the tip on using error messages… really helpful :slight_smile:

http://www.php.net/manual/en/function.pathinfo.php

What you are looking for is called ‘basename’:
$FileName = $parts[‘basename’];

At which point I wouldn’t waste the overhead on the extra variables, and would just use $parts code-wide.


&lt;?php

// Where the file is going to be placed
$target_path="/var/savedfiles/".$subdirectory."/";

// rename file to remove web-unfriendly characters
$originalFilename=$finalFilename=preg_replace(
	'`[^a-z0-9-_.]`i',
	'',
	$_FILES['uploadedfile']['name']
);

$fileInfo=pathinfo($finalFilename);

// rename file if it already exists by prefixing an incrementing number
$fileCounter=1;
// loop until an available filename is found
while (file_exists($target_path.$finalFilename)) {
	$finalFilename=(
		$fileInfo['baseName'].'_'.
		$fileCounter++.'.'.
		$fileInfo['extension']
	);
}

// Add the original filename to our target path.
$target_path.=$finalFilename;

if (move_uploaded_file(
	$_FILES['uploadedfile']['tmp_name'],
	$target_path
)) {
	echo '
		The file '.$finalFilename.' has been uploaded
	';
} else {
	echo '
		There was an error uploading '.$originalFilename.',
		your file may be greater than 1Gb. Please try again!
  ';
}
?&gt;

naturally, more meaningful variable names, ditching the double quotes, and some consistent formatting never hurts.

The basename includes the file extension, which is not what abasel wanted. As already mentioned, the filename item in the array has what he needs.

Oops, yer right. Man, I’m slipping badly tonight on this stuff… You are correct, should be ‘filename’ and not ‘basename’.