【问题标题】:Check picture file type and size before file upload in php在php中文件上传之前检查图片文件类型和大小
【发布时间】:2009-08-08 21:25:46
【问题描述】:

我有以下代码:

$filecheck = basename($_FILES['imagefile']['name']);
  $ext = substr($filecheck, strrpos($filecheck, '.') + 1);
  if (($ext == "jpg" || $ext == "gif" || $ext == "png") && ($_FILES["imagefile"]["type"] == "image/jpeg" || $_FILES["imagefile"]["type"] == "image/gif" || $_FILES["imagefile"]["type"] == "image/png") && 
    ($_FILES["imagefile"]["size"] < 2120000)){
} else {
echo "F2";
die();
}

我需要做的是检查上传的文件是否为 jpg/gif/png 并且其大小是否小于 2 兆。

如果它大于 2 兆,或者不是正确的文件类型,我需要返回/回显 F2(api 的错误代码)。

当我使用上面的代码处理一个 70k 的 jpg 文件时,它返回 F2。

附注 我上传的图片扩展名为 .JPG。案件可能是一个因素吗?如果是这样,我该如何适应?

【问题讨论】:

  • 回答您的子注释:$ext = strtolower(substr($filecheck, strrpos($filecheck, '.') + 1));

标签: php


【解决方案1】:

请注意,您可能不想依赖文件扩展名来确定文件类型。例如,有人上传带有.png 扩展名的可执行文件会相当容易。恶意客户端也可以轻松伪造 mime 类型以作为图像传递。 依赖该信息存在安全风险

PHP Documentation:
文件的 MIME 类型(如果浏览器提供了此信息)。一个例子是“image/gif”。然而,这种 mime 类型并未在 PHP 端进行检查,因此不要认为它的价值是理所当然的

尝试使用gd (getimagesize()) 加载图像,以确保它们实际上是有效的图像(而不仅仅是用图像文件的标题伪装的随机文件...finfo_file 依赖于这些标题)。

if($_FILES["imagefile"]["size"] >= 2120000) {
  echo "F2";
  die();
} else {
    $imageData = @getimagesize($_FILES["imagefile"]["tmp_name"]);

    if($imageData === FALSE || !($imageData[2] == IMAGETYPE_GIF || $imageData[2] == IMAGETYPE_JPEG || $imageData[2] == IMAGETYPE_PNG)) {
      echo "F2";
      die();
    }
}

如果确实必须使用扩展名来验证文件是否为图像,请使用strtolower()将扩展名转为小写。

$filecheck = basename($_FILES['imagefile']['name']);
$ext = strtolower(substr($filecheck, strrpos($filecheck, '.') + 1));

if (!(($ext == "jpg" || $ext == "gif" || $ext == "png") && ($_FILES["imagefile"]["type"] == "image/jpeg" || $_FILES["imagefile"]["type"] == "image/gif" || $_FILES["imagefile"]["type"] == "image/png") && 
    ($_FILES["imagefile"]["size"] < 2120000))){
    echo "F2";
    die();
}

【讨论】:

    【解决方案2】:

    请注意,我上传的图片扩展名为 .JPG。案件可能是一个因素吗?如果是这样,我该如何适应?

    是的,这就是问题所在。您应该将 strtolower() 添加到此行:

    $ext = substr($filecheck, strrpos($filecheck, '.') + 1);
    

    喜欢:

    $ext = strtolower(substr($filecheck, strrpos($filecheck, '.') + 1));

    这将解决您当前的问题。但从技术上讲,你不应该担心文件扩展名,你应该只需要检查 MIME 类型

    【讨论】:

    • 确实是 MIME 类型。该文件也可以命名为 .jpeg。
    • 依赖该信息存在安全风险。请在下面阅读我的回答。
    【解决方案3】:

    $ext == "jpg" 这样的比较只检查$ext 是否完全是“jpg”。

    在进行这些比较之前,您可能希望在 $ext 上使用strtolower,以处理“.JPG”的情况。


    如果您使用的是 PHP mime_content_type 来检查文件的内容类型,而不是依赖于客户端发送的 $_FILES['imagefile']['name'] 和/或 $_FILES["imagefile"]["type"] --并且可以因此被伪造。

    如果您使用 PHP >= 5.3,您可能需要考虑新的扩展 fileinfo,它是 finfo_file 函数


    对于文件的大小,您已经在使用 $_FILES["imagefile"]["size"] ;没关系,我想,但你只有在文件上传后才会知道——不过,恐怕在上传之前没有真正的方法来检查这种事情......


    在上传文件之前,您可能能够找到一些 JS 代码来对扩展名进行第一次预检查——但您仍然需要在服务器端进行检查,因为在客户端完成的任何操作本质上都是不安全的。

    不确定您是否可以对文件的大小执行相同的操作...

    某些浏览器可能支持名为MAX_FILE_SIZE 的隐藏字段(请参阅有关file upload 的文档);但不确定它是否真的受支持(实际上从未见过它使用过;所以可能不是:-()


    作为旁注,您可能需要配置upload_max_filesize,因此它允许上传至少与您想要的一样大(默认情况下,它通常设置为 2MB ;所以对您来说应该已经可以了)

    【讨论】:

      【解决方案4】:

      文件大小相当明显,但人们在上面检查文件格式是否正确的做法有些低效,而且“不安全”。

      这是我的工作:

      if($_FILES["userPicture"]["error"] == 0) {
      // File was uploaded ok, so it's ok to proceed with the filetype check.
          $uploaded_type = exif_imagetype($_FILES["userPicture"]["tmp_name"]);
          // What we have now is a number representing our file type.
      
          switch($uploaded_type) {
              case "1":
                  $uploaded_type = "gif";
              break;
              case "2":
                  $uploaded_type = "jpg";
              break;
              case "3":
                  $uploaded_type = "png";
              break;
          }
      }
      

      更多信息:
      http://www.php.net/manual/en/function.exif-imagetype.php

      编辑:这具有“在每个浏览器中”工作的优势,因为它不依赖于文件名或用户提供的任何内容,除了文件数组值“error”告诉我们没有真正的错误。

      【讨论】:

        【解决方案5】:

        请注意,对于 Internet Explorer, 他们将 JPEG 文件的 mime 类型提交为 image/pjpeg - 这与其他浏览器不同。

        这是一个简单的函数,可以根据文件扩展名获取 mime 类型:

        function mime2ext($mime){ // mime is like image/jpeg
            $m = explode('/',$mime);
            $mime = $m[count($m)-1]; // get the second part of the mime type
            switch($mime){
                case 'jpg':
                case 'jpeg':
                case 'pjpeg':
                    return 'jpg';
                    break;
                case 'png':
                    return 'png';
                    break;
                case 'gif':
                    return 'gif';
                    break;
            }
            return '';
        }
        

        【讨论】:

          【解决方案6】:

          php是一种服务器端脚本语言,如果图片是在客户端,你不能通过php上传之前检查它们的大小。

          【讨论】:

          • 非常好的一点 - 可以使用一些 javascript 来检查文件大小,然后拒绝,而 filetype 可以通过@Andrew Moore 的答案在脚本内部检查
          【解决方案7】:

          你需要两件事:

          使您的扩展检查不区分大小写:

          if($strtolower($ext == "jpg")){
            // do your stuff
          }
          

          检查文件是否实际包含图像。一个简单的方法是文件信息:

          $finfo = finfo_open(FILEINFO_MIME_TYPE);
          echo finfo_file($finfo, $filename);
          $finfo_close($finfo);
          

          另一种检查文件是否真的是图像的方法是加载到像 gd 这样的图像库中。如果您的文件可以成功加载,则为图像。

          请记住,jpeg 图像可以具有 .jpg.jpeg 扩展名。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-06-23
            • 1970-01-01
            • 2022-01-10
            • 2016-10-25
            • 2016-06-17
            相关资源
            最近更新 更多