如何在 Laravel 5 中获取上传文件的公共 url
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29794194/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get public url of an uploaded file in Laravel 5
提问by Lihai
As you may know Laravel uses Flysystem PHP package to provide filesystem abstraction. Ive started to use this feature in my project, just for fun uploaded some images to my Amazon s3 bucket, I have also instance of Cloudfront linked to this bucket. My problem is when im trying to display those images in my html page, i need a url.
你可能知道 Laravel 使用 Flysystem PHP 包来提供文件系统抽象。我已经开始在我的项目中使用这个功能,只是为了好玩,上传了一些图片到我的 Amazon s3 存储桶,我也有链接到这个存储桶的 Cloudfront 实例。我的问题是当我试图在我的 html 页面中显示这些图像时,我需要一个 url。
I could not find any "clean" way to do it, as flysystem is generic library i throught that i will be able to do something like this:
我找不到任何“干净”的方法来做到这一点,因为 flysystem 是通用库,我通过它我将能够做这样的事情:
Storage::disk('my_awesome_disk')->publicUrl("{$path}/{$image->name}")
for 'public' files and its easy to determine if file is "public" or not because its included in their api, so if im using s3 bucket as my driver for the disk i should get: "https://s3.amazonaws.com/my_awesome_bucket/path/image.png"
对于“公共”文件,它很容易确定文件是否“公共”,因为它包含在他们的 api 中,所以如果我使用 s3 存储桶作为我的磁盘驱动程序,我应该得到:“ https://s3.amazonaws。 com/my_awesome_bucket/path/image.png"
or alternatively:
或者:
Storage::disk('my_awesome_disk')->signedUrl("{$path}/{$image->name}", $timeout)
for 'private' files - i should get a temporary url that will expire after some time.
对于“私人”文件 - 我应该得到一个临时网址,该网址将在一段时间后过期。
Is this something i can achieve only with specific implementation? for example if im using Amazon S3 i can easily run:
这是我只能通过特定实现才能实现的东西吗?例如,如果我使用 Amazon S3,我可以轻松运行:
$signed_url = $s3Client->getObjectUrl($bucket_name,
$resource_key,
"+{$expires} minutes");
But i dont want to do ugly "switch cases" to determine what driver im using. And how can i get a url from a cdn (like cloudfront) through the FileSystem interface? Any suggestion?
但我不想做丑陋的“切换案例”来确定我使用的驱动程序。以及如何通过 FileSystem 接口从 CDN(如 cloudfront)获取 url?有什么建议吗?
回答by Ben Harold
I think of Flysystem
as an interface to a disk (or other storage mechanism) and nothing more. Just as I would not ask my local filesystem to calculate a public URI, I would not ask Flysystem
to do it either.
我认为Flysystem
是磁盘(或其他存储机制)的接口,仅此而已。正如我不会要求我的本地文件系统计算公共 URI 一样,我也不会要求Flysystem
这样做。
I create objects that correspond to the files that I save via Flysystem
. Depending on my needs, I might save the public URI directly in the database record, or I might create a custom getter that builds the public URI based on runtime circumstances.
我创建与我通过Flysystem
. 根据我的需要,我可能会直接将公共 URI 保存在数据库记录中,或者我可能会创建一个自定义 getter 来根据运行时情况构建公共 URI。
With Flysystem
, I know the path to the file when I write the file. In order to keep track of these files I'll typically create an object that represents a saved file:
使用Flysystem
,我在写入文件时知道文件的路径。为了跟踪这些文件,我通常会创建一个代表已保存文件的对象:
class SavedFile extends Model
{
protected $fillable = [
'disk',
'path',
'publicURI',
];
}
When I save the file, I create a record of it in the database:
当我保存文件时,我在数据库中创建了它的记录:
$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,
]);
}
Whenever I need the public URI, I can just grab it off the SavedFile
model. This is handy for trivial applications, but it breaks down if I ever need to switch storage providers.
每当我需要公共 URI 时,我都可以从SavedFile
模型中获取它。这对于琐碎的应用程序很方便,但如果我需要切换存储提供程序,它就会崩溃。
Leverage Inheritance
利用继承
Another neat trick is to define a method that will resolve the public URI based on a variable defined in the child of an abstract SavedFile
model. That way I'm not hard-coding the URI in the database, and I can create new classes for other storage services with just a couple of variable definitions:
另一个巧妙的技巧是定义一个方法,该方法将根据在抽象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';
}
Now if I have a bunch of files stored on my local filesystem and one day I move them to Amazon S3, I can simply copy the files and swap out the dependencies in my IoC binding definitions and I'm done. No need to do a time consuming and potentially hazardous find-and-replace on a massive database table, since the calculation of the URI is done by the model:
现在,如果我在本地文件系统上存储了一堆文件,并且有一天我将它们移动到 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
Edit:
编辑:
Support for Public and Private Files
支持公共和私人文件
Just add a flag to the object:
只需向对象添加一个标志:
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)