【问题标题】:Check file extension in upload form in PHP [duplicate]在 PHP 中检查上传表单中的文件扩展名 [重复]
【发布时间】:2012-05-14 10:16:24
【问题描述】:

我检查文件扩展名是否已上传。我的示例方法有效,但现在我需要了解我的方法(使用pathinfo)是否正确。还有其他更好更快的方法吗?

$filename = $_FILES['video_file']['name'];
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if ($ext !== 'gif' || $ext !== 'png' || $ext !== 'jpg') {
    echo 'error';
}

【问题讨论】:

  • 为什么文件名为“video_file”,但您只允许图像..
  • 我发现这个问题正在寻找有效的文件扩展名。我不是在这里回答这个问题,但我想指出您的 if 语句中有逻辑错误。条件之间必须是&&,而不是||...只是想我会分享我的观点。
  • 我推荐使用 Reza S 的解决方案。如果处理图像,我还建议使用getimagesize php 函数来检测文件是否实际上是图像。如果未检测到图像,则返回 false。

标签: php file-upload


【解决方案1】:

检查文件扩展名不是最佳做法。完成此任务的首选方法是检查文件MIME type

来自 PHP:

<?php
    $finfo = finfo_open(FILEINFO_MIME_TYPE); // Return MIME type
    foreach (glob("*") as $filename) {
        echo finfo_file($finfo, $filename) . "\n";
    }
    finfo_close($finfo);
?>

上面的示例将输出类似于您应该检查的内容。

text/html
image/gif
application/vnd.ms-excel

虽然 MIME 类型也可以被欺骗(编辑文件的前几个字节并修改幻数),但它比编辑文件名更难。因此,您永远无法 100% 确定该文件类型实际上是什么,并且应该注意处理用户上传/通过电子邮件发送的文件。

【讨论】:

  • 我几乎怀疑有没有办法获得真正的文件扩展名。到处都有“分析文件名”的答案,这是最糟糕的方法......非常感谢这个答案!
  • 这个答案应该在最上面,有人很容易更改文件扩展名!
  • @PrafullaKumarSahu 您可以在这里找到问题的详细答案:stackoverflow.com/a/8028436/196917
  • 我发现一个更好的资源可能是这个链接将来会被删除,但现在它似乎是一个很棒的资源。 acunetix.com/websitesecurity/upload-forms-threat
  • 我想步步高也在寻找一种方法来防止 webshel​​l 被上传。在 HTTP 请求中很容易更改 mime 类型。检查扩展名是一种更好的(虽然不是理想的)方法,因为没有正确扩展名的文件将无法执行。检查 OWASP 资源: • owasp.org/index.php/Unrestricted_File_Upload
【解决方案2】:

使用if( $ext !== 'gif') 可能效率不高。如果您允许 20 种不同的扩展程序怎么办?

试试:

$allowed = array('gif', 'png', 'jpg');
$filename = $_FILES['video_file']['name'];
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if (!in_array($ext, $allowed)) {
    echo 'error';
}

【讨论】:

  • 我上传的是大写的文件名 (DOG.JPG),所以我必须添加 $filename = strtolower($filename);
  • @Baba 您好先生,我们如何在多文件上传中做到这一点。?而且我在 $ext 上也收到错误,这意味着我无法从此代码中获取文件扩展名。我该怎么办?
  • 重新“高效”:你的意思是sufficient吗?
  • 此过程不安全。用户可以将危险文件重命名为 jpg 并将其保存到服务器。为了确保只上传可以按预期处理的图片,我建议检查 MimeType。 (请参阅下面的其他解决方案:stackoverflow.com/a/10456149/2320007
【解决方案3】:

如何在上传之前验证表单上的文件扩展名(仅限 jpg/jpeg)。此处发布的另一个答案的变体带有包含的数据过滤器,这在评估其他发布的表单值时可能很有用。注意:如果为空,则错误将留空,因为这是我的用户的选项,而不是要求。

<?php
if(isset($_POST['save'])) {

//Validate image
if (empty($_POST["image"])) {
$imageError = "";
} else {
$image = test_input($_POST["image"]);
$allowed =  array('jpeg','jpg');
$ext = pathinfo($image, PATHINFO_EXTENSION);
if(!in_array($ext,$allowed) ) {
$imageError = "jpeg only";
}
}

}

// Validate data
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
<?

您的 html 将如下所示;

<html>
<head>
</head>

<body>
<!-- Validate -->
<?php include_once ('validate.php'); ?>

<!-- Form -->
<form method="post" action="">

<!-- Image -->
<p>Image <?php echo $imageError; ?></p>
<input type="file" name="image" value="<?php echo $image; ?>" />

<p><input type="submit" name="save" value="SAVE" /></p>
</form>

</body>
</html>

【讨论】:

    【解决方案4】:

    要正确实现这一点,最好检查 mime 类型。

    function get_mime($file) {
      if (function_exists("finfo_file")) {
        $finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
        $mime = finfo_file($finfo, $file);
        finfo_close($finfo);
        return $mime;
      } else if (function_exists("mime_content_type")) {
        return mime_content_type($file);
      } else if (!stristr(ini_get("disable_functions"), "shell_exec")) {
        // http://stackoverflow.com/a/134930/1593459
        $file = escapeshellarg($file);
        $mime = shell_exec("file -bi " . $file);
        return $mime;
      } else {
        return false;
      }
    }
    //pass the file name as
    echo(get_mime($_FILES['file_name']['tmp_name']));
    

    【讨论】:

      【解决方案5】:

      我认为这可能对你有用

      //<?php
          //checks file extension for images only
          $allowed =  array('gif','png' ,'jpg');
          $file = $_FILES['file']['name'];
          $ext = pathinfo($file, PATHINFO_EXTENSION);
              if(!in_array($ext,$allowed) ) 
                  { 
      //?>
      <script>
             alert('file extension not allowed');
             window.location.href='some_link.php?file_type_not_allowed_error';
      </script>
      
      //<?php
      exit(0);
          }
      //?>
      

      【讨论】:

        【解决方案6】:

        使用这个功能

         function check_image_extension($image){
        
                $images_extentions = array("jpg","JPG","jpeg","JPEG","png","PNG");
        
                $image_parts = explode(".",$image);
        
                $image_end_part = end($image_parts);
        
                if(in_array($image_end_part,$images_extentions ) == true){
        
                    return time() . "." . $image_end_part;
        
        
                }else{
        
                    return false;
                }
        
        
            }
        

        【讨论】:

          【解决方案7】:

          也可以通过其他方式检查文件类型。我相信这是检查上传文件类型的最简单方法。如果您正在处理图像文件,请使用以下代码。如果您正在处理视频文件,则将图像检查替换为 if 块中的视频检查......玩得开心

          $img_up = $_FILES['video_file']['type']; $img_up_type = explode("/", $img_up); $img_up_type_firstpart = $img_up_type[0];

          if($img_up_type_firstpart == "image") { // image 是图片文件类型,如果需要查看视频文件类型可以处理视频

          /* 做你的逻辑代码 */ }

          【讨论】:

          • $_FILES['field_name']['type'] 是用户定义的,因此不应依赖于验证。您应该使用 php 的 exif_imagetype 或 getimagesize 函数来检查图像的详细信息/类型。
          【解决方案8】:

          我个人更喜欢使用preg_match()函数:

          if(preg_match("/\.(gif|png|jpg)$/", $filename))
          

          in_array()

          $exts = array('gif', 'png', 'jpg'); 
          if(in_array(end(explode('.', $filename)), $exts)
          

          如果您有很多扩展来验证和处理问题,in_array() 会很有用。 另一种验证文件图像的方法:可以使用@imagecreatefrom*(),如果函数失败,则表示图像无效。

          例如:

          function testimage($path)
          {
             if(!preg_match("/\.(png|jpg|gif)$/",$path,$ext)) return 0;
             $ret = null;
             switch($ext)
             {
                 case 'png': $ret = @imagecreatefrompng($path); break;
                 case 'jpeg': $ret = @imagecreatefromjpeg($path); break;
                 // ...
                 default: $ret = 0;
             }
          
             return $ret;
          }
          

          然后:

          $valid = testimage('foo.png');
          

          假设foo.png 是一个带有.png 扩展名的PHP 脚本文件,上述函数将失败。可以避免shell update、LFI等攻击。

          【讨论】:

            【解决方案9】:

            不确定这是否会有更快的计算时间,但另一种选择......

            $acceptedFormats = array('gif', 'png', 'jpg');
            
            if(!in_array(pathinfo($filename, PATHINFO_EXTENSION), $acceptedFormats))) {
                echo 'error';
            }
            

            【讨论】:

              【解决方案10】:

              pathinfo 很酷,但您的代码可以改进:

              $filename = $_FILES['video_file']['name'];
              $ext = pathinfo($filename, PATHINFO_EXTENSION);
              $allowed = array('jpg','png','gif');
              if( ! in_array( $ext, $allowed ) ) {echo 'error';}
              

              当然,仅仅检查文件名的扩展名并不能保证文件类型是有效的图像。您可以考虑使用getimagesize 之类的函数来验证上传的图像文件。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2019-12-30
                • 2011-11-25
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-07-28
                • 2014-12-10
                相关资源
                最近更新 更多