在 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); } });