我用PHP制作了一个上传脚本。如何避免覆盖文件?

时间:2009-05-11 00:04:33

标签: php

我使用move_uploaded_file功能制作了图片上传脚本。此函数似乎用新的文件覆盖任何预先存在的文件。所以,我需要检查目标位置是否已有文件。如果是,那么我需要在文件名后附加一些内容(在扩展名之前,以便文件名仍然有效),因此文件名是唯一的。如果可能的话,我希望将更改设置为最小化而不是附加日期时间。

如何使用PHP执行此操作?

7 个答案:

答案 0 :(得分:15)

上传文件时,我几乎总是会重命名。通常会有该文件的某种数据库记录。我使用它的ID来保证文件的唯一性。有时我甚至会存储客户端原始文件名在数据库中的内容,但我永远不会保留它或临时名称,因为无法保证信息良好,您的操作系统将支持它或它是唯一的(这是你的问题)。

所以只需将其重命名为您自己设计的一些方案。这是我的建议。

如果您没有任何数据库引用,那么您可以使用file_exists(),但不能保证在检查是否存在某些内容和移动它之间的其他内容不会使用相同的文件名那你就会覆盖。这是一个经典的race condition

答案 1 :(得分:2)

答案 2 :(得分:1)

如果值为目录,请不要使用file_exists(),因为它返回true(至少在* nix系统上,因为目录是专用文件)。改为使用is_file()。

例如,说某些内容失败,你有一个字符串:

$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"; }

这对我来说在过去造成了一些问题,所以我总是使用is_file()而不是file_exists()。

答案 3 :(得分:1)

我使用日期和时间函数根据上传时间生成随机文件名。

答案 4 :(得分:1)

假设您从表单中提交了一个文件,其中有一个名为incomingfile的输入,如下所示:

<input type="file" id="incomingfile" name="incomingfile" />

首先,我使用“删除”文件名并将其从默认临时目录复制到临时目录。这是处理特殊字符所必需的。当我没有采用这种做法时,我遇到了麻烦。

$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);

使用以下代码我检查文件是否存在,如果是,我找到一个新名称并最终复制它。例如,如果我想编写一个名为myimage.jpg的文件并且它已经存在,我将待处理文件重命名为myimage__000.jpg。如果这也存在,我将挂起的文件重命名为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

使用过的功能:
strtolower
preg_replace
copy
file_exists
str_pad
pathinfo
str_replace
unlink

答案 5 :(得分:0)

要检查文件是否存在,您可以使用file_exists功能。

要剪切文件名,您可以使用pathinfo功能。

答案 6 :(得分:0)

我用

$file_name = time() . "_" . $uploaded_file_name;