接着上2篇笔记:
使用 qshell 将本地文件同步到七牛云
https://blog.csdn.net/beyond__devil/article/details/83030702
将 laravel 项目内静态文件,css、js、images 部署到七牛云 csdn
https://blog.csdn.net/beyond__devil/article/details/83057313
本篇笔记,我们根据最后遗留的问题,扩展 laravel 文件系统驱动,添加 七牛云 存储引擎。
参考文章:
laravel 文件存储文档
https://laravelacademy.org/post/9567.html
基于七牛云 PHP SDK + Laravel 文件存储实现 Laravel 学院静态资源云存储及 CDN 加速
https://laravelacademy.org/post/9486.html
昨晚因为一个小问题,让我调试代码,调试了N久,看了好久的 filesystem 源码,稍微总结下:
文件系统的 Facade,我们使用的是:
Storage
Storage Facade 的定义,我们在门面类列表查看:
https://laravelacademy.org/post/9536.html
filesystem - Illuminate\Filesystem\FilesystemManager
filesystem.disk - Illuminate\Contracts\Filesystem\Filesystem
打开 Illuminate\Filesystem 目录,简单看下:
Cache.php - 缓存有关
Filesystem.php - 文件、目录处理类
FilesystemAdapter.php - 设配器(laravel)
FilesystemManager.php - 存储驱动管理
FilesystemServiceProvider.php - 服务提供者
laravel 文件系统,底层使用的 league/flysystem 包,这里我们有时间也可以简单看下源码,大概知道是个什么意思就行。
注意:
我们只需要知道我们平常使用:
Storage::xxx() 调用文件存储方法
其实调用的就是: Illuminate\Filesystem\FilesystemManager 就可以。然后我们一点点看源码,基本就都能明白了(Laraval 有时候很复杂,半天找不到对应的到底是哪个文件)
Storage::extend() 就是 Illuminate\Filesystem\FilesystemManager->extend(),用于扩展我们自定义的 '文件存储'
Storage::xxx() 方法有:
FilesystemManager.php:
drive() - 同 disk()
disk() - 获取文件系统实例,如果没有,使用默认驱动(config/filesystem.php 有2个默认配置,一个默认配置,一个默认云存储配置)
cloud() - 获取默认云存储(config/filesystem.php 有2个默认配置,一个默认配置,一个默认云存储配置)
createLocalDriver() - 创建一个 local 驱动
createFtpDriver() - 创建一个 ftp 驱动
createSftpDriver() - 创建一个 sftp 驱动
createS3Driver() - 创建一个 Amazon S3 驱动
createRackspaceDriver() - 创建一个 Rackspace 驱动
set() - 获取给定的驱动实例
getDefaultDriver() - 获取默认驱动名
getDefaultCloudDriver() - 获取默认云存储驱动名
forgetDisk() - unset 给定的驱动
extend() - 注册一个自定义驱动
__call($method, $parameters) // Storage::xxx() 其他方法,都是通过魔术方法 __call() 来调用 '默认驱动' 的方法,$this->dist() 返回的是 'FilesystemAdapter.php' 类的实例
{
return $this->disk()->$method(...$parameters);
}
FilesystemAdapter.php:
里面经常会调用 $this->driver() 方法,而 $this->driver() 都是 'league/flysystem/Filesystem.php' 的实例。它里面对应的所有方法,都是对参数进行处理,最终调用的就是我们具体的 '驱动适配器'(local、public、s3、qiniu) 的方法了,所以我们就暂且忽略 'league/flysystem/Filesystem.php' 这个中间处理层了
assertExists() - PHPUnit 测试使用
assertMissing() - PHPUnit 测试使用
exists($path) - 文件是否存在,调用 adaptar 的 has()
path($path) - 获取给定文件的全路径,调用 adaptar 的 getPathPrefix() . $path
get($path) - 获取文件内容,调用 adaptar 的 read()
response($path, $name = null, array $headers = [], $disposition = 'inline') - 创建给定文件的流响应(stream),中间会调用 '自身的' readStream() 方法
download() - 借助 response() 方法,下载
put($path, $contents, $options = []) - 将制定内容写入到文件中,根据不同情况,调用不同的写入方法。有 '自身的 putFile()','adaptar 的 putStream()','adaptar 的 put()'
putFile($path, $file, $options = []) - 将上传文件,写入到存储,调用 '自身的 putFileAs()'
putFileAs($path, $file, $name, $options = []) - 将上传文件,写入到存储,调用上面写的 '自身的 put()'
getVisibility($path) - 获取文件的可见性,调用 'adaptar 的 getVisibility()'
setVisibility($path) - 设置文件的可见性,调用 'adaptar 的 setVisibility()'
prepend($path, $data, $separator = PHP_EOL) - 向前追加指定内容到文件,调用 '自身的 put()'(文件存在,追加,不存在,新建)
append($path, $data, $separator = PHP_EOL) - 向后追加指定内容到文件,调用 '自身的 put()'(文件存在,追加,不存在,新建)
delete($paths) - 删除指定文件(支持多个,数组,或者多个参数,会使用 file_get_args() 来获取),调用 'adaptar 的 delete()'
copy($from, $to) - 复制文件,调用 'adaptar 的 coty()'
move($from, $to) - 移动文件,调用 'adaptar 的 rename()'
size($path) - 获取文件大小,调用 'adaptar 的 getSize()'
mimeType($path) - 获取文件的 MIME 类型,调用 'adaptar 的 getMimeType()'
lastModified($path) - 获取文件的最后修改时间,调用 'adaptar 的 getTimestamp()'
url($path) - 获取文件的访问 URL,『我们自己需要定义一个 getUrl() 方法,这个方法很关键,我们可以在我们的 qiniuAdaptar 里添加 getUrl() 方法,然后静态文件的访问,我们可以直接使用 Storage::geturl() 来获取』
readStream($path)
writeStream($path, $resource, array $options = [])
temporaryUrl($path, $expiration, array $options = [])
getAwsTemporaryUrl($adapter, $path, $expiration, $options)
getRackspaceTemporaryUrl
files($directory = null, $recursive = false) - 获取目录下的所有文件,类型只是 'file',调用 'adaptar 的 listContents()'
allFiles($directory = null) - 获取目录下的所有文件(递归),调用上面的 $this->files()
Directories($directory = null, $recursive = false) - 获取目录下的所有目录,类型只是 'dir',调用 'adaptar 的 listContents()'
allDirectories($directory = null) - 获取目录下的所有目录(递归),调用上面的 $this->Directories()
makeDirectory($path) - 创建目录,调用 'adaptar 的 createDir()'
deleteDirectory($path) - 删除目录,调用 'adaptar 的 deleteDir()'
flushCache() - 只有当该 adaptar 继承了 'CacheAdapter',才可用
getDriver() - 获取当前的 Filesystem 实例
__call($method, array $parameters) // Storage::xxx() 其他方法,还可以通过魔术方法 __call() 来调用 'Filesystem' 的方法(方法很少了...)
{
return call_user_func_array([$this->driver, $method], $parameters);
}
Filesystem.php 额外的方法(好多类似别名访问):
PluggableTrait 方法,插件相关(未用到,我们不考虑)
ConfigAwareTrait 方法,配置相关
getAdapter() - 获取 adaptar,local、public、s3、qiniu 等
write() - 调用 'adaptar 的 write()'
putStream()
readAndDelete() - 读取文件内容,并删除文件,文件不存在,返回 false,文件存储,返回文件内容
update() - 调用 'adaptar 的 update()'
updateStream() - 调用 'adaptar 的 updateStream() '
read()
readStream()
rename()
deleteDir()
createDir()
listContents()
getMimetype()
getTimestamp()
getSize()
getMetadata()
assertPresent() - 文件不存在报错(disable_asserts 配置)
assertAbsent() - 文件存在报错(disable_asserts 配置)
自己语言表达能力有点差,可能自己也不是很明白,要讲清楚很难,源码总结就说到这里。
开始扩展七牛云存储,主要参考上面的 '基于七牛云 PHP SDK + Laravel 文件存储实现 Laravel 学院静态资源云存储及 CDN 加速' 这篇文章,七牛云的源码封装,我会走一遍,稍微添加或修改,最后整理处理。
安装 '七牛云 PHP SDK':
composer require qiniu/php-sdk
.env 添加配置:
FILESYSTEM_CLOUD=qiniu
QINIU_ACCESS_KEY=你的七牛云AccessKey
QINIU_SECRET_KEY=你的七牛云SecretKey
QINIU_DEFAULT_REGION=你的默认区域,比如z0
QINIU_BUCKET=你的bucket(通过在对象存储中新增存储空间获取)
QINIU_PREFIX=七牛云空间内,文件存储的相对路径(路径前缀)
QINIU_URL=你的静态 CDN URL
config/filesystem.php,添加 'qiniu' 驱动:
'disks' => [
...
'qiniu' => [
'driver' => 'qiniu',
'key' => env('QINIU_ACCESS_KEY', 'xxx'),
'secret' => env('QINIU_SECRET_KEY', 'xxx'),
'region' => env('QINIU_DEFAULT_REGION', ''),
'bucket' => env('QINIU_BUCKET', 'xxx'),
'prefix' => env('QINIU_PREFIX', 'storage'),
'url' => env('QINIU_URL', 'xxx'),
],
],
编写 '七牛云存储适配器':
App/Services/FileSystem/QiniuAdapter.php
注:
laravel 从 5.1 之后好像取消了 App/Services 目录,我们自己来创建这个目录,再多添加一层 FileSystem,可能以后会添加其他的文件存储。(也可以指定其他目录)
注册 '七牛云存储适配器':
vim app/Providers/AppServiceProvider.php
boot() 方法添加:
use Storage;
use League\Flysystem\Filesystem;
use App\Services\FileSystem\QiniuAdapter;
public function boot()
{
Storage::extend('qiniu', function ($app, $config) {
return new Filesystem(new QiniuAdapter($config));
})
}
App/Services/FileSystem/QiniuAdapter.php 适配器代码:
QiniuAdapter 必须实现 League\Flysystem\AdapterInterface 接口
我们可查看官方的 Local 文件存储,仿照写:
league/flysystem/src/Adapter/Local.php
下面是 'laravel 学院' 的代码小修改:
/*********************************************
<?php
namespace App\Services\FileSystem;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use League\Flysystem\Adapter\AbstractAdapter;
use League\Flysystem\Config;
use Qiniu\Auth;
use Qiniu\Storage\BucketManager;
use Qiniu\Storage\UploadManager;
use Symfony\Component\HttpFoundation\File\Exception\UploadException;
class QiniuAdapter extends AbstractAdapter
{
protected $uploadManager;
protected $bucketManager;
private $accessKey;
private $accessSecret;
private $bucketName;
private $token;
private $url;
public function __construct($config)
{
$this->uploadManager = new UploadManager();
$this->accessKey = $config['key'];
$this->accessSecret = $config['secret'];
$this->bucketName = $config['bucket'];
$auth = new Auth($this->accessKey, $this->accessSecret);
$this->bucketManager = new BucketManager($auth);
$this->token = $auth->uploadToken($this->bucketName);
$this->setPathPrefix($config['prefix']);
$this->url = $config['url'];
}
/**
* Write a new file.
*
* @param string $path
* @param string $contents
* @param Config $config Config object
*
* @return array|false false on failure file meta data on success
*/
public function write($path, $contents, Config $config)
{
return $this->upload($path, $contents);
}
/**
* Write a new file using a stream.
*
* @param string $path
* @param resource $resource
* @param Config $config Config object
*
* @return array|false false on failure file meta data on success
*/
public function writeStream($path, $resource, Config $config)
{
return $this->upload($path, $resource, true);
}
/**
* Update a file.
*
* @param string $path
* @param string $contents
* @param Config $config Config object
*
* @return array|false false on failure file meta data on success
*/
public function update($path, $contents, Config $config)
{
return $this->upload($path, $contents);
}
/**
* Update a file using a stream.
*
* @param string $path
* @param resource $resource
* @param Config $config Config object
*
* @return array|false false on failure file meta data on success
*/
public function updateStream($path, $resource, Config $config)
{
return $this->upload($path, $resource, true);
}
/**
* Rename a file.
*
* @param string $path
* @param string $newpath
*
* @return bool
*/
public function rename($path, $newpath)
{
$path = $this->applyPathPrefix($path);
$newpath = $this->applyPathPrefix($newpath);
$error = $this->bucketManager->rename($this->bucketName, $path, $newpath);
return $error == null ? true : false;
}
/**
* Copy a file.
*
* @param string $path
* @param string $newpath
*
* @return bool
*/
public function copy($path, $newpath)
{
$path = $this->applyPathPrefix($path);
$newpath = $this->applyPathPrefix($newpath);
$error = $this->bucketManager->copy($this->bucketName, $path, $this->bucketName, $newpath);
return $error == null ? true : false;
}
/**
* Delete a file.
*
* @param string $path
*
* @return bool
*/
public function delete($path)
{
$this->applyPathPrefix($path);
$error = $this->bucketManager->delete($this->bucketName, $path);
return $error == null ? true : false;
}
/**
* Delete a directory.
*
* @param string $dirname
*
* @return bool
*/
public function deleteDir($dirname)
{
throw new \BadFunctionCallException('暂不支持该操作');
}
/**
* Create a directory.
*
* @param string $dirname directory name
* @param Config $config
*
* @return array|false
*/
public function createDir($dirname, Config $config)
{
throw new \BadFunctionCallException('暂不支持该操作');
}
/**
* Set the visibility for a file.
*
* @param string $path
* @param string $visibility
*
* @return array|false file meta data
*/
public function setVisibility($path, $visibility)
{
throw new \BadFunctionCallException('暂不支持该操作');
}
/**
* Check whether a file exists.
*
* @param string $path
*
* @return array|bool|null
*/
public function has($path)
{
$path = $this->applyPathPrefix($path);
$stat = $this->bucketManager->stat($this->bucketName, $path);
if ($stat[0] == null) {
return false;
} else {
return true;
}
}
/**
* Read a file.
*
* @param string $path
*
* @return array|false
*/
public function read($path)
{
$path = $this->applyPathPrefix($path);
list($fileInfo, $error) = $this->bucketManager->stat($this->bucketName, $path);
if ($fileInfo) {
return $fileInfo;
} else {
throw new FileNotFoundException('对应文件不存在');
}
}
/**
* Read a file as a stream.
*
* @param string $path
*
* @return array|false
*/
public function readStream($path)
{
throw new \BadFunctionCallException('暂不支持该操作');
}
/**
* List contents of a directory.
*
* @param string $directory
* @param bool $recursive
*
* @return array
*/
public function listContents($directory = '', $recursive = false)
{
return $this->bucketManager->listFiles($this->bucketName);
}
/**
* Get all the meta data of a file or directory.
*
* @param string $path
*
* @return array|false
*/
public function getMetadata($path)
{
return $this->read($path);
}
/**
* Get the size of a file.
*
* @param string $path
*
* @return array|false
*/
public function getSize($path)
{
$fileInfo = $this->read($path);
return $fileInfo['fsize'];
}
/**
* Get the mimetype of a file.
*
* @param string $path
*
* @return array|false
*/
public function getMimetype($path)
{
$fileInfo = $this->read($path);
return $fileInfo['fileType'];
}
/**
* Get the last modified time of a file as a timestamp.
*
* @param string $path
*
* @return array|false
*/
public function getTimestamp($path)
{
$fileInfo = $this->read($path);
return $fileInfo['putTime'];
}
/**
* Get the visibility of a file.
*
* @param string $path
*
* @return array|false
*/
public function getVisibility($path)
{
throw new \BadFunctionCallException('暂不支持该操作');
}
protected function upload(string $path, $contents, $stream = false)
{
$path = $this->applyPathPrefix($path);
try {
if ($stream) {
$response = $this->uploadManager->put($this->token, $path, $contents);
} else {
$response = $this->uploadManager->putFile($this->token, $path, $contents);
}
} catch (\Exception $ex) {
throw $ex;
} catch (\Exception $ex) {
throw $ex;
}
list($uploadResult, $error) = $response;
if ($uploadResult) {
return $uploadResult;
} else {
throw new UploadException('上传文件到七牛失败:' . $error->message());
}
}
public function getUrl($path)
{
$path = $this->applyPathPrefix($path);
return $this->url . DIRECTORY_SEPARATOR . $path;
}
}
*********************************************/
这个 QiniuAdapter 有不少问题,因为好多方法其实未实现~~,打算好好看看 七牛云 SDK & 七牛云开发者文档,看看能不能把这个 QiniuAdapter 给写的更好一点。看了会,发现有点不太好搞啊~~
查找资料过程中,在 packagist.org 输入 qiniu,本想找下 qiniu/php-sdk,发现了好多七牛相关的包,被打脸了!!!这篇笔记有点长,接下篇,终结下七牛云存储的问题!!!
laravel 添加 七牛云 存储驱动
猜你喜欢
转载自blog.csdn.net/beyond__devil/article/details/83065677
今日推荐
周排行