Layui+thinkPHP6.0文件上传

本文介绍了使用Layui前端框架进行异步文件上传,结合ThinkPHP6.0后端实现的过程,包括前端Layui的上传逻辑、前端代码解析、后端ThinkPHP6.0的文件处理及验证方法。重点讨论了在实际操作中遇到的坑,如前端文件名的设定、后端验证规则的编写以及文件保存路径的配置,并提供了错误排查的建议,如调整php.ini配置以允许大文件上传。
摘要由CSDN通过智能技术生成

1、写在前面

  1. Layui文件上传逻辑:异步上传(点击按钮就将文件上传到服务器,然后再返回线上图片地址,等提交表单提交时 ,将其它表单信息和图片的线上地址一起提交 )
  2. 先给我自己的代码

2、Layui前端代码说明

<form class="layui-form">
    <div class="layui-form-item">
        <label class="layui-form-label">标签</label>
        <div class="layui-input-block">
            <button type="button" class="layui-btn" id="firstID">
                <i class="layui-icon">&#xe67c;</i>上传按钮
            </button>
            <input type="hidden" name="url" id="secondID">
        </div>
    </div>
</form>

上面这段代码声明了一个layui表单,里面有一个按钮和一个隐藏的input。

<script>
    layui.use(['upload','form'], function(){
        var upload = layui.upload;
        var form = layui.form;
        upload.render({
            elem: '#firstID', 			//选中你要绑定的上传组件
            url: '/datatest/upload',//上传接口
            accept:'file',					//文件类型,不写默认是images,file表示全类型
            done: function(res){		//上传完回调,这里的res必须是json类型
                if (res.status === 200) {
                    layer.msg(res.msg, {icon: 1});
                    $('#secondID').val(res.path);  //回填路径值
                }else{
                    layer.msg('上传失败', {icon: 2});
                }
            },
            error: function(){
                layer.msg('error'+ res.status, {icon: 2});
            }
        });
    });
</script>

注意,官网文档里特别说明了接口返回信息必须是严格的JSON格式,详见官方文档https://www.layui.com/doc/modules/upload.html

3、thinkPHP6.0后端代码

​ tp6的官方代码对于上传这部分的描写着实是坑。先给我自己的代码:

class DataTest{
  public function upload(){
    $file = request()->file('file');  //这里‘file’是你提交时的name
    try{
        validate(['goodFile' => [     //goodFile是你自定义的键名,目的是为了对check里数组中的
            'fileSize' =>50*1024*1024,//goodFile字段值进行验证;允许文件大小
            'fileExt'  => array('mp3','wav'),  //允许的文件后缀
            ]])->check(['goodFile'=>$file]);//也就是对上传的$file进行验证
        $saveName = \think\facade\Filesystem::disk('public')->putFile( 'music', $file);//保存文件名
        $arr = ['status' => 200, 'msg' => '成功', 'path' => app()->getRootPath().'public/storage'.$saveName];
        return json($arr);   				//返回标准json格式
    }catch (\Exception $e) {
        return $this->exceptionHandle($e,'上传失败!' . $e->getMessage(),'json','');
    }
	}
}


首先,对于 file函数

$files = request()->file('file');

File()这个函数本身并没有‘file’参数,这里的‘file只是’你提交时input的name。不过layui时绑定组件提交,并没有显式地给出name(这里就是个大坑),尝试多次后才确定‘file‘可行。

如果你把前端代码改成

 <input type="file" name="yourName" vlaue="请上传文件">

那么你后端代码就要改成这样,亲测有效

$files = request()->file('yourName');

其次,对于check函数验证

validate()->check()

Check()里面只能是一个数组,也就是我上面写的[‘goodFile’=>$file]。而官方文档里确直接把$file给填进去了,这是为什么呢?让我们看一下官方文档的代码

//官方文档代码
public function upload(){
    // 获取表单上传文件
    $files = request()->file(); //注意这里
    try {
        validate(['image'=>'filesize:10240|fileExt:jpg|image:200,200,jpg'])
            ->check($files);  //注意这里
        $savename = [];
        foreach($files as $file) {
            $savename[] = \think\facade\Filesystem::putFile( 'topic', $file);
        }
    } catch (\think\exception\ValidateException $e) {
        echo $e->getMessage();
    }
}

可以看到作者写的file函数里面是不带参数的,这样得到的$files就是是一个数组,而validate里面就是验证$files里字段‘image’的值。而且从后面的foreach来看,这里是多文件上传。作者实在太懒。


最后,对于保存路径值

$saveName = \think\facade\Filesystem::disk('public')->putFile( 'music', $file);//保存文件名
$arr = ['status' => 200, 'msg' => '成功', 'path' => app()->getRootPath().'public/storage/'.$saveName];

这里默认会在public/storage/music/目录下保存文件。

如果你需要保存到别处,这里你需要修改:项目根目录->config.php->filesystem.php

<?php

return [
    // 默认磁盘
    'default' => env('filesystem.driver', 'local'),
    // 磁盘列表
    'disks'   => [
        'local'  => [
            'type' => 'local',
            'root' => app()->getRuntimePath() . 'storage',
        ],
        'public' => [
            // 磁盘类型
            'type'       => 'local',
            // 磁盘路径
            'root'       => app()->getRootPath() . 'public/storage', 
            // 磁盘路径对应的外部URL路径
            'url'        => '/storage',
            // 可见性
            'visibility' => 'public',
        ],
        // 更多的磁盘配置信息
    ],
];

具体是修改public里的root和url,把后面的storage改为你想要的文件名。


注意!

在你修改允许文件大小后还有可能会失败,因为你可能忘了修改php.ini里的默认upload_max_filesize允许上传文件大小
php.ini

1、打开php.ini

2、查找post_max_size:(修改上传大小限制)

表单提交最大数值,此项不是限制上传单个文件的大小,而是针对整个表单的提交数据进行限制的默认为8m,设置为自己需要的值,此参数建议要设置比upload_max_filesize大一些

3、查找file uploads:*(修改上传开关限制)*

是否允许通过http上传文件的开关,确认file_uploads = on

4、查找upload_tmp_dir:*(修改上传临时文件限制)*

文件上传至服务器上存储临时文件的地方,如果没指定就会用系统默认的临时文件夹如果系统报错提示有“xxx临时目录xxx”的话,这个目录就需要你来设置一个有效目录,没报错就不用管

5、查找upload_max_filesize:*(修改上传大小限制)*

允 许上传文件大小的最大值,默认为2m,设置为自己需要的值此参数建议不要超过post_max_size值,因为它受控于post_max_size值 (就算upload_max_filesize设置了1g,

而post_max_size只设置了2m时,大于2m的文件照样传不上去,因为它受控于 post_max_size值)

6、如果要上传大于8m的文件,还需要对下面的参数也进行设置:(修改上传时间限制)

查找max_execution_time = 600 ;每个php页面运行的最大时间值(秒),默认30秒

max_input_time = 600 ;每个php页面接收数据所需的最大时间,默认60秒

memory_limit = 8m ;每个php页面所需要的最大内存,默认8m

要在前端显示导出进度条,可以使用layui的layer和jquery库来实现。在导出数据的过程中,可以通过计算已经导出的行数和总行数来计算出导出进度,并将其传递给前端页面。然后,利用ajax轮询的方式来获取导出进度,并更新进度条的显示。以下是示例代码: 1.前端页面代码: ```html <!-- 导出按钮 --> <button class="layui-btn layui-btn-normal" onclick="exportData()">导出数据</button> <!-- 进度条 --> <div class="layui-progress layui-progress-big" lay-showPercent="true" style="display:none; margin-top:15px;"> <div class="layui-progress-bar layui-bg-green" lay-percent="0%"></div> </div> <!-- 引入jquery和layui的layer库 --> <script src="https://cdn.bootcss.com/jquery/3.5.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/layer/3.1.1/layer.min.js"></script> <script> // 导出数据 function exportData() { // 显示进度条 $('.layui-progress').show(); // 发送ajax请求导出数据 $.ajax({ type: 'post', url: '/index/export', dataType: 'json', success: function(res) { // 隐藏进度条 $('.layui-progress').hide(); // 下载导出的文件 window.location.href = res.fileUrl; }, error: function() { // 隐藏进度条 $('.layui-progress').hide(); // 弹出错误提示 layer.msg('导出数据失败,请稍后重试!', {icon: 2}); } }); // 定时获取导出进度 var timer = setInterval(function() { $.ajax({ type: 'get', url: '/index/getExportProgress', dataType: 'json', success: function(res) { // 更新进度条显示 $('.layui-progress-bar').attr('lay-percent', res.progress + '%'); $('.layui-progress-bar').css('width', res.progress + '%'); // 导出完成,清除定时器 if (res.progress == 100) { clearInterval(timer); } } }); }, 1000); } </script> ``` 2.控制器代码: ```php // 导出数据 public function export() { try { // 省略从数据库中获取数据的代码 // ... // 获取总行数 $totalCount = count($data); // 初始化PHPExcel和PHPExcel_IOFactory require_once 'PHPExcel/PHPExcel.php'; require_once 'PHPExcel/IOFactory.php'; // 创建PHPExcel对象 $objPHPExcel = new PHPExcel(); // 创建第一个工作表 $sheet = $objPHPExcel->getActiveSheet(); // 省略将数据写入PHPExcel对象中的代码 // ... // 开始导出 ob_start(); $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007'); $objWriter->save('php://output'); $excelData = ob_get_clean(); // 生成导出文件名 $fileName = date('YmdHis') . '.xlsx'; $fileUrl = 'public/export/' . $fileName; // 保存导出文件 file_put_contents($fileUrl, $excelData); // 返回导出结果 return json([ 'fileUrl' => $fileUrl, ]); } catch (Exception $e) { // 导出数据失败,返回错误提示 return json([ 'code' => -1, 'msg' => '导出数据失败,请稍后重试!', ]); } } // 获取导出进度 public function getExportProgress() { // 获取当前导出进度 $progress = session('export_progress'); // 计算导出进度百分比 if ($progress['current'] == 0) { $percent = 0; } else { $percent = floor($progress['current'] / $progress['total'] * 100); } // 返回导出进度百分比 return json([ 'progress' => $percent, ]); } ``` 在以上代码中,我们利用ajax发送导出数据的请求,并在前端页面上显示进度条。然后,我们在控制器中逐行导出数据,并计算出导出进度,并将导出进度存储到session中。最后,我们通过ajax轮询的方式来获取导出进度,并更新进度条的显示。当导出完成时,我们返回导出结果并清除轮询定时器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值