文件上传

文件上传类

<?php

/**
 * 文件上传
 *
 * 前台使用
 * <link rel='stylesheet' type='text/css' href='/Public/static/kcs/kcs.css'>
 * <script src='/Public/static/kcs/kcs.src.js'></script>
 * <script src='/Public/static/kcs/kcs.js'></script>
 * <script> KCS.uploader(el,{ '120', height:'120', url:'{:U('upload')}'}); </script>
 */
class Upload
{

    const CHUNK_UPLOADED = 1;

    const FILE_UPLOADED = 2;

    // 配置项 : 允许上传的文件类型,不区分大小写
    protected $allowedType = array(
            'jpg',
            'jpeg',
            'png',
            'bmp',
            'gif',
            'txt',
            'doc',
            'docx',
            'xls',
            'xlsx',
            'ppt',
            'pptx',
            'pdf',
            'zip',
            'rar',
            'mp3',
            'wav',
			'csv'
    );

    // 配置项 : 临时文件过期时间, 单位秒(s)
    protected $tempFileExpire = 3600;

    // 配置项 : 文件上传完毕后移动到此目录, 默认不移动
    protected $uploadDir = null;

    // 配置项 : 文件自动保存目录的 web 路径, 未配置时使用 /+$uploadDir 作为默认值
    protected $uploadPath = null;

    // 配置项 : 文件上传临时目录, 必填
    protected $tempDir = null;

    // 配置项 : 文件临时目录的 web 路径, 未配置时使用 /+$tempDir 作为默认值
    protected $tempPath = null;

    // 配置项 : 上传成功回调
    protected $success = null;

    // 配置项 : 上传错误回调
    protected $error = null;

    // 当前上传文件的[临时]文件名
    protected $filename = null;

    // 当前上传文件的[原始]文件名
    protected $filenameOri = null;

    // 当前上传文件的[存储]文件名
    protected $filenameSave = null;

    // 当前文件类型
    protected $fileType = null;

    // 错误通知类型
    protected static $notifyInfo = array(
            1000 => '无法获取文件名',
            1001 => '文件名不合法',
            1002 => '创建临时文件失败',
            1003 => '文件上传错误',
            1004 => '文件未上传',
            1005 => '无法读取上传临时文件',
            1006 => '无法读取输入流',
            1007 => '无法移动文件到上传目录',
            1008 => '无法移动文件到临时目录',
            1009 => '创建上传目录失败',
            1010 => '未设置临时目录',
            1011 => '创建临时目录失败',
            1012 => '文件类型错误'
    );

    protected $application;

    protected $webPath;

    static $instace;

    public static function getInstance ()
    {
        return self::$instace ?  : self::$instace = new self();
    }

    /**
     * 文件上传处理流程
     */
    public function handle ($config = array(), $return = true)
    {
        try
        {
            $this->_loadConfig($config);

            // 获取文件信息
            $this->_loadFileinfo();

            // 文件保存路径
            $filePath = $this->tempDir . $this->filename . '.part';

            // 清理过期文件
            // $this->_cleanUp();

            // 分段上传 : 当前分段序号
            $chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;

            // 分段上传 : 分段总数
            $chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 0;

            // 打开或创建临时文件
            $out = fopen("{$filePath}", $chunks ? "ab" : "wb") or $this->_notify(1002);

            // 从上传文件或输入中读取数据
            if (! empty($_FILES) && isset($_FILES['kcs_uploader_file']))
            {
                $_FILES["kcs_uploader_file"]["error"] and $this->_notify(1003, $_FILES["file"]["error"]);
                is_uploaded_file($_FILES["kcs_uploader_file"]["tmp_name"]) or $this->_notify(1004);
                $in = fopen($_FILES["kcs_uploader_file"]["tmp_name"], "rb") or $this->_notify(1005);
            }
            else
            {
                $in = fopen("php://input", "rb") or $this->_notify(1006);
            }

            // 追加到临时文件
            while ($buff = fread($in, 4096))
            {
                fwrite($out, $buff);
            }
            fclose($out);
            fclose($in);

            // 分段上传
            if ($chunks && $chunk < $chunks - 1)
            {
                return $this->_notify(self::CHUNK_UPLOADED);
            }

            // 上传完毕
            if (! $chunks || $chunk == $chunks - 1)
            {
                // 重命名上传文件
                $newFilename = (is_null($this->filenameSave) ? uniqid(rand(100, 999)) : $this->filenameSave)
                    . '.' . $this->fileType;

                // 上传图片临时路径
                $newFile = $this->tempDir . $newFilename;
                // 上传图片的 web 路径
                $webPath = $this->tempPath . $newFilename;
                // 重命名临时文件
                copy($filePath, $newFile) or $this->_notify(1008, $filePath . '=>' . $newFile);
                unlink($filePath);

                // web 路径修正
                $webPath = str_replace('\', '/', $webPath);

                // 发送成功通知
                $response = array(
                        'url' => $webPath,
                        'file' => $newFile,
                        'title' => $this->filenameOri
                );
                $this->_notify(self::FILE_UPLOADED, $response);
            }
        }
        catch (Exception $e)
        {
            $this->_notify(- 1, $e->getMessage());
        }
    }

    /**
     * 移动上传文件
     */
    public function move ($webPath, $config = array())
    {
        $this->_loadConfig($config);

        $path = $this->tempDir ?  : $this->uploadDir;
        $oldFile = $path . substr($webPath, strlen($path) - 1);
        $newFile = $this->uploadDir . basename($oldFile);

        if (! file_exists($oldFile))
        {
            throw new Exception("文件不存在 : $oldFile");
        }

        // 未配置临时目录时, 不需要移动上传文件
        $status = $oldFile == $newFile;
        $status or $status = (copy($oldFile, $newFile) and unlink($oldFile));

        if (! $status)
        {
            throw new Exception("移动文件失败 : $oldFile -> $newFile");
        }

        $fileInfo = array(
                'path' => $newFile,
                'url' => $this->uploadPath . basename($newFile),
                'md5' => md5_file($newFile),
                'sha1' => sha1_file($newFile)
        );

        return $fileInfo;
    }

    /**
     * 加载配置项, 并校验
     */
    protected function _loadConfig ($config)
    {
        is_array($config) or $config = array();
        foreach ($config as $_key => $_value)
        {
            if (property_exists($this, $_key))
            {
                $this->$_key = $_value;
            }
        }

        // 检查临时目录
        ($this->tempDir = $this->tempDir ?  : $this->uploadDir) or $this->_notify(1010);
        if (! file_exists($this->tempDir))
        {
            mkdir($this->tempDir, 0777, true) or $this->_notify(1011, $this->$this->tempDir);
        }

        $this->tempDir = rtrim($this->tempDir, '/') . '/';

        // 修正临时目录 web 路径
        $this->tempPath or $this->tempPath = '/' . trim($this->tempDir, './');
        $this->tempPath = rtrim($this->tempPath, '/') . '/';

        // 检查上传目录
        if (! $this->uploadDir)
        {
            return;
        }

        // 创建上传目录
        if (! file_exists($this->uploadDir))
        {
            mkdir($this->uploadDir, 0777, true) or $this->_notify(1009, $this->uploadDir);
        }

        $this->uploadDir = rtrim($this->uploadDir, '/') . '/';

        // 修正上传目录 web 路径
        $this->uploadPath or $this->uploadPath = '/' . trim($this->uploadDir, './');
        $this->uploadPath = rtrim($this->uploadPath, '/') . '/';
    }

    /**
     * 获得上传文件的文件名和类型并校验
     */
    protected function _loadFileinfo ()
    {
        if (isset($_REQUEST["name"]))
        {
            $filename = $_REQUEST["name"];
        }
        elseif (! empty($_FILES))
        {
            $filename = @$_FILES["kcs_uploader_file"]["name"];
        }
        else
        {
            // 获取文件名失败
            $this->_notify(1000);
        }

        // 文件名只允许包含 数字,字母,下划线和点号
        // preg_match('/^[a-zA-Z0-9_.]+$/', $filename) or $this->_notify(1001, '文件名无效 : ' . $filename);

        $this->filenameOri = $filename;
        $filetype = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
        $this->filename = md5($_REQUEST['kcs_uploader_id'] . $filename) . '.' . $filetype;

        // 文件类型检测
        in_array($filetype, $this->allowedType) or $this->_notify(1012, '文件类型无效 : ' . $filetype);

        $this->fileType = $filetype;
    }

    /**
     * 清除过期的临时文件, 删除的临时文件写入清理日志
     */
    protected function _cleanUp ($targetDir)
    {
        while (($file = readdir($this->tempDir)) !== false)
        {
            $tmpfilePath = $this->tempDir . $file;

            // Remove temp file if it is older than the max age and is not the current file
            if (filemtime($tmpfilePath) < time() - $this->tempFileExpire)
            {
                $filesize = number_format(filesize($tmpfilePath) / (1024 * 1024), 2) . 'KB';
                @$status = unlink($tmpfilePath);
                self::_log("清理过期临时文件 [" . ($status ? '1' : '0') . "] : $file (" . $filesize . ")");
            }
        }
        closedir($dir);
    }

    /**
     * 发送通知
     */
    protected function _notify ($status = '', $info = null)
    {
        $json = array(
                'jsonrpc' => '2.0',
                'id' => 'id'
        );

        // 分段上传完毕
        if ($status == self::CHUNK_UPLOADED)
        {
            exit(json_encode($json));
        }

        // 文件上传完毕
        if ($status == self::FILE_UPLOADED)
        {
            $json['result'] = $info;
            if (is_callable($this->success))
            {
                return call_user_func($this->success, $json);
            }
            exit(json_encode($json));
        }

        // 返回错误信息
        $msg = self::$notifyInfo[$status] ?  : $info;
        $json['error'] = array(
                'code' => $status,
                'message' => $msg
        );
        self::_log($msg . ' | ' . $info);
        if (is_callable($this->error))
        {
            return call_user_func($this->error, $msg);
        }
        exit(json_encode($json));
    }

    protected function _log ($msg)
    {
        function_exists('_log') && _log($msg);
    }
}

  调用文件上传

  1 <?php
  2 $operate=$_REQUEST["operate"];
  3 $operate=empty($operate)?"upload":$operate;
  4 
  5 switch ($operate){
  6     case 'upload';
  7         file_upload();
  8         break;
  9     case 'download';
 10         file_download();
 11         break;
 12     case 'del';
 13         file_del();
 14         break;
 15 }
 16 
 17 function file_download(){
 18     $file_code=intval($_REQUEST["file_code"]);
 19     $sql="select FILE_PATH,FILE_NAME from app_file where DOWN_CODE='{$file_code}' and STATUS='1'";
 20     $file_info=N_query($sql);
 21     if(!empty($file_info)){
 22         $file_info=$file_info[1];
 23         //以只读和二进制模式打开文件
 24         $file = fopen ( $file_info["FILE_PATH"], "rb" );
 25 
 26         //告诉浏览器这是一个文件流格式的文件
 27         Header ( "Content-type: application/octet-stream" );
 28         //请求范围的度量单位
 29         Header ( "Accept-Ranges: bytes" );
 30         //Content-Length是指定包含于请求或响应中数据的字节长度
 31         Header ( "Accept-Length: " . filesize ( $file_info["FILE_PATH"] ) );
 32         //用来告诉浏览器,文件是可以当做附件被下载,下载后的文件名称为$file_name该变量的值。
 33         Header ( "Content-Disposition: attachment; filename=" . $file_info["FILE_NAME"] );
 34 
 35         //读取文件内容并直接输出到浏览器
 36         echo fread ( $file, filesize ( $file_info["FILE_PATH"] ) );
 37         fclose ( $file );
 38     }
 39 }
 40 
 41 function file_del(){
 42     $file_code=intval($_REQUEST["file_code"]);
 43     $sql="select FILE_PATH,FILE_NAME from app_file where DOWN_CODE='{$file_code}' and STATUS='1'";
 44     $file_info=N_query($sql);
 45     if(!empty($file_info)){
 46         $file_info=$file_info[1];
 47         $current_time=time();
 48         $sql="update app_file set STATUS='0',DEL_TIME={$current_time} where DOWN_CODE='{$file_code}' and STATUS='1'";
 49         N_query($sql);
 50         @unlink( $file_info["FILE_PATH"]);
 51     }
 52     $return_result["status"]=1;
 53     $return_result["msg"]="删除成功";
 54     echo  json_encode($return_result,256);
 55     exit;
 56 
 57 }
 58 
 59 function file_upload(){
 60     $type_arr=["projectLending"];
 61     $type=trim($_REQUEST["type"]);
 62 
 63     $type=empty($type)?"projectLending":$type;
 64     if(!in_array($type,$type_arr)){
 65         throw new Exception("参数错误");
 66     }
 67 
 68     if($type=="projectLending"){
 69         //项目放款流程
 70         uploadProjectLending();
 71     }
 72 }
 73 
 74 function uploadProjectLending(){
 75     $config = array(
 76         // 文件上传目录, 默认不移动
 77         'uploadDir' => './uploads/projectLending/' . date('Y/m/d'),
 78         'success' => 'uploadProjectLendingSuccessReturn',
 79         'error' => 'uploadProjectLendingErrorReturn',
 80         //"allowedType"=>['xls','xlsx','csv'],
 81     );
 82     NUpload::getInstance()->handle($config);
 83 }
 84 function uploadProjectLendingErrorReturn($result){
 85     $return_result["status"]=1;
 86     $return_result["msg"]=$result;
 87     echo  json_encode($return_result,256);
 88     exit;
 89 }
 90 function uploadProjectLendingSuccessReturn($result){
 91     $now_time=time();
 92     $info = $result['result'];
 93     $USR_UID=$_SESSION['USER_LOGGED'];
 94     $APP_UID=trim($_REQUEST["app_uid"]);
 95     $TAS_UID=trim($_REQUEST["tas_uid"]);
 96     $UPLOAD_TYPE='projectLending';
 97     $FILE_NAME=$info['title'];
 98     $FILE_PATH=$info['file'];
 99     $FILE_SIZE=$info["file_size"];
100     $FILE_EXT=$info["file_ext"];
101     $ISIMAGEL=0;
102     $STATUS=1;
103     $UPLOAD_TIME=$now_time;
104     $DEL_TIME=0;
105     $DOWN_CODE=md5($USR_UID."|".$now_time);
106 
107     $sql="insert into app_file (`USR_UID`,`APP_UID`,`TAS_UID`,`UPLOAD_TYPE`,`FILE_NAME`,`FILE_PATH`,`FILE_SIZE`,`FILE_EXT`,`ISIMAGEL`,`STATUS`,`UPLOAD_TIME`,`DEL_TIME`,`DOWN_CODE`) VALUES (
108       '{$USR_UID}','{$APP_UID}','{$TAS_UID}','{$UPLOAD_TYPE}','{$FILE_NAME}','{$FILE_PATH}','{$FILE_SIZE}','{$FILE_EXT}','{$ISIMAGEL}','{$STATUS}','{$UPLOAD_TIME}','{$DEL_TIME}','{$DOWN_CODE}')";
109     N_query($sql);
110 
111 
112     $return_result["status"]=0;
113     $return_result["msg"]="上传成功";
114     $return_result["url"]=$info['url'];
115     $return_result["file_ext"]=$info['file_ext'];
116     $return_result["file_size"]=$info['file_size'];
117     $return_result["title"]=$info['title'];
118     $return_result["file_id"]=$DOWN_CODE;
119     $return_result["time"]=date("Y-m-d H:i:s",$now_time);
120     $return_result["download_url"]="/sysworkflow/zh/neoclassic/ncfpms_ajax/uploadFile?operate=download&file_code=".$DOWN_CODE;
121     $return_result["del_url"]="/sysworkflow/zh/neoclassic/ncfpms_ajax/uploadFile?operate=del&file_code=".$DOWN_CODE;
122     echo json_encode($return_result);
123     exit;
124 }
原文地址:https://www.cnblogs.com/saonian/p/10194260.html