[英]I made an upload script in PHP. How do I avoid overwriting files?
I've made an image upload script using the move_uploaded_file
function. 我使用
move_uploaded_file
函数制作了一个图像上传脚本。 This function seems to overwrite any preexisting file with the new one. 此函数似乎用新的文件覆盖任何预先存在的文件。 So, I need to check if the target location already has a file.
所以,我需要检查目标位置是否已有文件。 If it does then I need to append something to the filename(before the extension so that the file name is still valid) so the filename is unique.
如果是,那么我需要在文件名后附加一些内容(在扩展名之前,以便文件名仍然有效),因此文件名是唯一的。 I'd like to have the change be minimal instead of something like appending the datetime, if possible.
如果可能的话,我希望将更改设置为最小化而不是附加日期时间。
How can I do this with PHP? 我怎么能用PHP做到这一点?
When uploading files I will nearly always rename them. 上传文件时,我几乎总是会重命名它们。 Typically there will be some kind of database record for that file.
通常会有该文件的某种数据库记录。 I use the ID of that to guarantee uniqueness of the file.
我使用它的ID来保证文件的唯一性。 Sometimes I'll even store what the client's original filename was in the database too but I'll never keep it or the temporary name because there is no guarantee that information is good, that your OS will support it or that it's unique (which is your issue).
有时我甚至会存储客户端原始文件名在数据库中的内容,但我永远不会保留它或临时名称,因为无法保证信息良好,您的操作系统将支持它或它是唯一的(这是你的问题)。
So just rename it to some scheme of your own devising. 所以只需将其重命名为您自己设计的一些方案。 That's my advice.
这是我的建议。
If you don't have any database reference, then you could use file_exists() for this but there's no guarantee that between the time of checking if something exists and moving it that something else won't use that same filename that you'll then overwrite. 如果您没有任何数据库引用,那么您可以使用file_exists() ,但不能保证在检查某些内容是否存在之间以及移动它之前其他内容不会使用相同的文件名。覆盖。 This is a classic race condition .
这是一个经典的比赛条件 。
Let's assume you are submitting a file from a form where you have an input named incomingfile
like this: 假设您从一个表单中提交一个文件,其中您有一个名为
incomingfile
如下所示:
<input type="file" id="incomingfile" name="incomingfile" />
First of all I use to "depure" the filename and copy it from the default temporary directory to a temporary directory. 首先,我使用“删除”文件名并将其从默认临时目录复制到临时目录。 This is necessary to deal with special characters.
这是处理特殊字符所必需的。 I had troubles when I didn't adopt this practice.
当我没有采用这种做法时,我遇到了麻烦。
$new_depured_filename = strtolower(preg_replace('/[^a-zA-Z0-9_ -.]/s', '_', $_FILES["incomingfile"]["name"]));
copy($_FILES["incomingfile"]["tmp_name"], 'my_temp_directory/'.$new_depured_filename);
With the following piece of code I check if the file exists, if so, I find a new name and finally copy it. 使用下面的代码我检查文件是否存在,如果是,我找到一个新名称并最终复制它。 For example if I want to write a file called
myimage.jpg
and it already exists I rename the pending file to myimage__000.jpg
. 例如,如果我想写一个名为
myimage.jpg
的文件并且它已经存在,我将挂起的文件重命名为myimage__000.jpg
。 If this exists as well I rename the pending file to myimage__001.jpg and so on until I find a non-existing filename. 如果这也存在,我将挂起的文件重命名为myimage__001.jpg,依此类推,直到找到一个不存在的文件名。
$i=0; // A counter for the tail to append to the filename
$new_filename = $new_depured_filename;
$new_filepath='myfiles/music/'.$new_filename;
while(file_exists($new_filepath)) {
$tail = str_pad((string) $i, 3, "0", STR_PAD_LEFT); // Converts the integer in $i to a string of 3 characters with left zero fill.
$fileinfos = pathinfo($new_filepath); // Gathers some infos about the file
if($i>0) { // If we aren't at the first while cycle (where you have the filename without any added strings) then delete the tail (like "__000") from the filename to add another one later (otherwise you'd have filenames like myfile__000__001__002__003.jpg)
$previous_tail = str_pad((string) $i-1, 3, "0", STR_PAD_LEFT);
$new_filename = str_replace('__'.$previous_tail,"",$new_filename);
}
$new_filename = str_replace('.'.$fileinfos['extension'],"",$new_filename); // Deletes the extension
$new_filename = $new_filename.'__'.$tail.'.'.$fileinfos['extension']; // Append our tail and the extension
$new_filepath = 'myfiles/music/'.$new_filename; // Crea il nuovo percorso
$i++;
}
copy('my_temp_directory/'.$new_depured_filename, $new_filepath); // Finally we copy the file to its destination directory
unlink('my_temp_directory/'.$new_depured_filename); // and delete the temporary one
Used functions: 使用功能:
strtolower 用strtolower
preg_replace 的preg_replace
copy 复制
file_exists 文件已存在
str_pad str_pad
pathinfo PATHINFO
str_replace str_replace函数
unlink 取消链接
Don't use file_exists() for the reason that it returns true (on *nix systems at least, since directories are specialized files) if the value is a directory. 不要使用file_exists(),因为它返回true(至少在* nix系统上,因为目录是专用文件),如果值是目录。 Use is_file() instead.
请改用is_file()。
For example, say something fails and you have a string like: 例如,说某些内容失败,你有一个字符串,如:
$path = "/path/to/file/" . $file; // Assuming $file is an empty value, if something failed for example
if ( true === file_exists($path) ) { echo "This returns true"; }
if ( true === is_file($path) ) { echo "You will not read this"; }
It's caused a few problems in the past for me, so I always use is_file() rather than file_exists(). 它在过去给我带来了一些问题,所以我总是使用is_file()而不是file_exists()。
我使用日期和时间函数根据上传时间生成随机文件名。
To check if a file exists, you can use the file_exists
function. 要检查文件是否存在,可以使用
file_exists
函数。
To cut the filename, you can use the pathinfo
function. 要剪切文件名,可以使用
pathinfo
函数。
我用
$file_name = time() . "_" . $uploaded_file_name;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.