我正在使用 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) 时,它确实有效,但随后图像已经上传,并且损坏可能已经造成。执行此操作并随后执行检查,然后删除 te 文件对我来说似乎是不好的做法。
$_REQUEST 中唯一的内容是文件名,我将其用于 var $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);
PHP 5.4 现在支持
getimagesizefromstring
查看文档: https://www.php.net/manual/en/function.getimagesizefromstring.php
你可以尝试:
$input = fopen('php://input', 'r');
$string = stream_get_contents($input);
fclose($input);
getimagesizefromstring($string);
您可以使用
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);