网络人 > PHP技术 > 一个可以防止图片木马的PHP上传类

一个可以防止图片木马的PHP上传类

<?php
//成功后返回一个数组,如果有错误请使用UploadHandler->showError()调用返回值
class UploadHandler
{
    private $formName;//表单名
    private $fileName;//最终返回文件名
    private $maxSize;//上传文件大小限制
    private $allowMime;//允许的MIME类型
    private $allowExt;//允许的扩展名
    private $uploadPath;//上传目录
    private $fileInfo = array();//上传文件数组
    private $ext;//文件扩展名
    private $img;//存放图片相关信息
    private $destination;//最终地址
    private $imgArr = array('jpg', 'jpeg', 'png', 'gif');//遇到图片进行检测
    private $imgFlag = 0;
    private $error = null;
    public $returnArr;

    public function __construct(
        $formName = 'myfiles',//表单名
        $fileName = '',//文件名
        $uploadPath = A_DIR,//上传目录
        $maxSize = 5242880,//文件大小限制
        $allowExt = array(),//文件扩展名
        $allowMime = array('image/jpeg', 'image/png', 'image/gif')//MIME类型
    )
    {
        $this->formName = $formName;
        $this->fileName = $fileName;
        $this->maxSize = $maxSize;
        $this->allowMime = $allowMime;
        $this->allowExt = empty($allowExt) ? $this->imgArr : $allowExt;//默认只允许图片上传
        $this->uploadPath = $uploadPath;
        if (empty($_FILES[$this->formName])) {
            $this->error = '未获取到' . $this->formName . '表单$_FILES内容!';
            $this->showError();
        } else {
            $this->fileInfo = $_FILES[$this->formName];
        }

    }

    private function checkError()
    {
        if (empty($this->fileInfo)) {
            $this->error = '上传文件信息为空';
            return false;
        } else {
            if ($this->fileInfo['error'] == 0) {
                return true;
            } else {
                switch ($this->fileInfo['error']) {
                    case 1:
                        $this->error = '超出了php.ini中文件upload_max_filesize设置大小';
                        break;
                    case 2:
                        $this->error = '超出了表单MAX_FILE_SIZE的文件大小';
                        break;
                    case 3:
                        $this->error = '文件被部分上传';
                        break;
                    case 4:
                        $this->error = '没有选择上传文件';
                        break;
                    case 6:
                        $this->error = '没有临时文件夹';
                        break;
                    case 7:
                        $this->error = '文件无法写入磁盘';
                        break;
                    case 8:
                        $this->error = 'PHP未开启上传扩展或PHP扩展程序中断!';
                        break;
                    default:
                        $this->error = '发生未知错误:' . $this->fileInfo['error'];
                        break;
                }
            }
            return false;
        }

    }

    private function checksize()
    {
        if ($this->fileInfo['size'] > $this->maxSize) {
            $this->error = '上传文件超过限制!';
            return false;
        } else {
            return true;
        }
    }

    private function checkExt()
    {
        $this->ext = strtolower(pathinfo($this->fileInfo['name'], PATHINFO_EXTENSION));
        if (in_array($this->ext, $this->imgArr)) {
            //如果扩展名是图片,就进行检测
            $this->img = @getimagesize($this->fileInfo['tmp_name']);//读取图片信息
            if (empty($this->img)) {
                $this->error = '图片不能识别(可能不是真实图片)!';
                return false;
            } else {
                $typearr = array(1 => 'gif', 2 => 'jpg', 3 => 'png');
                $this->ext = $typearr[$this->img[2]];
                $this->imgFlag = 1;//初步检测为图片,等下一步重绘操作!
            }
        }
        if (in_array($this->ext, $this->allowExt)) {
            return true;
        } else {
            $this->error = '不允许的扩展名!';
            return false;
        }
    }

    private function checkMime()
    {
        if (in_array($this->fileInfo['type'], $this->allowMime)) {
            return true;
        } else {
            $this->error = '不允许的文件类型!';
            return false;
        }
    }

    private function checkHTTPPost()
    {
        if (is_uploaded_file($this->fileInfo['tmp_name'])) {
            return true;
        } else {
            $this->error = '不是通过HTTP Post方式上传的!';
            return false;
        }
    }

    public function showError()
    {
        $this->error = empty($this->error) ? '未定义错误通知!' : $this->error;
        return $this->error;
    }

    private function creatFolder()
    {
        if (is_dir($this->uploadPath) || (!is_dir($this->uploadPath) && @mkdir($this->uploadPath, 0777, true))) {
            return true;
        } else {
            $this->error = '上传目录不存在并无法创建,请检测目录权限!';
            return false;
        }
    }

    public function uploadFile()
    {
        if ($this->checkError() && $this->checksize() && $this->checkExt() && $this->checkMime() && $this->checkHTTPPost() && $this->creatFolder()) {
            $this->destination = $this->uploadPath . $this->fileName . '.' . $this->ext;
            $this->returnArr = array('fileName' => $this->fileName, 'ext' => $this->ext, 'path' => $this->uploadPath, 'size' => $this->fileInfo['size'], 'isImg' => $this->imgFlag, 'destination' => $this->destination);
            if ($this->imgFlag == 1) {
                //对图片进行重绘操作,防止图片木马
                if ($this->ext == 'gif') {
                    @$im = imagecreatefromgif($this->fileInfo['tmp_name']);
                } elseif ($this->ext == 'png') {
                    @$im = imagecreatefrompng($this->fileInfo['tmp_name']);
                } else {
                    @$im = imagecreatefromjpeg($this->fileInfo['tmp_name']);
                }
                if ($im == false) {
                    $this->error = '重绘图片失败!';
                    $this->showError();
                } else {
                    //按格式保存并返回
                    if ($this->ext == 'gif') {
                        imagegif($im, $this->destination);
                    } elseif ($this->ext == 'png') {
                        imagepng($im, $this->destination);
                    } else {
                        imagejpeg($im, $this->destination, 80);
                    }
                    imagedestroy($im);//销毁一图像
                    return $this->returnArr;
                }
            } else {
                if (move_uploaded_file($this->fileInfo['tmp_name'], $this->destination)) {
                    return $this->returnArr;
                } else {
                    $this->error = '移动文件失败!';
                    $this->showError();
                }
            }
        } else {
            $this->showError();
        }
    }

}

使用方式:

    require('upload.class.php');
    $upload_handler = new UploadHandler(
        $formName = 'files',//表单名
        $fileName = time() . rand(100000, 999999),//文件名
        '/uploads/'//上传目录
    );
    $imgResult = $upload_handler->uploadFile();//上传文件
    print_r($imgResult);//返回的信息

默认情况下只允许上传图片,可以通过传入参数的方式限制或者允许上传的文件类型,扩展名。当程序检测到上传的是图片类型时,将会自动对图片进行重绘操作,JPG格式会按80%的压缩率优化。

除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:http://www.neter8.com/php/27.html

下一篇 »:好用的jQuery2.X文件上传插件,使用HTML5+JS«上一篇:使用js实现键盘翻页,利用json减少代码。

《一个可以防止图片木马的PHP上传类》相关文章推荐阅读

《一个可以防止图片木马的PHP上传类》的网友评论(0)

感谢打赏!