PHP学习笔记 02 之文件上传

我们了解了表单传值后,这些我就可以完成PHP的文件上传了。我们了解PHP文件上传前,先了解PHP文件上传的原理。

一、PHP上传文件原理

  1. 第一步:将本地的文件通过form表单上传到服务器的临时目录中,临时目录是默认的,但我们可以修改,修改方式最后讲;
  2. 第二步:将上传的文件从临时目录中移动到指定目录中.。

二、form表单注意事项

  • method属性必须是: method = ‘post’
  • enctype属性必须是:enctype = multipart/form-data , 对上传文件进行编码,文件上传并不是上传的文件本身,而是上传文件的编码,由服务器端对编码进行分析。

三、简单的文件上传功能实现

1、思路分析

对于上面error字段的错误信息说明,php官方手册上给出了解释:

UPLOAD_ERR_OK
: 其值为 0,没有错误发生,文件上传成功。

UPLOAD_ERR_INI_SIZE
: 其值为 1,上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值。

UPLOAD_ERR_FORM_SIZE
: 其值为 2,上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。

UPLOAD_ERR_PARTIAL
: 其值为 3,文件只有部分被上传。

UPLOAD_ERR_NO_FILE
: 其值为 4,没有文件被上传。

UPLOAD_ERR_NO_TMP_DIR
: 其值为 6,找不到临时文件夹。PHP 4.3.10 和 PHP 5.0.3 引进。

UPLOAD_ERR_CANT_WRITE
: 其值为 7,文件写入失败。PHP 5.1.0 引进。

我们知道如何获取临时文件信息后,根据原理我们只需要做以下几件事就可以实现文件上传功能:

  1. 得到临时文件,即得到文件的路径,就是数组里的tmp_name;
  2. 自定义一个目录,然后加上文件名,然后拼接成文件路径,如‘E:/uploads/1.jpg’,我们上次的文件名就是数组里的name;
  3. 然后将临时文件移动到自定义的目录,这里我们会用到 move_uploaded_file 函数,关于这个函数如下说明:

2、代码实现

(1)前台test.html

<!--  
Created by phpstrom
USER: 冷魅蘇
Date: 2019/4/27
Time: 17:00
-->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Examples</title>
</head>
<body>
<form action="upload.php" method="post" enctype="multipart/form-data">
    <label for="myfile">上传文件:</label>
    <input type="file" id="myfile" name="myfile">
    <br>
    <input type="submit" value="提交">
</form>
</body>
</html>

(2)后台upload.php

<?php
/*
* Created by phpstrom
* USER: 冷魅蘇
* Date: 2019/4/27
* Time: 17:02
*/
echo '<pre size="16">';
//得到临时文件
$tmpName = $_FILES['myfile']['tmp_name'];
//对应保存的目录
$fileName = 'E:/uploads/'. $_FILES['myfile']['name'];
//移动临时文件到目录
move_uploaded_file($tmpName,$fileName);

开心,文件上传已经实习了,但问题很大。

四、完善上传代码upload.php

1、简单的文件上传代码漏洞分析

上述的文件上传我们是已经实习了,但有几点问题:

  1. 自定义的文件目录是否存在,如果根本没有这个文件夹,会出现错误。所以,我们要检查是否有该文件夹,如果没有就创建。
  2. 文件上传到临时目录可能会出现错误,所以错误信息我们还是要显示出来的;
  3. 文件上传的大小要限制,不限制是不合理的,我们限制文件上传大小可以通过前台js限制,也可以通过php.ini中配置相应的参数(后面会说明),但我们还是要通过PHP代码进行判断;
  4. 我们常见的有头像上传、视频上传、文本上传等,所有我们对于不同的功能应该规定上传的文件类型;
  5. 我们保存的文件名不应该是同样的,否则每次上传就把原文件给覆盖了,但如何你需要把原文件给覆盖也可以,但生成不同的文件名保存,这个功能也应该是需要具备的;
  6. 临时文件的移动可能会出错,所以错误处理我们需要加上去;
  7. 文件保存的目录、文件上传的大小、上传的文件类型还有name的名称,这些我们都是可能变的,我们不可以固定不变,所以我们要把上面的全部封装成函数,以变量传参的方式来实习文件上传。

2、完善后的upload.php

下面直接给出修改后的代码,具体思路代码注释里面有说明:

<?php
/*
* Created by phpstrom
* USER: 冷魅蘇
* Date: 2019/4/25
* Time: 22:15
*/
/**
 * @param $file     前台post提交的文件信息
 * @param $mime     定义上传文件的类型
 * @param $maxSize  定义上传文件的大小
 * @param $path     定义保存的路径
 * @return          返回上传成功的文件名或错误信息码
 */
function upload($file,$mime,$maxSize,$path){
    //检查是否有该文件夹,如果没有就创建,并给予最高权限
    if (!file_exists ($path)) {
        if (!mkdir ("$path", 0777, true)) {      //创建文件夹,没成功返回4010
            return 4010;
        }
    }

    //判断文件上传到临时目录的错误
    switch ($file['error']){
        case 1:
            return 4001;     //'上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值'
            break;
        case 2:
            return 4002;     //'上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值'
            break;
        case 3:
            return 4003;     //'文件上传不完整'
            break;
        case 4:
            return 4004;     //'没有文件被上传'
            break;
        case 6:
            return 4005;     //'服务器内部错误,文件写入失败'
            break;
        case 7:
            return 4006;     //'服务器内部错误,文件写入失败'
            break;
    }

    if ($file['size']>$maxSize){
        return 4007;     //'文件上传大小超过限制'
    }

    //判断用户的上传文件的类型是合法,in_array() 数组查询
    if (!in_array($file['type'],$mime)){
        return 4008;     //"上传文件必须是图片"
    }

    //得到临时文件名
    $tmp = $file['tmp_name'];

    //调用函数生成随机的文件名
    $fileName = getRandFileName();

    //获取文件的扩展名
    $ext = pathinfo($file['name'],PATHINFO_EXTENSION);

    //拼接成保存的文件名
    $baseName = $fileName.'.'.$ext;

    //拼接路径
    $destination = $path.$baseName;

    //如果文件合法,则将临时文件夹中的文件移动到指定的文件夹,并指定文件名
    if (move_uploaded_file($tmp,$destination)){
        return '上传成功,保存的文件名为:'.$baseName;
    }else{
        return 4009;
    }
}

/**
 * 随机文件名的格式,时间戳+随机6位的大小写字母和数字的组合
 * mt_rand(x,y)  x,y的随机整数
 * chr 字符转换
 * ASCII码表:97-122 小写字母  65-90大写字母
 */
function getRandFileName(){
    //将时间戳转成我们想要的格式
    $str = date('YmdHis',time());
    for($i=0; $i<6; $i++){
        switch (mt_rand(0,2)){      //随机从小写字母、大写字母、数字取一个
            case 0:
                $str .= chr(mt_rand(97,122));
                break;
            case 1:
                $str .= chr(mt_rand(65,90));
                break;
            case 2:
                $str .= mt_rand(0,9);
                break;
        }
    }
    return $str;
}

//文件上传信息手册
$errorInfo = [
    '4001' => '上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值',
    '4002' => '上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值',
    '4003' => '文件上传不完整',
    '4004' => '没有文件被上传',
    '4005' => '服务器内部错误,文件写入失败',
    '4006' => '服务器内部错误,文件写入失败',
    '4007' => '文件上传大小超过限制',
    '4008' => '上传文件必须是图片',
    '4009' => '文件从临时文件夹移动到上传文件夹失败',
    '4010' => '保存文件的目录创建失败,请确定目录是否合法'
];
//文件保存的文件夹
$path = 'E:/uploads/';
//定义文件上传的大小3MB
$maxSize = 1024*1024*3;
//定义允许用户上传的mime类型,现控制在图片上传
$mime = ['image/jpeg','image/jpg','image/pjpeg','image/png','image/gif'];
$file = $_FILES['myfile'];

$res = upload($file,$mime,$maxSize,$path);


echo '<pre style="font-size: 14px;">';
echo '<h3>临时文件上传信息</h3>';
var_dump($_FILES['myfile']);
echo '<h3>错误信息手册,显示文件名称上传成功</h3>';
var_dump($errorInfo);
echo $res;

说明:文件类型(MIME)

常见的几种类型:

欢喜,我们的文件上传功能就此完成。下面我们说明一下对于文件上传,php.ini的相关配置,php.ini文件就在你安装的php目录下。

五、php.ini相关参数

1. upload_tmp_dir //修改上传文件的临时目录
upload_max_filesize //上传允许的单文件的最大值
max_file_uploads //上传文件的允许最大数量

2. post_max_size //上传所有文件字节允许的最大值

声明:本文欢迎大家评论和转载,使用本文章或代码还请声明,且在使用处的明显位置给出。如有其它问题或有什么建议,可在下方评论,或加QQ(1414782205),或发邮箱[email protected]

猜你喜欢

转载自www.cnblogs.com/jcdjor/p/10779760.html