在流上使用getimagesize()而不是字符串

5
我正在使用Valum的文件上传程序来通过AJAX上传图像。此脚本以我不完全了解的方式将文件提交到我的服务器,因此最好通过展示我的服务器端代码来解释:

$pathToFile = $path . $filename;

//Here I get a file not found error, because the file is not yet at this address
getimagesize($pathToFile);

$input = fopen('php://input', 'r');
$temp = tmpfile();
$realSize = stream_copy_to_stream($input, $temp);

//Here I get a string expected, resource given error 
getimagesize($input);

fclose($input);

$target = fopen($pathToFile, 'w');
fseek($temp, 0, SEEK_SET);

//Here I get a file not found error, because the image is not at the $target yet
getimagesize($pathToFile);

stream_copy_to_stream($temp, $target);
fclose($target);

//Here it works, because the image is at the desired location so I'm able to access it with $pathToFile. However, the (potentially) malicious file is already in my server.
getimagesize($pathToFile);

问题在于我想要使用getimagesize()进行文件验证,但是getimagesize仅支持字符串,而我只有资源可用,这会导致错误:getimagesize期望一个字符串,但是实际传入的是资源。
当我在脚本末尾执行getimagesize($pathTofile)时,它确实可以工作,但是图像已经被上传,损坏可能已经发生。这样做并随后执行检查,然后也许删除文件似乎不是好的做法。 $_REQUEST中唯一的东西是文件名,我将其用于变量$pathToFile。$_FILES为空。
如何对流执行文件验证?
编辑: 解决方法是先将文件放入临时目录,在将其复制到目标目录之前对临时文件进行验证。
// Store the file in tmp dir, to validate it before storing it in destination dir
$input = fopen('php://input', 'r');
$tmpPath = tempnam(sys_get_temp_dir(), 'upl'); // upl is 3-letter prefix for upload
$tmpStream = fopen($tmpPath, 'w'); // For writing it to tmp dir
stream_copy_to_stream($input, $tmpStream);
fclose($input);
fclose($tmpStream);

// Store the file in destination dir, after validation
$pathToFile = $path . $filename;
$destination = fopen($pathToFile, 'w');
$tmpStream = fopen($tmpPath, 'r'); // For reading it from tmp dir
stream_copy_to_stream($tmpStream, $destination);
fclose($destination);
fclose($tmpStream);

请在您的问题中添加getimagesize代码,否则很难回答。从您的问题中看来,您也有一个字符串指向文件,您可以使用该字符串而不是资源ID。因此,了解阻止您这样做的原因将会很有帮助。 - hakre
完成了,我希望这能更清楚一些。 - Thomas
2个回答

7

2

不要使用tmpfile(),你可以使用tempnam()sys_get_temp_dir()来创建一个临时路径。

然后使用fopen()获取它的句柄,并复制流。

现在你有了一个字符串和一个句柄,可以进行需要的操作。

//Copy PHP's input stream data into a temporary file

$inputStream   = fopen('php://input', 'r');
$tempDir       = sys_get_temp_dir();
$tempExtension = '.upload';

$tempFile   = tempnam($tempDir, $tempExtension);
$tempStream = fopen($tempFile, "w");
$realSize   = stream_copy_to_stream($inputStream, $tempStream);

fclose($tempStream);

getimagesize($tempFile);

我认为这个方向是正确的,但是tempnam()返回一个字符串而不是资源,那么我该如何使用stream_copy_to_stream()呢?我应该使用fwrite吗?抱歉,我有点迷失了,在这里我甚至不太理解什么是流。 - Thomas
我觉得我快完成了,唯一的问题是目标目录中的文件大小为0字节。你知道我做错了什么吗?我把我的当前代码放在问题里。 - Thomas
你已经复制了流吗?那么它应该大于0字节。 - hakre
我添加了一些示例代码,它还添加了fflush命令,以防存在未写入的缓冲区。这也可能是问题所在。看一下。 - hakre
很不幸,还是没有成功,上传的文件仍然是空的。我编辑了我的代码以展示我如何使用fflush。 - Thomas
显示剩余3条评论

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