PHP机制防止用户上传相同文件的方法

4
我正在尝试通过PHP网站允许用户上传文件。由于所有文件都保存在服务器上的单个文件夹中,虽然概率较低,但有可能两个不同的用户上传了两个文件,这些文件尽管不同,但名称完全相同。或者它们是完全相同的文件。
在这两种情况下,我想立即使用exec(“openssl md5”.$file ['upload'] ['tmp_name'])确定文件的MD5哈希值。然后,我将检查数据库是否存在相同的MD5哈希值,如果找到,我就不会完成上传。
然而,在move_uploaded_file文档中,我发现了这个评论:
警告:如果您保存了一个md5_file哈希值以记录已上传的文件,并且这对于防止用户上传相同的文件很有用,请注意,在使用move_uploaded_file之后,md5_file哈希值会更改!当删除文件时,您无法找到相应的哈希值并将其从数据库中删除。
这是真的吗?在将文件从临时目录移动到永久位置后,文件在tmp目录中的MD5哈希值会更改吗?我不明白为什么会这样。无论如何,还有其他更好的方法来确保同一文件不会多次上传到文件系统吗?

...如果找到了,我就不会完成上传。我希望你已经仔细考虑过了...如果用户认为他们可以上传自己超酷的模因,然后发现他们不能上传,因为其他人已经上传了,那么用户会感觉如何呢?除非你提供一种方法将新的“尝试提交”链接到现有条目,以便两个用户“看起来”拥有自己的文件。 - rlemon
1
请使用sha1或sha256代替md5。确保哈希文件内容而不是文件名。 - Will Bickford
1
我不明白为什么SHA1或SHA256更可取。除非Magsol存储了大量的文件,否则不应该有任何区别。您能解释一下为什么他应该使用您的SHA吗? - SteAp
@rlemon:别担心,我不会用memes做那个,只是用meme模板 :) 另外,这是用于上传视频的。由于它们是如此大的文件,如果同样的文件已经存在于服务器上,我宁愿不为重复文件分配空间,而是将链接重定向--就像你建议的那样--到先前上传的视频。 - Magsol
@Magsol 没问题,只要记账。 - rlemon
5个回答

1

你不应该使用exec("openssl md5 " . $file['upload']['name'])吗?我认为临时文件名会因上传而异。


这是这样吗?我以为 ['tmp_name'] 是指文件系统中的临时目录,而 move_uploaded_file() 通常涉及将 ['name'] 作为“目标”参数。如果我想在调用 move_uploaded_file 之前访问它,我应该使用 ['name'] 吗? - Magsol

1

看起来确实是这样。 我也简短地查看了文档。 但为什么不在使用move_uploaded_file之前共享md5校验和,并将该值存储在数据库中,直接将其与新文件链接起来呢? 这样您就可以随时检查上传的文件以及该文件是否已存在于文件系统中。

这确实需要一个数据库,但大多数人都可以访问它。


是的!这正是我目前正在做的事情。实际上,我在发布后意识到,即使使用move_uploaded_file()时MD5发生变化,调用move_uploaded_file()之前对文件进行MD5哈希仍将所有内容哈希到正确的域并提供良好的比较。 - Magsol

1
如果你被这里的答案所说的所有原因所说服,并决定根本不使用md5(我仍然不确定你是否想要或必须使用哈希),那么你只需为每个用户和上传时间附加一些唯一的东西到每个文件名中。这样你就会得到更可读的文件名,例如:$filename = "$filename-$user_ip_string-$microtime",当然,在此之前,你必须准备好并格式化好这三个变量,这是不言而喻的。
没有同样的文件名、同样的IP地址和同样的微秒数发生的可能性,对吧?你可以只使用微秒数,但使用IP地址可以使结果更加确定。当然,像我说的,如果你决定不使用哈希算法并选择一个更简单的解决方案,所有这些都不重要。

1
某种独特的名称是我的想法,所以我并不一定要使用MD5。我想我可以放弃尝试检测是否意外(甚至是故意)上传了相同的文件,只需确保每个文件都有自己独特的名称。这可能是更好的方法,因为它肯定会让服务器端更容易处理! - Magsol

1

尝试将上传的文件重命名为唯一标识符。 使用以下方法:

$dest_filename = $filename;
        if (RENAME_FILE) {
      $dest_filename = md5(uniqid(rand(), true)) . '.' . $file_ext;
         }

如果有帮助,请告诉我 :)


请添加以下内容: define('RENAME_FILE', true); - Albab

0

通常情况下,通过 move_uploaded_file 函数移动文件并不会魔法般地改变哈希值。

但是,如果你计算包括文件路径在内的 md5() 哈希值,当文件被移动到新的路径或文件夹时,哈希值肯定会改变。

如果你只计算文件名的 md5() 值,则哈希值不会改变。

将上传的文件重命名为唯一名称是个好主意。

但别忘了,要将文件存储在文档根目录之外的 vHost 文件夹中,这样才能使用 PHP 脚本下载它。

最后提醒:虽然非常非常不可能,但两个不同文件的md5哈希值可能相同


1
最后的评论描述了一种被称为哈希碰撞的现象。这就是MD5近来备受诟病的原因。 - BoltClock
一个解决方法是进行两阶段测试;先进行MD5,然后比较文件的大小和随机字节。或者如果它们很小,只需比较内容即可。 - Phil Lello
是的,我正在尝试对文件的内容进行哈希,而不是对其文件名进行哈希,因为两个用户可以很容易地上传两个具有通用且相同名称但内容迥异的文件,而我想要防止重复的是内容。 我不关心一百万个名为“video.avi”的文件,只要每个视频都是不同的 :) - Magsol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接