上传的PHP临时文件名冲突

时间:2009-03-10 19:22:02

标签: php file-upload temporary-files

当用户上传文件时,随机将其替换为另一个用户的上传文件,我最终将问题追溯到PHP并重新使用tmp文件名。有没有办法来解决这个问题?有没有办法制作更好的随机名称?它随着时间的推移似乎会降级,因为随机文件名种子变得越来越弱?这是在PHP 5.2.8和FreeBSD 7.0上

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

非常感谢任何帮助。我一直试图解决这个问题超过4个月,并且随着时间的推移变得更糟。谢谢。

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

5 个答案:

答案 0 :(得分:4)

对于PHP安装或PHP内部使用的任何系统调用生成随机文件名(很可能是tempnam),听起来有些严重错误。

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

答案 1 :(得分:3)

在FreeBSD 7的libc实现中将相关代码追溯到_gettemp后,我不清楚文件tmp_name的内容如何无效。 (为了跟踪它,您可以下载PHP 5.2.8的副本并在main/rfc1867.c中读取 - {10}中的{10}个调用,该函数从第227行开始,这是函数启动时的主要工作但是,在第97行,它基本上只是系统上mkstemp的包装器,可以在第66行(链接)的FreeBSD libc implementation中找到,它使用_gettemp(与上面相同)实际上生成随机文件名。但是the manpage for mkstemp在BUGS部分提到arc4random() function不可重入。可能有可能同时有2个请求进入关键代码段返回相同的main/php_open_temporary_file.c - 我对Apache如何使用mod_php或php-cgi在那里发表评论知之甚少(尽管使用FastCGI / php-cgi可能有效 - 我目前无法对此成功评论)

然而,针对最简单的解决方案,如果您没有经历文件tmp_name本身无效,而是与其他上传的文件发生冲突(例如,如果使用tmp_name的文件名部分作为您的唯一来源存储文件名中的唯一性),由于birthday paradox,您可能会遇到冲突。在another question中,您提到要移动大约5,000,000个文件,而在still another question中,您提到每天收到30-40k的上传文件。这让我感到生日悖论碰撞的主要情况。 mktemp man page提到(如果像PHP一样使用6个'X'),则有56,800,235,584个可能的文件名(62 ** 6或62 ** n,其中n ='X'的数量等)。但是,鉴于你有超过500万个文件,碰撞的概率是approximately 100%(另一个启发式建议你已经经历过220次碰撞的顺序,如果((files *(files-1) ))/ 2)/(62 ** 6)表示任何文件= 5,000,000)。如果这是您面临的问题(可能,如果没有为生成的上传文件名添加进一步的熵),您可以尝试类似tmp_name的内容 - 这个想法是为了添加更多随机性随机文件名,防止冲突。另一种方法是将另外两个“X”添加到move_uploaded_file($file['tmp_name'], UPLOADS.sha1(mt_rand().$file['tmp_name']).strrchr($file['name'], '.'))的第134行并重新编译。

答案 2 :(得分:2)

PHP是否在apache下运行,mod_php

您可以尝试 create a per-process temporary upload directory ,其名称包含您的php getmypid(),然后ini_set您的PHP流程“upload_tmp_dir 那个目录。如果为每个请求生成一个新的php进程,则无效。

答案 3 :(得分:0)

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

答案 4 :(得分:-1)

我建议在文件名中使用GUID生成器,看看你收到了这么多。