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

Posted

技术标签:

【中文标题】getimagesize() 在流上而不是字符串上【英文标题】:getimagesize() on stream instead of string 【发布时间】:2012-01-02 19:46:42 【问题描述】:

我正在使用Valum's file uploader 使用 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);

【问题讨论】:

请将getimagesize代码也添加到您的问题中,否则很难回答。从您的问题看来,您的文件也有一个字符串,您可以使用该字符串而不是资源 ID。所以很高兴知道是什么阻止你这样做。 完成,我希望这能澄清一点。 【参考方案1】:

PHP 5.4 现在支持getimagesizefromstring

查看文档: http://php.net/manual/pt_BR/function.getimagesizefromstring.php

你可以试试:

$input = fopen('php://input', 'r');
$string = stream_get_contents($input);
fclose($input);

getimagesizefromstring($string);

【讨论】:

【参考方案2】:

您可以使用tempnam()sys_get_temp_dir() 来创建临时路径,而不是使用tmpfile()

然后使用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 吗?对不起,我有点迷路了,我什至不明白什么是流。 在该字符串上使用fopen()。然后你也得到了一个资源。 我想我快到了,唯一的问题是现在目标目录中的文件有 0 个字节。你知道我做错了什么吗?我把我当前的代码放在了问题中。 您已经复制了流吗?那么它应该大于0字节。 我还添加了一些示例代码,它还添加了fflush 命令,以防有一些未写入的缓冲区。也可能是问题所在。看看吧。

以上是关于getimagesize() 在流上而不是字符串上的主要内容,如果未能解决你的问题,请参考以下文章

绘制矩形边框始终为白色(在实时摄像机流上)

IO流上:概述字符流缓冲区

如何检测 .NET StreamReader 是不是在底层流上找到了 UTF8 BOM?

D-Bus 可以在不是 Unix 域套接字的流上使用吗?

使用您自己的 AMS,如何在 RTMP 流上使用 BitmapData.draw() 而没有安全异常?

在不使用 Azure SDK 的情况下使用 REST API 将流上传到 Azure Blob 存储