PHP基础之文件的上传与下载

文件上传与下载

文件上传

  • 文件上传表单
    • 表单的提交方式必须为POST
    • enctype="multipart/form-data"
      • 说明浏览器可以提供文件上传功能
      • 该属性提示表单中有二进制文件数据
      • <input type="hidden" name="max_file_size" value="30000">
        • 可以指定允许上传文件的最大尺寸
        • MAX_FILE_SIZE必须在文件域的上面。
<!-- form.html -->
<form action="upload.php" enctype="multipart/form-data" method="post">
  <input type="hidden" name="max_file_size" value="30000">
  选择文件:<input type="file" name="userfile">
  <input type="submit" value="上传文件">
</form>
  • 文件域 表单的enctype属性

    • 默认情况下,表单传递是字符流,不能传递二进制流
    • 通过设置表单的enctype属性传递复合数据
    • enctype属性的值有
      • application/x-www-form-urlencoded (默认)表示传递的是带格式的文本数据
      • multipart/form-data 复合的表单数据(字符串\文件),文件上传必须设置此值
      • text/plain 用于向服务器传递无格式的文本数据,主要用户电子邮件
  • PHP处理上传文件

    • PHP会自动生成一个$_FILES二维数组,该数组保存了上传文件的信息
# upload.php
<?php
    $name= $_FILES['userfile']['name'];
    $type= $_FILES['userfile']['type'];
    $size= $_FILES['userfile']['size'];
    $tmpName= $_FILES['userfile']['tmp_name'];
    $error= $_FILES['userfile']['error'];
    echo "{$name}<br>{$type}<br>{$size}<br>{$tmpName}<br>{$error}";
?>
  • $_FILES['userfile'] 键值说明

    • $_FILES['userfile']['name'] 上传文件的名称
    • $_FILES['userfile']['type'] 上传文件的MIME类型(image/jpeg、image/gif、image/png)
    • $_FILES['userfile']['size'] 上传文件的大小,以字节为单位
    • $_FILES['userfile']['tmp_name'] 文件上传时的临时文件
    • $_FILES[][‘error’] 错误编码(值有0、1、2、3、4、6、7)
      • 0 - 正确
      • 4 - 没有文件上传
      • 1 - 文件大小超过了php.ini中允许的最大值 upload_max_filesize = 2M
      • 2 - 文件大小超过了表单允许的最大值
      • 3 - 只有部分文件上传
      • 6 - 找不到临时文件
      • 7 - 文件写入失败
  • 与文件上传有关的配置

    • post_max_size = 8M 表单允许的最大值
    • upload_max_filesize = 2M 允许上传的文件大小
    • upload_tmp_dir =F:\wamp\tmp 指定临时文件地址,如果不知道操作系统指定
    • file_uploads = On 是否允许文件上传
    • max_file_uploads = 20 允许同时上传20个文件
<?php
  echo ini_get('post_max_size');
  echo ini_get('upload_max_filesize');
  echo ini_get('upload_tmp_dir');
  echo ini_get('file_uploads');
  echo ini_get('max_file_uploads');
?>
  • 将上传文件移动到指定位置
    • move_uploaded_file() 临时地址,目标地址
    • 上传的同名的文件要给覆盖
# upload.php
<?php
  mkdir('D:\Program Files\xampp\htdocs\uploads');
  $newDir= "uploads/".$_FILES['userfile']['name'];
  if(!empty($_POST)) {
    if($_FILES['userfile']['error']== 0){  
      if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
        echo "上传成功";
      };
    }else{
      echo '上传有误';
      echo '错误码:'.$_FILES['userfile']['error'];
      exit;
    }
  }
?>

优化文件上传

  • 更改文件名
    • 通过时间戳做文件名
    • 通过uniqid()实现
      • uniqid() 生成唯一的ID
      • uniqid('goods_') 带有前缀
      • uniqid('goods_',true) 唯一ID+随机数
# upload.php
<?php
    # 判断是否存在目录
    $dir= 'D:\Program Files\xampp\htdocs\uploads';
    if(!is_dir($dir)){
        mkdir($dir);
    }
    # 通过时间戳做文件名
    $newName= time().rand(100,999).strrchr($_FILES['userfile']['name'],'.'); 
    $newDir= "uploads/".$newName;
    # 上传服务处理
    if(!empty($_POST)) {
        if($_FILES['userfile']['error']== 0){  
            if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
                echo "上传成功";
            };
        }else{
            echo '上传有误';
            echo '错误码:'.$_FILES['userfile']['error'];
            exit;
        }
    }
?>
# upload.php
<?php
    # 判断是否存在目录
    $dir= 'D:\Program Files\xampp\htdocs\uploads';
    if(!is_dir($dir)){
        mkdir($dir);
    }
    # 通过uniqid()实现
    $newName= uniqid('goods_',true).strrchr($_FILES['userfile']['name'],'.'); 
    $newDir= "uploads/".$newName;
    # 上传服务处理
    if(!empty($_POST)) {
        if($_FILES['userfile']['error']== 0){  
            if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
                echo "上传成功";
            };
        }else{
            echo '上传有误';
            echo '错误码:'.$_FILES['userfile']['error'];
            exit;
        }
    }
?>
  • 验证文件格式
    • 将文件的后缀和允许的后缀对比 (不能识别文件伪装)
    • 通过$_FIELS[]['type']类型判断 (不能识别文件伪装)
    • 在php.ini中开启fileinfo扩展 (可以防止文件伪装)
# # upload.php
<?php
  if(!empty($_POST)) {
    # 判断是否存在目录
    $dir= 'D:\Program Files\xampp\htdocs\uploads';
    if(!is_dir($dir)){
      mkdir($dir);
    }
    # 通过uniqid()实现重命名
    $newName= uniqid('goods_',true).strrchr($_FILES['userfile']['name'],'.'); 
    $newDir= "uploads/".$newName;
    # 文件名拓展名验证
    $allow= array('.jpg','.png','.gif');
    $ext= strrchr($_FILES['userfile']['name'],'.');
    if(!in_array($ext,$allow)){
      echo '文件上传不合法';
      exit;
    }
    # 上传服务处理
    if($_FILES['userfile']['error']== 0){  
      if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
        echo "上传成功";
      };
    }else{
      echo '上传有误';
      echo '错误码:'.$_FILES['userfile']['error'];
      exit;
    }
  }
?>
# upload.php
<?php
  if(!empty($_POST)) {
    # 判断是否存在目录
    $dir= 'D:\Program Files\xampp\htdocs\uploads';
    if(!is_dir($dir)){
      mkdir($dir);
    }
    # 通过uniqid()实现重命名
    $newName= uniqid('goods_',true).strrchr($_FILES['userfile']['name'],'.'); 
    $newDir= "uploads/".$newName;
    # 文件名拓展名验证
    $allow= array('image/jpeg','image/png','image/gif');
    $ext= $_FILES['userfile']['type'];
    if(!in_array($ext,$allow)){
      echo '文件上传不合法';
      exit;
    }
    # 上传服务处理
    if($_FILES['userfile']['error']== 0){  
      if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
        echo "上传成功";
      };
    }else{
      echo '上传有误';
      echo '错误码:'.$_FILES['userfile']['error'];
      exit;
    }
  }
?>
# upload.php
<?php
  if(!empty($_POST)) {
    # 判断是否存在目录
    $dir= 'D:\Program Files\xampp\htdocs\uploads';
    if(!is_dir($dir)){
      mkdir($dir);
    }
    # 通过uniqid()实现重命名
    $newName= uniqid('goods_',true).strrchr($_FILES['userfile']['name'],'.'); 
    $newDir= "uploads/".$newName;
    # 文件名拓展名验证
    $info=finfo_open(FILEINFO_MIME_TYPE);
    $ext= finfo_file($info, $_FILES['userfile']['tmp_name']);
    $allow= array('image/jpeg','image/png','image/gif');
    if(!in_array($ext,$allow)){
      echo '文件上传不合法';
      exit;
    }
    # 上传服务处理
    if($_FILES['userfile']['error']== 0){  
      if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
        echo "上传成功";
      };
    }else{
      echo '上传有误';
      echo '错误码:'.$_FILES['userfile']['error'];
      exit;
    }
  }
?>
  • 优化文件上传
<?php
    if(!empty($_POST)) {
        # 判断是否存在目录
        $dir= 'D:\Program Files\xampp\htdocs\uploads';
        if(!is_dir($dir)){
            mkdir($dir);
        }
        # 通过uniqid()实现重命名
        $newName= uniqid('goods_',true).strrchr($_FILES['userfile']['name'],'.'); 
        $newDir= "uploads/".$newName;
        # 文件名拓展名验证
        $info=finfo_open(FILEINFO_MIME_TYPE);
        $ext= finfo_file($info, $_FILES['userfile']['tmp_name']);
        $allow= array('image/jpeg','image/png','image/gif');
        if(!in_array($ext,$allow)){
            echo '只能上传 '.implode(' , ',$allow).' 等文件格式';
            exit;
        }
        # 验证文件大小
        $fileSize= ini_get('upload_max_filesize');
        if(substr($fileSize, -1, 1)== 'k'){
            $fileSize= (integer)$fileSize* 1024;
        }elseif(substr($fileSize, -1, 1)== 'M'){
            $fileSize= (integer)$fileSize* 1024* 1024;
        }elseif(substr($fileSize, -1, 1)== 'G'){
            $fileSize= (integer)$fileSize* 1024* 1024* 1024;
        }elseif(substr($fileSize, -1, 1)== 'T'){
            $fileSize= (integer)$fileSize* 1024* 1024* 1024* 1024;
        }
        if($_FILES['userfile']['size']> $fileSize){
            echo '文件大小不能超过'.number_format($fileSize/1024, 1).'K';
            exit;
        }
        # 验证是否是http上传
        if(!is_uploaded_file($_FILES['userfile']['tmp_name'])){
            echo '文件不是HTTP POST上传的<br>';
            exit;
        }
        # 上传服务处理
        if($_FILES['userfile']['error']== 0){  
            if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
                echo "上传成功";
            };
        }else{
            switch($_FILES['userfile']['error']) {
                case 1:
                    echo '文件大小超过了php.ini中允许的最大值,最大值是:'.ini_get('upload_max_filesize');
                    break;  
                case 2:
                    echo '文件大小超过了表单允许的最大值';
                    break; 
                case 3:
                    echo '只有部分文件上传';
                    break; 
                case 4:
                    echo '没有文件上传';
                    break; 
                case 6:
                    echo '找不到临时文件';
                    break; 
                case 7:
                    echo '文件写入失败';
                    break; 
                default:
                    echo '未知错误';
                    break; 
            }
        }
    }
?>

文件下载

  • 方法解释

    • __FILE__ 当前文件的带文件名的绝对路径
    • dirname(__FILE__) 返回路径中的目录部分
    • iconv() 文件编码转换
    • feof() 检测流上的文件结束符的函数,如果文件结束,则返回非0值,否则返回0
  • 响应头设置

    • Content-type: application/octet-stream 指定文件类型
    • Content-Disposition: attachment; filename={$file_name} 指定文件描述
<?php
    header('Content-Type:text/html; charset=utf-8');
    define('ROOT_PATH', dirname(__FILE__));

    function downfile($file_path){
        $file_path= iconv('utf-8', 'gb2312', $file_path);
        if(!file_exists($file_path)){
            exit('文件不存在!');
        }

        $file_name= basename($file_path);
        $file_size= filesize($file_path);
        $file= fopen($file_path, 'r');
        header("Content-type: application/octet-stream");
        header("Content-Disposition: attachment; filename={$file_name}");

        $buffer= 1024;
        $file_count= 0;

        while(!feof($file) && ($file_size- $file_count> 0)){
            $file_data= fread($file, $buffer);
            $file_count+= $buffer;
            echo $file_data;
        }

        fclose($file);
    }
    downfile(ROOT_PATH.".\img\pigger.jpg");
?>
posted @ 2020-11-23 11:45  wing1377  阅读(210)  评论(0编辑  收藏  举报