【问题标题】:File upload issues in PHPPHP中的文件上传问题
【发布时间】:2025-12-04 13:00:02
【问题描述】:

您好,我正在尝试使用 php 脚本上传图片。真正奇怪的是,我只在 Internet Explorer 中收到以下错误,其他任何地方的脚本都可以正常工作:

Warning: move_uploaded_file(pictures/) [function.move-uploaded-file]: failed to open stream: Is a directory in /home/tntauto1/public_html/admin_add1.php on line 59

Warning: move_uploaded_file() [function.move-uploaded-file]: Unable to move '/tmp/phpcJnHZE' to 'pictures/' in /home/tntauto1/public_html/admin_add1.php on line 59

Warning: copy() [function.copy]: The first argument to copy() function cannot be a directory in /home/tntauto1/public_html/admin_add1.php on line 60

这是脚本:

if(is_uploaded_file($_FILES['image']['tmp_name'])){
    if($_FILES['image']['type'] == 'image/jpeg'){
        $original = 'original_'.$v_id.'.jpg';
        $large = 'large_'.$v_id.'.jpg';
        $small = 'small_'.$v_id.'.jpg';

    }elseif($_FILES['image']['type'] == 'image/gif'){
        $original = 'original_'.$v_id.'.gif';
        $large = 'large_'.$v_id.'.gif';
        $small = 'small_'.$v_id.'.gif';
    }else{
        $error = 'Error: The image could not be uploaded. It must be in .jpg, .jpeg or .gif format.';
    }
    if(move_uploaded_file($_FILES['image']['tmp_name'],'pictures/'.$large)){}
        copy('pictures/'.$large,'pictures/'.$small);

    $imgsize = getimagesize('pictures/'.$large); //>>>>>>>>>>>>>>>>>>>>>>>>>>>>---- Resize to 480 X 360
    $width = $imgsize[0];
    $height = $imgsize[1];
    if(($width > 480) || ($height > 360)){//resize the image
        $ratio = $width / $height;
        if(100 / $ratio >= 80){//calculates if height of uploaded image is too large
            $new_width = floor(360 * $ratio);
            $new_height = 360;
        }elseif(150 * $ratio > 100){// calculate if width of uploaded image is too large
            $new_width = 480;
            $new_height = floor(480 / $ratio);
        }
        if($_FILES['image']['type'] == 'image/jpeg'){
            $img = imagecreatefromjpeg('pictures/'.$large);
            $img_copy = imagecreatetruecolor($new_width,$new_height);
            imagecopyresampled($img_copy,$img,0,0,0,0,$new_width,$new_height,$width,$height);
            imagejpeg($img_copy,'pictures/'.$large,100);    
        }
        if($_FILES['image']['type'] == 'image/gif'){
            $img = imagecreatefromjpeg('pictures/'.$large);
            $img_copy = imagecreatetruecolor($new_width,$new_height);
            imagecopyresampled($img_copy,$img,0,0,0,0,$new_width,$new_height,$width,$height);
            imagejpeg($img_copy,'pictures/'.$large,100);    
        }
    }   

【问题讨论】:

  • 大家好,谢谢大家的意见。不按文件类型检查它 $_FILES['name']['type'] 修复了它。 (对不起,我没有提到 $large 变量是在我没有发布的脚本中定义的)

标签: php file-upload


【解决方案1】:
if($_FILES['image']['type'] == 'image/jpeg'){

永远不要依赖浏览器提交的 MIME 类型。

在这种情况下,您的问题就像大卫提到的那样:IE 通常(错误地)为 JPEG 提供 image/pjpeg,因此您检测到未知文件类型并将 $error 设置为 Error: The image could not be uploaded. It must be in .jpg, .jpeg or .gif format.... 但尽管如此,您仍然尝试移动文件,尽管没有设置 $small 或 $large。

但不仅如此,浏览器提交的类型很可能是完全错误的。您不能相信上传的文件名或媒体类型是合适的,所以甚至不必费心检查它们。相反,请在调用 getimagesize 后查看$imgsize[2],以了解 PHP 认为该图像是什么类型。

而且...如果您接受来自普通用户的图片上传,您就会遇到安全问题。完全有可能创建一个包含 HTML 标记的有效 GIF(或其他文件类型)。然后当血腥愚蠢的 IE 出现以自己的页面访问 GIF 时,它会检测 HTML 标签,确定您告诉它的 Content-Type 一定是错误的,并将其解释为 HTML 页面,包括任何JavaScript 在那里,然后在您网站的安全上下文中执行。

如果您必须允许从不受信任的来源上传文件并且您没有自己处理图像(这通常会产生删除不需要的 HTML 的副作用),您通常必须从不同的主机名提供图像以避免他们在您的网站中编写脚本。

【讨论】:

  • 不知道您可以在图像中嵌入 HTML。一个人会怎么做?更重要的是,如何检测上传的图片是否包含 HTML 标签并进行相应处理?
  • 这是一个有趣的例子:lcamtuf.coredump.cx/squirrel。尝试检测任意文件中的标签是一种注定失败的方法,因为您必须使用与浏览器相同的启发式方法,这些方法是可变的且未记录的。相反,如上所述,从不同的主机名提供您的用户内容,这样如果它获得 XSS,它不会控制您的主站点。
  • 非常有趣。当我检查图像文件时,我可以看到 HTML 标签。有些人建议从上传的图像中创建一个新图像,以删除文件和/或元数据中可能存在的 HTML 和脚本。那行得通吗?我正在考虑就我的特殊情况发布一个关于此的问题。
  • 重新压缩图像会让您有机会删除元数据,当然。这仍然留下了攻击者发送图像数据的可能性,这些数据在压缩时会产生看起来像 HTML 标记的数据。 (假设攻击者可以访问相同的压缩器代码来分析和定位,)这是一个有趣但肯定很难的攻击;对于 JPEG 可能不切实际,但对于某些无损格式可能更可行。
  • 我已就此向question 询问。如果您愿意,可以查看并回答。
【解决方案2】:
if($FILES['image']['type'] == 'image/jpeg'){

保存文件上传数据的变量应该是$_FILES。由于$FILES 是一个空(刚刚使用)变量,因此您的$large 变量也是空的,因此您将文件移动到一个目录pictures/,就像PHP 告诉您的那样。您的$error 还应该包含错误消息,因为在它为真之前没有任何 ifs。

避免此类错误的一种方法是将error_reporting 设置为E_ALL 进行开发,这会显示您的$FILES 变量(错字)未定义的通知。

【讨论】:

  • 忽略这个答案,看起来好像你打错了,因为这里的问题格式错误。我同意 david.scheider 的回答,从 IE 上传时检查返回的 mime 类型。
【解决方案3】:

你不能移动一个目录,因为 $large 没有价值,或者被重置了。

【讨论】: