如何检查上传的文件扩展名


How can I check uploaded files extension?

如何在下面的代码中检查上传的文件扩展名(我已经写了一个文件类型检查)?我想防止上传带有错误扩展名的图像文件,如*.jpg.exe.

我的代码:

<?php
class Uploader {
    private $fileName;
    private $fileData;
    private $destination;
    public function __construct($key){
        $this->fileName = $_FILES[$key]['name'];
        $this->fileData = $_FILES[$key]['tmp_name'];
    }
    public function saveIn($folder){
        $this->destination = $folder;
    }
    public function save(){
        $folderWriteAble = is_writable($this->destination);
        if($folderWriteAble && (exif_imagetype($this->fileData) == IMAGETYPE_JPEG)){
            $name = "$this->destination/$this->fileName";
            $success = move_uploaded_file($this->fileData, $name);
        } else {
            trigger_error("cannot write to $this->destination");
            $success = false;
        }
        return $success;
    }
} 

如果您在服务器linux上运行,我会使用返回文件真实mime类型的命令file检查文件内容类型。然后你可以确定内容是什么(在大多数情况下)。

那个程序使用了神奇的字节。最初的想法是检查第一个视图字节,并检查文件是否包含已知模式,例如,对于windows可执行文件为"MZ",对于PNG文件为"‰PNG"。然而,file程序也做了一些比仅第一视图字节的基本集合更多的事情。


根据评论,您担心的是错误的,例如双文件扩展名。我想说的是,不要想它,只需重命名该文件,在最好的情况下使用一些随机名称。如果你担心有人只是统计一些文件号来查看未发布的图像,这也会有所帮助。

我认为您已经在(exif_imagetype($this->fileData) == IMAGETYPE_JPEG)上这样做了,但这里有一个非常好的讨论:https://security.stackexchange.com/questions/57856/is-there-a-way-to-check-the-filetype-of-a-file-uploaded-using-php

使用getimagesize检查文件中的前三位。请注意,$_FILES读取扩展名(当然人们可以更改)与读取权限位的getimagesize相比并不安全。

用法:

$image = getimagesize($_FILES['image']['tmp_name']);
$filetype = $image['mime'];

希望这能帮助

我知道这不一定能回答你的具体问题,但防止"PHP图像"被"执行"的一个好方法是让图像从一个不执行PHP脚本、只提供静态图像的地方提供(即:nginx,如果配置正确的话)。它甚至可以是一个外部CDN,或者只是一个不运行php的简单目录。

话虽如此,你也可以试试:

1- Make sure file type is (jpg, gif or png)
2- Make sure dimensions are numbers
3- Make sure file size does not exceed allowed size
4- Make sure file is not executable by anyone else (proper chmod settings are important in shared environment).
5- Rename and convert all uploads through imagemagick to jpg (or your desired format)

使用GD库来测试您上传的图像是否为jpg,此外,检查部分上传的图像也是否返回false:

$image = @imagecreatefromjpeg($this->fileData);
if(!$image) { imagedestroy($image); return false; } // file is not a jpg
else { imagedestroy($image); return true; } // file is a jpg

如果可以使用exec(),还可以调用unix文件实用程序来检查二进制签名。

// verify that the file is a jpg
$mime = "image/jpeg; charset=binary";
exec("file -bi " . $this->fileData, $out);
if ($out[0] != $mime) {
    // file is not a jpg
    ...

如果你安装了ClamAV,你也可以用exec命令检查病毒:

exec("clamscan --stdout " . $this->fileData, $out, $return);
if ($return) {
    // file is infected
    ...