This function creates a new filename to use for a copy of the given filename, its behaviour was mostly sto^Wborrowed from how the OS X Finder (*1) does it.
Note it *doesn't* actually copy the file, it just returns the new name. I needed it to work regardless of data source (filesystem, ftp, etc).
It also tries to match the current name as neatly as possible:
foo.txt -> foo copy.txt -> foo copy 1.txt -> foo copy 2.txt [etc]
foo.bar.baz.jpg -> foo.bar.baz copy.jpg
foobar -> foobar copy -> foobar copy 1 [etc]
".txt" -> .txt copy, and "txt." -> txt. copy
file.longextension -> file.longextension copy
It keeps trying until it finds a name that is not yet taken in $list, or until it looped 500 times (change as needed).
If the renamed file becomes longer than max filename length, it starts chopping away at the end of the part before where it adds " copy": reallylong...filename.txt -> reallylong...filena copy.txt
<?php
function duplicate_name($orig, $list = array(), $max = 64) {
$ext = '';
$counter = 0;
$list = (array) $list;
$max = (int) $max;
$newname = $orig;
do {
$name = $newname; if (preg_match('/ copy$| copy \d+$/', $name, $matches)) {
}elseif (preg_match('/(.+)\.([^.]{1,5})$/', $name, $parts)) {
list($name, $ext) = array($parts[1], $parts[2]);
}
if (preg_match('/ copy (\d+)$/', $name, $digits)) {
$newname = substr($name, 0, - strlen($digits[1])) . ($digits[1] + 1);
$cutlen = 6 + strlen($digits[1]+1); }elseif(preg_match('/ copy$/', $name, $digits)) {
$newname = $name . ' 1';
$cutlen = 7; }else{
$newname = $name . ' copy';
$cutlen = 5; }
if ($ext) {
$newname .= '.' . $ext;
$cutlen += strlen($ext) + 1;
}
if ($max > 0) {
if (strlen($newname) > $max) {
$newname = substr($newname, 0, max($max - $cutlen, 0)) . substr($newname, -$cutlen);
if (strlen($newname) > $max) {echo "duplicate_name() error: Can't keep the new name under given max length.\n"; return false;}
}
}
if ($counter++ > 500) {echo "duplicate_name() error: Too many similarly named files or infinite while loop.\n"; return false;}
} while (in_array($newname, $list));
return $newname;
}
?>
*1) The Finder seems to check the extension vs a list of known extensions, this function considers it valid if it's 5 or fewer characters long.
ps. sorry for taking up so much space! :-)