3分钟短文:用Laravel的方式管理服务器的文件们
引言
如果我们的应用程序接收用户提交的许多静态文件,文档,图片等等,需要将其上传到服务器并进行有效地管理。
然而,文件类型繁多,文件用途不同;还有可能我们使用第三方的对象存储服务,需要像访问本地文件一样地读取远端的文件。
如果有一套统一的API,或者操作风格,那样会节省很多不必要的差异化代码。laravel提供的Storage文档存储管理正式因此产生的,本期我们就来说一说。
代码时间
首先在配置文件内声明各个磁盘配置,可以设置驱动,配置目录等差异化信息。在 config/filesystem.php 文件内添加如下配置代码:
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'visibility' => 'public',
],
's3' => [
'driver' => 's3',
'key' => 'your-key',
'secret' => 'your-secret',
'region' => 'your-region',
'bucket' => 'your-bucket',
],
],
其中 driver 为 local 时,表示本地的文件系统驱动。
如果要把 storage 目录下的公用目录 public 公开到网络可访问位置,我们为其创建一个软连接:
php artisan storage:link
这样就把目录 public 指向了 storage/app/public 目录。那么位于该目录下的所有文件,可通过web服务器的根目录直接访问。
文件操作
laravel提供的Storage文件操作类,封装了非常方便的文件读写和高级的功能操作。比如读取一个文件的内容:
Storage::disk('s3')->get('file.jpg');
上述代码,读取s3服务上的一个图片文件。
覆盖性写入一个文件,或者创建一个新的不存在的文件,使用 put 方式:
Storage::disk('local')->put('file.jpg', $contentsOrStream)
或者把上传的文件,直接放入到某个指定的目录:
Storage::putFile('myDir', $file)
其中 $file 是一个 IlluminateHttpFile or IlluminateHttpUploadedFile 对象的实例。我们通过表单上传的file字段文件,可以使用
request()->file('file_field')
方便地获取。还有常用的判断文件是否存在:
Storage::exists('file.jpg')
避免了我们写 file_exists 这样还有传入绝对路径,或者相对路径的麻烦,使用对象方法操作,使得代码风格更为统一。
还有常用的一些方法,我们不一一解释了,罗列在下方:
- 文件复制 copy('file.jpg', 'newfile.jpg')
- 文件重命名 move('file.jpg', 'newfile.jpg')
- 文件头部追加内容 prepend('my.log', 'log text')
- 文件尾部追加内容 append('my.log', 'log text')
- 删除文件 delete('file.jpg')
等等等等,读者可以自定查看文档或在源码中研读。
如果我们引入了一个第三方的文件存储服务,且有其一套API操作方式,而laravel系统并未提供该服务的驱动,能否自定义一套呢?完全可以。
框架的文件系统驱动使用了 Flysystem 库用于统一化管理。我们只需要扩展Storage,并将第三方的驱动API实现Storage接口方法即可在程序内无差别地使用了。
在 AppServiceProvider 的 boot 方法内实现该扩展。比如我们引入 dropbox 存储服务:
Storage::extend('dropbox', function ($app, $config) {
$client = new DropboxClient(
$config['accessToken'], $config['clientIdentifier']
);
return new Filesystem(new DropboxAdapter($client));
});
我们使用Dropbox公司提供的 PHP SDK,或者使用composer安装相关包,在扩展方法中注册该驱动引擎即可。
写在最后
本文初步介绍了laravel中是如何使用Storage对象无差别地执行文件操作,用户只需关注文件操作逻辑,而不用在意底层的驱动方式,这样非常便于统一化。最后简介了引入自定义文件驱动的方法。
Happy coding :-)
- 关关的刷题日记05 —— Leetcode 219. Contains Duplicate II
- 关关的刷题日记05 —— Leetcode 217. Contains Duplicate 方法1和方法2
- HDU 2602 Bone Collector(01背包裸题)
- Appium+python自动化13-native和webview切换
- HDU 2639 Bone Collector II(01背包变形【第K大最优解】)
- 专知内容生产基石-数据爬取采集利器WebCollector 介绍
- python实现字符串模糊匹配
- 动态规划之01背包详解【解题报告】
- hihoCoder #1078 : 线段树的区间修改(线段树区间更新板子题)
- HDU 2546 饭卡(01背包裸题)
- 漫谈文件系统
- AI知识搜索利器:基于ElasticSearch构建专知实时高性能搜索系统
- 【深度干货】专知主题链路知识推荐#5-机器学习中似懂非懂的马尔科夫链蒙特卡洛采样(MCMC)入门教程01
- hihoCoder #1043 : 完全背包(板子题)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 隧道构建:端口转发的原理和实现
- SAP Spartacus注入自定义的CurrentProductService
- Redis系列(十一)redis命令全集
- Jinkens+gitlab针对k8s集群实现CI/CD
- Vue 踩过的坑
- Java TCP/UDP/HttpClient简例
- 让你设计实现一个签到功能,到底用MySQL还是Redis?
- 如何防止MySQL重复插入数据,这篇文章会告诉你
- Spring AOP注解开发
- 快速学习-Jenkins CLI凭据
- 快速学习-Jenkins CLI任务
- 珍惜数据,远离钓鱼
- Android Pie限制非 SDK 接口的调用
- 多线程基础(十一):interrupt深度分析
- [记录点滴]授人以渔,从Tensorflow找不到dll扩展到如何排查问题