note 72644 added to function.copy
| From: | mspreij at osu1 dot php dot net | Date: | Sat, 27 Jan 2007 16:20:42 +0000 |
| Subject: | note 72644 added to function.copy | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-122267@lists.php.net to get a copy of this message | ||
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
// $orig = current name, of course
// $list = array of filenames in the target directory (if none given, it will still return a new
name)
// $max = max length of filename
function duplicate_name($orig, $list = array(), $max = 64) {
$ext = '';
$counter = 0;
$list = (array) $list;
$max = (int) $max;
$newname = $orig;
do {
$name = $newname; # name in, newname out
if (preg_match('/ copy$| copy \d+$/', $name, $matches)) {
// don't even check for extension, name ends with " copy[ digits]"
// preg hereunder matches anything with at least one period in the middle (that is,
// non-period characters on either side), and an extension of 1-5 characters
}elseif (preg_match('/(.+)\.([^.]{1,5})$/', $name, $parts)) {
// split to name & extension
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 is only used for the bit at the end where it checks on max filename length
$cutlen = 6 + strlen($digits[1]+1); // ' copy ' + digits
}elseif(preg_match('/ copy$/', $name, $digits)) {
$newname = $name . ' 1';
$cutlen = 7; // ' copy' + ' 1'
}else{
$newname = $name . ' copy';
$cutlen = 5; // ' copy'
}
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! :-)
----
Server IP: 194.109.193.94
Probable Submitter: 82.73.63.123
----
Manual Page -- http://www.php.net/manual/en/function.copy.php
Edit -- https://master.php.net/note/edit/72644
Del: integrated -- https://master.php.net/note/delete/72644/integrated
Del: useless -- https://master.php.net/note/delete/72644/useless
Del: bad code -- https://master.php.net/note/delete/72644/bad+code
Del: spam -- https://master.php.net/note/delete/72644/spam
Del: non-english -- https://master.php.net/note/delete/72644/non-english
Del: in docs -- https://master.php.net/note/delete/72644/in+docs
Del: other reasons-- https://master.php.net/note/delete/72644
Reject -- https://master.php.net/note/reject/72644
Search -- https://master.php.net/manage/user-notes.php