单文件上传

原理

  • 文件从用户本地电脑通过web表单传输到服务器指定目录下

流程

  1. 浏览器请求一个服务器html脚本,包含文件上传表单
  2. 用户选择文件并上传
  3. 服务器将文件保存到临时目录
  4. 服务器脚本开始工作,判断文件有效,将有效文件从tmp目录移到指定目录(文件上传完成)

[zd-plane title=“演示图”]

[/zd-plane]

表单制作

表单包含三个属性:

  • method属性:表单必须用post方式
  • enctype属性:form 表单属性,用来规范表单数据的编码方式
  • action属性:将数据提交给哪里

对应的HTML代码

<form method='post' enctype='multipart/form-data' action='action.php'>
<input type="file" name="image">
<input type="submit" name="submit" value="提交">
</form>

用户看到上传文件和提交按钮,用户提交后,文件上传到服务器临时文件夹

$_FILES值

超预变量**$_FILES,**用来存储用户上传的文件信息

$_FILES包含以下内容

name :

  • 文件在用户电脑实际名字

tmp_name:

  • 文件上传到服务器后临路径

type:

  • 显示文件类型(不能相信name的后缀!!!!!!)

error:

文件上传的代号告知php文件接收中出现的问题

  • 0 上传成功
  • 1 文件超过了php设置的最大值
  • 2 文件超过html表单最大值
  • 3 只有部分文件被上传,出现网络中断
  • 4 没有文件被上传
  • 6 找不到临时文件
  • 7 php没有权限将临时文件移动到指定目录

size:

  • 文件大小

知道_FILES功能后,创建‘\_FILES功能后,创建`_FILES功能后,创建‘file=$_FILES[‘image’]` ;获得文件全部信息。使用

$file['tmp_name'] 将得到文件名xxx.jpg

$file['type'] 文件类型

等等函数来移动文件到目标目录

移动临时文件到目标位置

  1. 判断是否为http上传的文件 is_uploaded_file($filename)
  2. 如果满足条件1则移动文件 move_uploaded_file($filename,$destination)
#创建file变量,取得文件
$file=$_FILES['image']; #这里的名字与表单内input 的file类型的 name一样
#判断是否为上传文件
if(is_uploaded_file($file['tmp_name'])){ 
#将文件移动到新位置,获得文件名字$file['name'];
move_uploaded_file($file['tmp_name'],'diretory'.'/'.$file['name']);
}else{
echo '不是上传文件';
}

以上为单文件上传过程

多文件上传

html代码

同名表单

  • 针对一个要表述的内容,但使用不同文件:同名表单

所有上传的文件属于一个数组

html代码
<input type="file" name="image[]" />
<input type="file" name="image[]" />
<input type="file" name="image[]" />

则$_FILES中,会包含一个image的数组,里面是name属性和type属性等等 每个属性又包含三个值,分别对应三个文件

[zd-plane title=“结果图片”]

[/zd-plane]

不同名表单

  • 表述不同内容:不同名表单

文件有各自的名字,不属于一个数组

html代码
<input type="file" name="head" />
<input type="file" name="body" />
<input type="file" name="footer" />

则$_FILES 将包含 三个类分别为head\body\footer,各自包含自己的name,type等属性。

[zd-plane title=“结果图片”]

[/zd-plane]

多文件遍历

不同名表单遍历

按表单名字直接遍历
foreach ($_FILES as $file){
if(is_uploaded_file($file['tmp_name'])){
if(move_uploaded_file($file['tmp_name'],'./post_files/'.$file['name'])){
echo '上传成功';
}else{
echo '上传失败';
}
}
}

同名表单遍历

因为name\tepe里面各自包含多个变量,那就直接按索引遍历
for ($i = 0; $i < 3; $i++) {
// code...
$files=$_FILES['image'];
if(is_uploaded_file($files['tmp_name'][$i])){
if(move_uploaded_file($files['tmp_name'][$i],'./post_files/'.$files['name'][$i])){
echo '上传成功';
}else{
echo '上传失败';
}
}
}

文件上传的整完代码

  • 包含检测文件类型,大小,检测病毒等功能

[zd-plane title=“文件上传函数”]

  • 以下是action.php内容

upload_single_file函数

<?php
#将上传文件封装成函数
function upload_single_file($file,$allow_type,$path,&$error,$allow_format=[],$max_size=2000000){
    if(is_array($file)&&isset($file['error'])){
         #判断文件error是否有值
    }else{
        $error ='文件无效';
        return false;
    }
    
// 3、判断保存路径是否有效
    if(!is_dir($path)){
        $error='路径无效';
        return false;
    }

// 4、判断文件本身是否有错
    switch($file['error']){
        case 1:
        case 2:
            $error='文件超出服务器允许大小';
            return false;
        case 3:
            $error='文件上传过程出现错误';
            return false;
        case 4:
            $error='未选择要上传的文件';
            return false;
        case 6:
        case 7:
            $error='文件保存失败';
            return false;
    }
    
// 5、判断MIME类型是否允许
    if(!in_array($file['type'],$allow_type)){
        $error='文件类型不合适';
        return false;
    }
    
// 6、判断文件是否过大
    if($file['size']>$max_size){
        $error='文件过大';
        return false;
    }
        
// 7、判断后缀是否允许
    $ext=ltrim(strrchr($file['name'],'.'),'.');
    if(!empty($allow_format) && !in_array($ext,$allow_format)){
        $error='文件后缀不符合!!!只能为jpg,jpeg,png,gif';
        return false;
    }
    
// 8、移到指定目录
    
    if(!is_uploaded_file($file['tmp_name'])){
        $error='不是上传文件';
        return false;
    }
    
    // 判断文件是否已经存在
    $file_path=$path.'/'.$file['name'];
    if(file_exists($file_path)){
        $error='文件已经存在';
        return false;
    }
    
    if(move_uploaded_file($file['tmp_name'],$path.'/'.$file['name'])){
        // 检测文件是否有毒
        if(check_hex($path,$file['name'])==5){
            unlink($path.'/'.$file['name']);
            $error='文件可能包含病毒,上传失败';
            return false;
        }else{
            return true;
            // return $file['name'];
        }

    }else{
        $error='文件上传失败';
        return false;
    }
    
    
}

    $file=$_FILES['image'];
    $path='./post_files';
    $allow_type=['image/jpg','image/jpeg','image/png','image/gif'];
    $allow_format=['jpg','jpeg','png','gif'];
    $max_size=20000000;

    require './check_hex.php';

    
    if(upload_single_file($file,$allow_type,$path,$error,$allow_format,$max_size)){
        // echo $file_name;
        echo '上传成功';
    }else{
        echo $error;
    }

check_hex函数,检测图片是否包含一般病毒

  • 以下是check_hex.php内容
<?php
header("Content-type: text/html; charset=utf-8");
function check_hex($path,$img) {
    $status = 0;
    $tips = array(
        "0" => "文件没问题",
        "5" => "文件有毒",
        "-1" => "文件没有上传"
    );
    echo '<br/>';
    $img=$path.'/'.$img;
    if (file_exists($img)) {
        $resource = fopen($img, 'rb');
        $fileSize = filesize($img);
        fseek($resource, 0);
        if ($fileSize > 512) { // 取头和尾
            $hexCode = bin2hex(fread($resource, 512));
            fseek($resource, $fileSize - 512);
            $hexCode .= bin2hex(fread($resource, 512));
        } else { // 取全部
            $hexCode = bin2hex(fread($resource, $fileSize));
        }
        fclose($resource);
        /* 匹配16进制中的 <% ( ) %> */
        /* 匹配16进制中的 <? ( ) ?> */
        /* 匹配16进制中的 <script | /script> 大小写亦可 */
        if (preg_match("/(3c25.*?28.*?29.*?253e)|(3c3f.*?28.*?29.*?3f3e)|(3C534352495054)|(2F5343524950543E)|(3C736372697074)|(2F7363726970743E)/is", $hexCode)) {
            $status = 5;
        }
    } else {
        $status = -1;
    }
    return $status;
}

[/zd-plane]