16.ThinkPHP 文件上传

Posted 余生随缘~~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了16.ThinkPHP 文件上传相关的知识,希望对你有一定的参考价值。

框架上传功能

上传文件

内置的上传只是上传到本地服务器,上传到远程或者第三方平台的话需要自己扩展。

假设表单代码如下:

<form action="/index/index/upload" enctype="multipart/form-data" method="post">
<input type="file" name="image" /> <br> 
<input type="submit" value="上传" /> 
</form> 

然后在控制器中添加如下的代码:

public function upload(){
    // 获取表单上传文件 例如上传了001.jpg
    $file = request()->file(\'image\');
    // 移动到框架应用根目录/uploads/ 目录下
    $info = $file->move( \'../uploads\');
    if($info){
        // 成功上传后 获取上传信息
        // 输出 jpg
        echo $info->getExtension();
        // 输出 20160820/42a79759f284b767dfcb2a0197904287.jpg
        echo $info->getSaveName();
        // 输出 42a79759f284b767dfcb2a0197904287.jpg
        echo $info->getFilename(); 
    }else{
        // 上传失败获取错误信息
        echo $file->getError();
    }
}

move方法成功的话返回的是一个\\think\\File对象,你可以对上传后的文件进行后续操作。

多文件上传

如果你使用的是多文件上传表单,例如:

<form action="/index/index/upload" enctype="multipart/form-data" method="post">
<input type="file" name="image[]" /> <br> 
<input type="file" name="image[]" /> <br> 
<input type="file" name="image[]" /> <br> 
<input type="submit" value="上传" /> 
</form> 

控制器代码可以改成:

public function upload(){
    // 获取表单上传文件
    $files = request()->file(\'image\');
    foreach($files as $file){
        // 移动到框架应用根目录/uploads/ 目录下
        $info = $file->move( \'../uploads\');
        if($info){
            // 成功上传后 获取上传信息
            // 输出 jpg
            echo $info->getExtension(); 
            // 输出 42a79759f284b767dfcb2a0197904287.jpg
            echo $info->getFilename(); 
        }else{
            // 上传失败获取错误信息
            echo $file->getError();
        }    
    }
}

上传验证

支持对上传文件的验证,包括文件大小、文件类型和后缀:

public function upload(){
    // 获取表单上传文件 例如上传了001.jpg
    $file = request()->file(\'image\');
    // 移动到框架应用根目录/uploads/ 目录下
    $info = $file->validate([\'size\'=>15678,\'ext\'=>\'jpg,png,gif\'])->move( \'../uploads\');
    if($info){
        // 成功上传后 获取上传信息
        // 输出 jpg
        echo $info->getExtension();
        // 输出 20160820/42a79759f284b767dfcb2a0197904287.jpg
        echo $info->getSaveName();
        // 输出 42a79759f284b767dfcb2a0197904287.jpg
        echo $info->getFilename(); 
    }else{
        // 上传失败获取错误信息
        echo $file->getError();
    }
}

getSaveName方法返回的是图片的服务器文件地址,并不能直接用于图片的URL地址,尤其在windows平台上必须做转换才能正常显示图片。

如果上传文件验证不通过,则move方法返回false。

验证参数 说明
size 上传文件的最大字节
ext 文件后缀,多个用逗号分割或者数组
type 文件MIME类型,多个用逗号分割或者数组

还有一个额外的自动验证规则是,如果上传的文件后缀是图像文件后缀,则会检查该文件是否是一个合法的图像文件。

上传错误提示信息支持多语言,你可以修改语言包来修改错误提示。

上传规则

默认情况下,会在上传目录下面生成以当前日期为子目录,以微秒时间的md5编码为文件名的文件,例如上面生成的文件名可能是:

/home/www/uploads/20160510/42a79759f284b767dfcb2a0197904287.jpg

我们可以指定上传文件的命名规则,使用rule方法即可,例如:

// 获取表单上传文件 例如上传了001.jpg
$file = request()->file(\'image\');
// 移动到服务器的上传目录 并且使用md5规则
$file->rule(\'md5\')->move(\'../uploads/\');

最终生成的文件名类似于:

application/uploads/72/ef580909368d824e899f77c7c98388.jpg

系统默认提供了几种上传命名规则,包括:

规则 描述
date 根据日期和微秒数生成
md5 对文件使用md5_file散列生成
sha1 对文件使用sha1_file散列生成

其中md5和sha1规则会自动以散列值的前两个字符作为子目录,后面的散列值作为文件名。

如果需要使用自定义命名规则,可以在rule方法中传入函数或者方法,例如:

// 获取表单上传文件 例如上传了001.jpg
$file = request()->file(\'image\');
// 移动到服务器的上传目录 并且使用uniqid规则
$file->rule(\'uniqid\')->move(\'../uploads/\');

生成的文件名类似于:

application/uploads/573d3b6d7abe2.jpg

如果你希望保留原文件名称,可以使用:

// 获取表单上传文件 例如上传了001.jpg
$file = request()->file(\'image\');
// 移动到服务器的上传目录 并且使用原文件名
$file->move(\'../uploads/\',\'\');

默认情况下,会覆盖服务器上传目录下的同名文件,如果不希望覆盖,可以使用:

// 获取表单上传文件 例如上传了001.jpg
$file = request()->file(\'image\');
// 移动到服务器的上传目录 并且设置不覆盖
$file->move(\'../uploads/\',true,false);

获取文件hash散列值

可以获取上传文件的哈希散列值,例如:

// 获取表单上传文件
$file = request()->file(\'image\');
// 移动到服务器的上传目录 并且使用原文件名
$upload = $file->move(\'/home/www/upload/\');
// 获取上传文件的hash散列值
echo $upload->md5();
echo $upload->sha1();

可以统一使用hash方法获取文件散列值

// 获取表单上传文件
$file = request()->file(\'image\');
// 移动到服务器的上传目录 并且使用原文件名
$upload = $file->move(\'/home/www/upload/\');
// 获取上传文件的hash散列值
echo $upload->hash(\'sha1\');
echo $upload->hash(\'md5\');

返回对象

上传成功后返回的仍然是一个File对象,除了File对象自身的方法外,并且可以使用SplFileObject的属性和方法,便于进行后续的文件处理。

webuploader 无刷新上传前端组件上传

官网:http://fex.baidu.com/webuploader/

简介

image-20200529231156559

结合tp5.1的上传demo


文件上传并回显到页面

视图文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传</title>
    <!--引入CSS-->
    <link rel="stylesheet" type="text/css" href="/static/webuploader/css/webuploader.css">
    <!--引入jquery-->
    <script type="text/javascript" src="/static/admin/js/jquery.min.js"></script>
    <!--引入JS-->
    <script type="text/javascript" src="/static/webuploader/jekyll/js/webuploader.js"></script>
</head>
<body>
<img src="#" id="avatar" style="width:200px ;display:none" >
<div id="picker">选择文件</div>
<script>
    var token = \'{:token()}\';
    var uploader = WebUploader.create({
        // 选完文件后,是否自动上传。
        auto: true,
        // swf文件路径
        swf: \'/static/webuploader/jekyll/js/Uploader.swf\',
        // 文件接收服务端。
        server: \'{:url("uploadSubmit")}\',
        // 选择文件的按钮。可选。
        // 内部根据当前运行是创建,可能是input元素,也可能是flash.
        pick: \'#picker\',

        //设置文件上传域的name
        fileVal: \'pic\',

        //传递请求的额外参数
        formData: {
            \'__token__\': token,
        },
        // 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
        resize: false
    });

    //回调事件
    uploader.on( \'uploadSuccess\', function( $file,response ){
        console.log(arguments);
        if(response.static == 0){
            $(\'#avatar\').attr(\'src\', response.msg).show();
        }
    });
</script>
</body>
</html>

控制器

<?php

namespace app\\admin\\controller;

use think\\Controller;
use think\\Request;

class Upload extends Controller
{
    //上传界面
    public function index(){
        return view(\'admin@/upload/index\');
    }

	//上传处理
    public function upload(Request $request){
        //dump($request->file());
        $file = $request->file(\'pic\');
        // 移动到框架应用根目录/uploads/ 目录下
        $info = $file->move( \'./uploads\');
        if($info){
            $savename = \'/uploads/\'.str_replace(\'\\\\\',\'/\', $info->getSaveName());
            //$savename = \'1111\';
            return json([\'static\' => 0, \'msg\' => $savename]);
        }

        return json([\'static\' => 1, \'msg\' => $file->getError()]);
    }
}

路由

<?php
use \\think\\facade\\Route;
Route::group(\'admin\', function (){
    //文件上传界面
    Route::get(\'upload\', \'@admin/upload/index\')->name(\'upload\');
    //服务器端文件接收
    Route::post(\'uploadSubmit\', \'@admin/upload/upload\')->name(\'uploadSubmit\');
});

运行效果

image-20200529231603688

文件删除操作

视图文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传</title>
    <!--引入CSS-->
    <link rel="stylesheet" type="text/css" href="/static/webuploader/css/webuploader.css">
    <!--引入jquery-->
    <script type="text/javascript" src="/static/admin/js/jquery.min.js"></script>

    <!--引入JS-->
    <script type="text/javascript" src="/static/webuploader/jekyll/js/webuploader.js"></script>

    <style>
        .box {
            position: relative;
            width: 200px;
        }

        .box p {
            position: absolute;
            right: 10px;
            top: 5px;
            z-index: 100;
            color: white;
            background: red;
            /*将鼠标改成手型*/
            cursor: pointer;
        }

        .box p:hover {
            text-decoration: underline;
        }
    </style>
</head>
<body>

<div class="box">
    <img src="#" id="avatar" style="width:200px ;display:none" >
    <p id="del">删除</p>
</div>
<div id="picker">选择文件</div>

<script>
    var token = \'{:token()}\';
    var uploader = WebUploader.create({
        // 选完文件后,是否自动上传。
        auto: true,

        // swf文件路径
        swf: \'/static/webuploader/jekyll/js/Uploader.swf\',

        // 文件接收服务端。
        server: \'{:url("uploadSubmit")}\',

        // 选择文件的按钮。可选。
        // 内部根据当前运行是创建,可能是input元素,也可能是flash.
        pick: \'#picker\',

        //设置文件上传域的name
        fileVal: \'pic\',

        //传递请求的额外参数
        formData: {
            \'__token__\': token,
        },
        // 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
        resize: false
    });

    //回调事件
    uploader.on( \'uploadSuccess\', function( $file,response ) {
        //console.log(arguments);
        if(response.static == 0){
            $(\'#avatar\').attr(\'src\', response.msg).show();
        }
    });

    //点击删除事件
    $(\'#del\').click(function () {
        let img = $(this).prev().attr(\'src\');
        //console.log(img);
        /*发送ajax*/
        $.ajax({
            url: \'{:url("uploadDel")}\',
            type: \'delete\',
            data: {img},
            success: ret => {
                console.log(ret);
                if(ret.status == 0){
                    alert(ret.msg);
                    $(\'#avatar\').hide();
                }
            }
        });
    });
</script>
</body>
</html>

控制器

<?php

namespace app\\admin\\controller;

use think\\Controller;
use think\\Request;

class Upload extends Controller
{
    //上传界面
    public function index(){
        return view(\'admin@/upload/index\');
    }

    //上传处理
    public function upload(Request $request){
        //dump($request->file());
        $file = $request->file(\'pic\');
        // 移动到框架应用根目录/uploads/ 目录下
        $info = $file->move( \'./uploads\');
        if($info){
            $savename = \'/uploads/\'.str_replace(\'\\\\\',\'/\', $info->getSaveName());
            //$savename = \'1111\';
            return json([\'static\' => 0, \'msg\' => $savename]);
        }
        return json([\'static\' => 1, \'msg\' => $file->getError()]);
    }

	//文件删除
    public function del(Request $request){
        //var_dump($request->server());
        // 注意路径问题
        //向上3级
        $img = dirname(__DIR__, 3) .\'/public\'.$request->delete(\'img\');
        //dump($img);
        $data = [\'status\'=>1,\'msg\'=>\'删除失改\'];
        if (unlink($img)){
            $data = [\'status\'=>0,\'msg\'=>\'删除成功\'];
        }
        return json($data);
    }
}

路由

<?php
use \\think\\facade\\Route;

    //文件上传界面
    Route::get(\'upload\', \'@admin/upload/index\')->name(\'upload\');

    //服务器端文件接收
    Route::post(\'uploadSubmit\', \'@admin/upload/upload\')->name(\'uploadSubmit\');

    //服务端删除文件
    Route::delete(\'uploadDel\', \'@admin/upload/del\')->name(\'uploadDel\');

});

运行结果

image-20200530152539572

以上是关于16.ThinkPHP 文件上传的主要内容,如果未能解决你的问题,请参考以下文章

java Ftp上传创建多层文件的代码片段

Alamofire 文件上传出现错误“JSON 文本未以数组或对象开头,并且允许未设置片段的选项”

将存储在内存中的文件上传到s3

JS创建文件并上传服务器

ajaxFileUpload上传带参数文件及JS验证文件大小

android的自带的httpClient 怎么上传文件