图片/文件上传

未匹配的标注

图片/文件上传

数据表单通过以下的调用来生成图片/文件上传表单,支持本地和云存储的文件上传。上传组件是基于webuploader实现的,具体的使用配置可参考webuploader官方文档

文件或图片上传表单字段请不要在模型中设置访问器修改器拼接域名,如有相关需求可参考文件/图片域名拼接

$form->file('file_column');
$form->image('image_column');

本地上传

先添加存储配置,config/filesystems.php 添加一项disk:


'disks' => [
    ... ,

    'admin' => [
        'driver' => 'local',
        'root' => public_path('uploads'),
        'visibility' => 'public',
        'url' => env('APP_URL').'/uploads',
    ],
],

设置上传的路径为public/uploads(public_path(‘uploads’))。

然后选择上传的disk,打开config/admin.php找到:


'upload'  => [

    'disk' => 'admin',

    'directory'  => [
        'image'  => 'images',
        'file'   => 'files',
    ]
],

disk设置为上面添加的admindirectory.imagedirectory.file分别为用$form->image($column)$form->file($column)上传的图片和文件的上传目录。

当然你也可以在代码中指定disk

$form->file('file')->disk('your disk name');

云盘上传

如果需要上传到云存储,需要安装对应laravel storage的适配器,拿七牛云存储举例

首先安装 zgldh/qiniu-laravel-storage

同样配置好disk,在config/filesystems.php 添加一项:

'disks' => [
    ... ,
    'qiniu' => [
        'driver'  => 'qiniu',
        'domains' => [
            'default'   => 'xxxxx.com1.z0.glb.clouddn.com', //你的七牛域名
            'https'     => 'dn-yourdomain.qbox.me',         //你的HTTPS域名
            'custom'    => 'static.abc.com',                //你的自定义域名
         ],
        'access_key'=> '',  //AccessKey
        'secret_key'=> '',  //SecretKey
        'bucket'    => '',  //Bucket名字
        'notify_url'=> '',  //持久化处理回调地址
        'url'       => 'http://of8kfibjo.bkt.clouddn.com/',  // 填写文件访问根url
    ],
],

然后修改dcat-admin的上传配置,打开config/admin.php找到:


'upload'  => [

    'disk' => 'qiniu',

    'directory'  => [
        'image'  => 'image',
        'file'   => 'file',
    ],
],

disk选择上面配置的qiniu,或:

$form->file('file')->disk('qiniu');

公共方法

缩略图 (thumbnail)

上传图片的同时生成缩略图

$form->image($column[, $label])->thumbnail('small', $width = 300, $height = 300);

// 生成多张缩略图
$form->image($column[, $label])->thumbnail([
    'small1' => [100, 100],
    'small2' => [200, 200],
    'small3' => [300, 300],
]);
use Dcat\Admin\Traits\Resizable;

class Photo extends Model
{
    use Resizable;
}

// To access thumbnail
$photo->thumbnail('small', 'photo_column');

存储驱动 (disk)

修改文件上传源

$form->file('file')->disk('your disk name');

上传路径 (move)

修改上传路径

$form->file('file')->move('public/upload/image1/');

文件名称 (name)

修改上传文件名称

$form->file('file')->name('test.text');

$form->image('picture')->name(function ($file) {
    return 'test.'.$file->guessExtension();
});

随机名称 (uniqueName)

使用随机生成文件名 (md5(uniqid()).extension)

$form->image('picture')->uniqueName();

禁止页面删除文件 (替换上传)

通过removable方法可以禁止用户从页面点击删除服务器上的文件,可以实现图片覆盖上传效果。

$form->file($column[, $label])->removable(false);

自动上传 (autoUpload)

开启这个功能之后选择完文件之后会立即自动上传,页面将不再显示上传按钮,使用方法如下

$form->file('file')->autoUpload();

$form->image('img')->autoUpload();

文件上传表单下载功能 (downloadable)

$form->file('...')->downloadable();

禁止删除 (retainable)

开启这个功能之后文件将不会从服务器删除

$form->file('file')->retainable();

$form->image('img')->retainable();

storagePermission

设置上传文件的权限

$form->image('picture')->storagePermission(777);

限制上传文件类型

限制上传文件的类型

$form->file('file')->accept('jpg,png,gif,jpeg');

// 可以指定 mimeTypes, 多个用逗号分割
$form->file('file')->accept('jpg,png,gif,jpeg', 'image/*');

分块上传 (chunked)

启用分块上传

$form->file('file')->chunked();

分块大小(chunkSize)

设置分块大小,单位为KB,默认5MB

{tip} 调用这个方法会自动启用分块上传

// 设置为 1MB
$form->file('file')->chunkSize(1024);

文件大小(maxSize)

设置单个文件最大大小,单位为Kb,默认大小为10M

{tip} 同时应该保证php.ini配置文件的upload_max_filesize参数值必须大于这个方法设置的值。

// 设置单个文件最大为1Mb
$form->file('file')->maxSize(1024);

并发上传线程数 (threads)

设置并发上传线程数,默认3

$form->file('file')->threads(5);

自定义上传接口 (url)

通过url可以设置自定义上传接口

$form->file('file')->url('users/files');

系统提供了Dcat\Admin\Traits\HasUploadedFile这个trait来帮助开发者更轻松地处理上传文件,用法如下

<?php

namespace App\Admin\Controllers;

use Dcat\Admin\Traits\HasUploadedFile;

class FileController
{
    use HasUploadedFile;

    public function handle()
    {
        $disk = $this->disk('local');

        // 判断是否是删除文件请求
        if ($this->isDeleteRequest()) {
            // 删除文件并响应
            return $this->deleteFileAndResponse($disk);
        }

        // 获取上传的文件
        $file = $this->file();

        // 获取上传的字段名称
        $column = $this->uploader()->upload_column;

        $dir = 'my-images';
        $newName = $column.'-我的文件名称.'.$file->getClientOriginalExtension();

        $result = $disk->putFileAs($dir, $file, $newName);

        $path = "{$dir}/$newName";

        return $result
            ? $this->responseUploaded($path, $disk->url($path))
            : $this->responseErrorMessage('文件上传失败');
    }
}

在你的路由文件app\Admin\routes.php中加上

$router->any('users/files', 'FileController@handle');

deleteUrl

修改删除已上传文件路径,此方法一般不需要修改

$form->file('file')->deleteUrl('file/delete');

自动保存字段值 (autoSave)

设置上传文件后是否自动保存文件路径到数据库,此方法默认启用,一般不需要修改

$form->file('file')->autoSave(false);

配置 (options)

自定义webuploader配置

$form->file('file')->options(['disableGlobalDnd' => true]);

可排序 (sortable)

此方法仅针对多图/文件上传表单有效

$form->multipleImage('images')->sortable();

压缩图片 (compress)

默认不启用

// 启用图片压缩功能

$form->multipleImage('images')->compress();

$form->image('avatar')->compress([
    'width' => 1600,
    'height' => 1600,

    // 图片质量,只有type为`image/jpeg`的时候才有效。
    'quality' => 90,

    // 是否允许放大,如果想要生成小图的时候不失真,此选项应该设置为false.
    'allowMagnify' => false,

    // 是否允许裁剪。
    'crop' => false,

    // 是否保留头部meta信息。
    'preserveHeaders' => true,

    // 如果发现压缩后文件大小比原来还大,则使用原来图片
    // 此属性可能会影响图片自动纠正功能
    'noCompressIfLarger' => false,

    // 单位字节,如果图片大小小于此值,不会采用压缩。
    'compressSize' => 0
]);

监听WebUploader文件上传事件 (on)

通过 on 方法可以监听 WebUploader文件上传相关事件

$form->file('...')
    ->on('startUpload', <<<JS
        function () {
            console.log('文件开始上传...', this);

            // 上传文件前附加自定义参数到文件上传接口
            this.uploader.options.formData['custom_field'] = '...';
        }
JS
    )
    ->on('uploadFinished', <<<JS
        function () {
            console.log('文件上传完毕');
        }
JS
    );

文件/图片域名拼接

文件或图片上传表单字段请不要在模型中设置访问器修改器拼接域名,如果你需要在访问的时候拼接完整域名,可以在模型中定义一个public方法

<?php

use Illuminate\Support\Str;
use Illuminate\Support\Facades\Storage;

class YourModel extends Model
{
    // 定义一个public方法访问图片或文件
    public function getImage()
    {
        if (Str::contains($this->image, '//')) {
            return $this->image;
        }

        return Storage::disk('admin')->url($this->image);
    }
}

保存域名

如果你需要保存文件域名到数据表,可以使用saveFullUrl方法

$form->image('avatar')->saveFullUrl();

$form->file('...')->saveFullUrl();

监听文件上传变动 (change)

通过以下方法可以监听文件上传成功或文件被删除时产生的变动

$file = $form->file('...');

Admin::script(
    <<<JS
$('{$file->getElementClassSelector()} .file-input').on('change', function () {
    console.log('文件发生变动', this.value);
});
JS
);

覆盖上传 (override)

通过 override 方法可以实现文件覆盖上传。

$form->file('file')->override();

$form->image('img')->override();

图片上传内置方法

压缩、裁切、添加水印等

可以使用压缩、裁切、添加水印等各种方法,需要先安装intervention/image.

更多使用方法请参考[Intervention]:

$form->image($column[, $label]);

// 修改图片上传路径和文件名
$form->image($column[, $label])->move($dir, $name);

// 剪裁图片
$form->image($column[, $label])->crop(int $width, int $height, [int $x, int $y]);

// 加水印
$form->image($column[, $label])->insert($watermark, 'center');

限制上传图片的尺寸

设置文件上传尺寸限制

参数: array 单位为像素

  • width 指定宽度
  • height 指定高度
  • min_width 最小宽度
  • min_height 最小高度
  • max_width 最大宽度
  • max_height 最大高度
  • ratio 宽高比 (width/height)
// 上传宽度为100-300像素之间的图片
$form->image('img')->dimensions(['min_width' => 100, 'max_width' => 300]);

把图片/文件路径保存在其他数据表

通过下面的方法可以把图片或文件的路径保存在单独的附件表,而当前的图片/文件字段只保存ID

{tip} 这里的示例用的是单图上传表单,如果是多图的话可以按这个思路自行调整。

图片/文件表结构

CREATE TABLE `images` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `path` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

使用

$form->image('image1')
    ->saving(function ($value) use ($form) {
        if ($form->isEditing() && ! $value) {
            // 编辑页面,删除图片逻辑
            Image::destroy($form->model()->image1);

            return;
        }

        // 新增或编辑页面上传图片
        if ($value) {
            $model = Image::where('path', $value)->first();
        }

        if (empty($model)) {
            $model = new Image();
        }

        $model->path = $value;

        $model->save();

        return $model->getKey();
    })
    ->customFormat(function ($v) {
        if (! $v) {
            return;
        }

        return Image::find((array) $v)->pluck('path')->toArray();
    });

文件上传失败或无法访问?

如果你发现无法上传文件,那么通常有几下几点原因:

  1. Laravel文件上传配置不正确,请检查admin.upload.disk参数。如果你不了解laravel文件上传功能,请阅读文档Laravel - 文件存储
  2. 文件过大,需要调整php.iniupload_max_filesize参数
  3. 文件上传目录没有写权限
  4. php没有安装或没有开启fileinfo扩展

如果你的文件上传成功了,却无法正常访问,那么可能是.env配置文件中的APP_URL参数没有设置正确。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
贡献者:6
讨论数量: 7
发起讨论 只看当前版本


肌无力猛男
dcat admin数据表单上传文件成功,但是报错
1 个点赞 | 24 个回复 | 问答 | 课程版本 2.x
Senkorl
dcat-admin表单 上传avif格式的图片报错
1 个点赞 | 18 个回复 | 问答 | 课程版本 2.x
xylp
dcat 图片上传报错
0 个点赞 | 11 个回复 | 问答 | 课程版本 2.x
jxdr
为什么文件上传只可以传一个文件, 图片可以传多个?
0 个点赞 | 5 个回复 | 代码速记 | 课程版本 2.x
daliu