10

当一个用户上传一个文件时,它会随机被另一个用户的上传替换,我终于找到了 PHP 的问题,并且 tmp 文件名被重用了。有没有办法来解决这个问题?有没有办法制作更好的随机名称?它似乎随着时间的推移而退化,因为随机文件名种子变弱了?这是 PHP 5.2.8 和 FreeBSD 7.0

这是一个日志,显示如何使用相同的 tmp 文件名并被另一个上传覆盖:http: //pastebin.com/m65790440

任何帮助是极大的赞赏。我已经尝试解决这个问题超过 4 个月,并且随着时间的推移变得更糟。谢谢你。

编辑:请记住,这不是 PHP 代码问题,这发生在它到达任何 PHP 代码之前,通过 $_FILES['name']['tmp_name'] 收到的文件在收到并被跟踪时不正确返回它在到达上传处理脚本之前被其他人的上传覆盖

4

5 回答 5

5

在将相关代码追踪到 FreeBSD 7 的 libc 实现中的_gettemp之后,我不清楚文件的内容是如何tmp_name无效的。(要跟踪它,您可以下载 PHP 5.2.8 的副本并读取main/rfc1867.c1018 行调用 in main/php_open_temporary_file.c,该函数从第 227 行开始,它在从第 97 行开始的函数中执行它的主要工作,然而,它本质上是只是系统上 mkstemp 的一个包装器,它位于第 66 行(链接)的FreeBSD libc 实现中,它使用_gettemp(与上面相同)实际生成随机文件名。但是mkstemp 的手册页在 BUGS 部分中提到该arc4random()函数是不可重入的。它可能有 2 个同时请求进入关键代码部分并返回相同的可能性tmp_name- 我对 Apache 如何与 mod_php 或 php-cgi 一起工作知之甚少,无法在此处发表评论(尽管使用 FastCGI/php-cgi 可能有效 - 我可以'此时不能成功评论)。

但是,针对最简单的解决方案,如果您没有完全体验到文件tmp_name本身无效,而是与其他上传的文件发生冲突(例如,如果使用 tmp_name 的文件名部分作为存储文件名中唯一性的唯一来源),由于生日悖论,您可能会面临碰撞。在另一个问题中,您提到要移动大约 5,000,000 个文件,在另一个问题中,您提到每天要接收 30-40k 上传。这让我觉得这是生日悖论碰撞的主要情况。mktemp手册页提到(如果像 PHP 那样使用六个“X”)有 56,800,235,584 个可能的文件名(62 ** 6 或 62 ** n,其中 n =“X”的数量等)。但是,鉴于您有超过 500 万个文件,发生冲突的概率大约为 100%(另一个启发式方法表明,如果 ((files*(files-1)) /2)/(62**6) 表示任何东西,其中文件 = 5,000,000)。如果这是您面临的问题(很可能,如果不向生成的上传文件名添加进一步的熵),您可以尝试类似move_uploaded_file($file['tmp_name'], UPLOADS.sha1(mt_rand().$file['tmp_name']).strrchr($file['name'], '.'))的方法 - 为随机文件名添加更多随机性,防止冲突。另一种方法是在第 134 行添加两个“X”main/php_open_temporary_file.c并重新编译。

于 2010-07-19T16:52:57.477 回答
4

听起来您的 PHP 安装或 PHP 内部用于生成随机文件名的任何系统调用(很可能是tempnam)都存在严重问题。

对于其他人:PHP 在处理用户代码之前在内部处理上传的文件。这些名称存储在$_FILES['file']['tmp_name'](其中“文件”是表单上文件输入元素的(引用)名称)。

于 2009-03-10T19:32:24.237 回答
2

PHP 是否在 apache 下运行mod_php

您可以尝试创建一个每个进程的临时上传目录,其名称包含您的 php getmypid(),然后是ini_set您的 PHP 进程'upload_tmp_dir到该目录。php如果为每个请求生成一个新进程,这将不起作用。

于 2009-03-10T19:28:10.630 回答
0

上传文件后将文件移动到用户目录。这些临时文件应该被删除。

于 2009-03-10T19:28:58.257 回答
-1

我建议使用 GUID 生成器作为文件名,因为你得到了这么多。

于 2009-03-10T19:25:57.233 回答