您可能知道Laravel使用Flysystem PHP包来提供文件系统抽象。 我开始在我的项目中使用此功能,只是为了将一些图像上传到我的Amazon s3存储桶,我还将Cloudfront实例链接到此存储桶。我的问题是当我试图在我的html页面中显示这些图像时,我需要一个网址。
我找不到任何“干净”的方法来做到这一点,因为flysystem是通用库,我将能够做到这样的事情:
Storage::disk('my_awesome_disk')->publicUrl("{$path}/{$image->name}")
对于'public'文件并且很容易确定文件是否为“public”,因为它包含在他们的api中,所以如果我使用s3 bucket作为我的磁盘驱动程序,我应该得到: “https://s3.amazonaws.com/my_awesome_bucket/path/image.png”
或者:
Storage::disk('my_awesome_disk')->signedUrl("{$path}/{$image->name}", $timeout)
对于'私人'文件 - 我应该得到一个临时网址,该网址会在一段时间后过期。
这是我只能通过具体实施才能实现的吗?例如,如果我使用亚马逊S3我可以轻松运行:
$signed_url = $s3Client->getObjectUrl($bucket_name,
$resource_key,
"+{$expires} minutes");
但我不想做丑陋的“切换案例”来确定我使用的驱动程序。 我如何通过FileSystem接口从cdn(如cloudfront)获取URL? 有什么建议吗?
答案 0 :(得分:3)
我认为Flysystem
是磁盘(或其他存储机制)的接口,仅此而已。就像我不会要求我的本地文件系统计算公共URI一样,我也不会要求Flysystem
这样做。
我创建的对象与我通过Flysystem
保存的文件相对应。根据我的需要,我可以将公共URI直接保存在数据库记录中,或者我可以根据运行时的情况创建一个构建公共URI的自定义getter。
使用Flysystem
,我知道写文件时文件的路径。为了跟踪这些文件,我通常会创建一个表示已保存文件的对象:
class SavedFile extends Model
{
protected $fillable = [
'disk',
'path',
'publicURI',
];
}
当我保存文件时,我在数据库中创建了它的记录:
$disk = 'local_example';
$path = '/path/to/file.txt';
$contents = 'lorem ipsum';
$host = 'https://example.com/path/to/storage/root/';
if (Store::disk($disk)->put($path, $contents)) {
SavedFile::create([
'disk' => $disk,
'path' => $path,
'publicURI' => $host . $path,
]);
}
每当我需要公共URI时,我都可以将其从SavedFile
模型中删除。这对于简单的应用程序来说非常方便,但如果我需要切换存储提供程序,它就会崩溃。
另一个巧妙的技巧是定义一个方法,该方法将根据抽象SavedFile
模型的子元素中定义的变量来解析公共URI。这样我就不会对数据库中的URI进行硬编码,只需要几个变量定义就可以为其他存储服务创建新类:
abstract class SavedFile extends Model
{
protected $table = 'saved_files';
protected $disk;
protected $host;
protected $fillable = [
'path',
];
public function getPublicURIAttribute()
{
return $this->host . $this->attributes['path'];
}
}
class LocalSavedFile extends SavedFile
{
$disk = 'local_example';
$host = 'https://example.com/path/to/storage/root';
}
class AwsSavedFile extends SavedFile
{
$disk = 'aws_example';
$host = 'https://s3.amazonaws.com/my_awesome_bucket';
}
现在,如果我有一堆文件存储在我的本地文件系统上,有一天我将它们移动到Amazon S3,我可以简单地复制文件并换掉我的IoC绑定定义中的依赖项,我就完成了。无需在大型数据库表上进行耗时且有潜在危险的查找和替换,因为URI的计算是由模型完成的:
$localFile = LocalSavedFile::create([
'path' => '/path/to/file.txt'
]);
echo $localFile->publicURI; // https://example.com/path/to/storage/root/path/to/file.txt
$awsFile = AwsSavedFile::find($localFile->id);
echo $awsFile->publicURI; // https://s3.amazonaws.com/my_awesome_bucket/path/to/file.txt
修改强>
只需在对象上添加一个标志:
abstract class SavedFile extends Model
{
protected $table = 'saved_files';
protected $disk;
protected $host;
protected $fillable = [
'path',
'public',
];
public function getPublicURIAttribute()
{
if ($this->attributes['public'] === false) {
// you could throw an exception or return a default image if you prefer
return false;
}
return $this->host . $this->attributes['path'];
}
}
class LocalSavedFile extends SavedFile
{
$disk = 'local_example';
$host = 'https://example.com/path/to/storage/root';
}
$localFile = LocalSavedFile::create([
'path' => '/path/to/file.txt',
'public' => false,
]);
var_dump($localFile->publicURI); // bool(false)