在 laravel 项目中除了在上传的时候可使用 move 和 store 方法【都是 request 实例封装的】以外,还可使用高级的上传文件保存方法 (由 storage 门面提供的)javascript
Storage 门面在使用的时候须要的注意事项:php
默认状况下,浏览器是没法访问到 public 磁盘目录的,可是其又想让浏览器访问,因此须要作一个 “软连接的 “的操做”html
php artisan storage:link
至关于快捷方式java
当软连接建立好以后,Public 磁盘中的内容会被同步到 /public/storage/ 下laravel
Storage 门面的通用文件保存方法:ajax
Storage::disk(磁盘名)->put(文件名,文件内容);
在 HTML 代码中添加隐藏域thinkphp
<input type="hidden" name="avatar" value="">
经过回调将返回的 path 写入隐藏域后端
七牛:一家提供各类网络服务的运营商,其性质相似于阿里云数组
作到代码与资源分离浏览器
缘由:
- 在后期维护网站的也比较方便;
- 资源分离以后能够减轻代码服务器的压力;
- 如何将资源分离和 CDN (content delivery network 内容分发网络) 配合起来用,对于 bat 之类的大公司来讲 1 年可以生下来的成本至少 7 位数以上;
注册七牛帐号后建立后期须要的对象存储实例 (不用充钱,每个月免费 10G 空间, 20G 的流量)
选择对象存储
新建空间:本身在哪一个区域选择哪一个存储区域
下载七牛的代码依赖库
composer require zgldh/qiniu-laravel-storage
配置 filesystems.php:
'qiiniu' => [ 'driver' => 'qiniu', 'domains'=> [ 'default' => 'xxxx.com1.z0.glb.clouddn.com', // 你的七牛域名 'https' => '', 'custom' => '' ], 'access_key' => '', // AK 'secret_key' => '', // SK 'bucket' => '', // 磁盘名字 'notify_url' => '', // 持久化处理 'access' => 'public', // 空间访问控制 ],
添加 providers 数组:
zgldh\QiniuStorage\QiniuFilesystemServiceProvider::class,
本项目中,咱们不止上传头像须要用到『图片上传功能』,在后面发布帖子功能中,咱们也将会容许用户上传图片,因此此处咱们须要预先设计一下图片上传相关的逻辑,咱们能够将『图片上传』核心操做作成一个工具类(注意顶部 use Illuminate\Support\Str;
):
app/Handlers/ImageUploadHandler.php
<?php namespace App\Handlers; use Illuminate\Support\Str; class ImageUploadHandler { // 只容许如下后缀名的图片文件上传 protected $allowed_ext = ["png", "jpg", "gif", 'jpeg']; public function save($file, $folder, $file_prefix) { // 构建存储的文件夹规则,值如:uploads/images/avatars/201709/21/ // 文件夹切割能让查找效率更高。 $folder_name = "uploads/images/$folder/" . date("Ym/d", time()); // 文件具体存储的物理路径,`public_path()` 获取的是 `public` 文件夹的物理路径。 // 值如:/home/vagrant/Code/larabbs/public/uploads/images/avatars/201709/21/ $upload_path = public_path() . '/' . $folder_name; // 获取文件的后缀名,因图片从剪贴板里黏贴时后缀名为空,因此此处确保后缀一直存在 $extension = strtolower($file->getClientOriginalExtension()) ?: 'png'; // 拼接文件名,加前缀是为了增长辨析度,前缀能够是相关数据模型的 ID // 值如:1_1493521050_7BVc9v9ujP.png $filename = $file_prefix . '_' . time() . '_' . Str::random(10) . '.' . $extension; // 若是上传的不是图片将终止操做 if ( ! in_array($extension, $this->allowed_ext)) { return false; } // 将图片移动到咱们的目标存储路径中 $file->move($upload_path, $filename); return [ 'path' => config('app.url') . "/$folder_name/$filename" ]; } }
咱们将使用 app/Handlers
文件夹来存放本项目的工具类,『工具类(utility class)』是指一些跟业务逻辑相关性不强的类,Handlers
意为 处理器 ,ImageUploadHandler 意为图片上传处理器,简单易懂。
`public_path()` 获取的是 `public` 文件夹的物理路径。
这里写了一个图片上传处理类,方便网站各处须要上传图片的进行调用
调用呢,成功则返回图片的地址,开发者接收到图片的地址后,哪怕是在页面显示图片,或者在表单里进行添加入库,都提供了方便。
基于上面Laravel开发的图片上传处理类,我将之进行整改,适合TP6的
use think\facade\Filesystem; class ImageUploadHandle { // 只容许如下后缀的图片文件 protected $allowed_ext = ["png", "jpg", "gif", 'jpeg']; /** * @param $file * @param $folder * @param bool $fileas 默认为false,保存到public目录下的指定目录格式下;为true,保存到public下的指定目录下 * @return bool|string */ public function save($file, $folder, $fileas = false) { if ($file) { // 获取文件后缀 $extension = strtolower($file->extension()); // 若是上传的不是图片终止操做 if (!in_array($extension, $this->allowed_ext)) { return false; } try { $savename = $fileas == false ? Filesystem::disk('public')->putFile($folder, $file) : Filesystem::disk( 'public' ) ->putFileAs($folder.'/'.date('Ymd'), $file, $file->getOriginalName()); } catch (\Exception $e) { return $e->getMessage(); } if ($savename) { // TP6中获取图片路径的方法 $path = Filesystem::getDiskConfig('public', 'url').'/'.str_replace('\\', '/', $savename); return $path; } } return false; } }
这样会保存到public/storage/本身定义的目录
下
对应的html页面:
<img src="{$admin_info.avatar|default='/static/admin/img/logo.png'}" alt="选择并上传头像" id="avatar_img" style="width: 140px;height: 140px;left:0;top: 0;border-radius: 50%;"/> <input type="file" id="avatar" name="avatar" accept="image/jpg,image/png,image/gif" style="width: 100%;height:100%;opacity: 0;position: absolute;left:0;top: 0;" onchange="uploadImg(this)" />
{$admin_info}
:这是后端进行查询单个管理员信息的数组{$admin_info.avatar|default='/static/admin/img/logo.png'}
:表明若是这个管理员存在头像,就显示本身的头像,没有则显示默认的一个图片的地址input
中的onchange
事件调用uploadImg(this)
方法this
表明当前html
组件input
ajax
方法上传代码:
function uploadImg(obj) { if (obj.value === "") { return false; } let formData = new FormData(); formData.append("avatar", $(obj)[0].files[0]); $.ajax({ type: "POST", url: "/admin/Admin/uploadAvatar", data: formData, cache: false, processData: false, contentType: false, success: function (data) { // 接收返回的图片地址 if (data.code === 1) { toastr.success("上传头像", data.msg); // 设置图片路径为最新的路径 $("#avatar_img").attr("src", data.data.path); setTimeout(function () { location.href = "/admin/Admin/profile"; }, 1000); } else { toastr.error(data.msg); } } }); return false; }
FormData
是js
的一个东西,经过这个将上传的文件获取到并append
到formData
实例中而后经过
ajax
进行图片上传
后端处理代码:
经过依赖注入将
Request
andImageUploadHandle
进行注入将文件处理类获取的返回的图片地址保存到表中
/** * 上传头像 * @param Request $request * @param ImageUploadHandle $imageUploadHandle * @return \think\response\Json */ public function uploadAvatar(Request $request, ImageUploadHandle $imageUploadHandle) { if (!$request->isPost() || !$request->isAjax()) { return writeJson(config('status.error'), "请求类型不合法"); } $avatar = $request->file('avatar'); $path = $imageUploadHandle->save($avatar, 'avatar'); // 将路径存储进入表中 // 获取当前用户id $admin_id = session('session_admin.id'); try { $result = $this->adminService->saveAvatar($admin_id, $path); } catch (\Exception $e) { return writeJson(config('status.error'), $e->getMessage()); } $data = ['path' => $path]; if ($result) { return writeJson(config('status.success'), "头像上传成功", $data); } return writeJson(config('status.error'), "上传失败"); }
上传结束后,使用js
来实现预览效果:
// 头像预览 $("#avatar").change(function () { // 获取上传文件对象 var file = $(this)[0].files[0]; // 读取文件URL var reader = new FileReader(); reader.readAsDataURL(file); // 阅读文件完成后触发的事件 reader.onload = function () { // 读取的URL结果:this.result $("#avatar_img").attr("src", this.result); } });