Laravel league/flysystem使用AWS S3获取文件URL


Laravel league/flysystem getting file URL with AWS S3

我正在尝试建立一个基于league/flysystem的Laravel文件管理系统:https://github.com/thephpleague/flysystem

我正在使用S3适配器,并使用以下命令保存上传的文件:

$filesystem->write('filename.txt', 'contents');

现在我被困在生成下载文件URL当使用S3适配器。

文件正确保存在S3桶中,我有权限访问它们,我只是不知道如何通过league/flysystem包获得S3的getObjectUrl方法。

I have try:

$contents = $filesystem->read('filename.txt');

但是返回文件的内容。

$contents = $filemanager->listContents();

$paths = $filemanager->listPaths();

但是他们给了我文件的相对路径。

我需要的是像"ht…//[s3-region].amazonaws.com/[bucket]/[dir]/[file]…"

我使用的是Laravel 5.2,下面的代码似乎工作得很好。

Storage::cloud()->url('filename');

我不确定什么正确的方式这样做是与Flysystem,但底层的S3Client对象有这样做的方法。你可以用$filesystem->getAdapter()->getClient()->getObjectUrl($bucket, $key);。当然,构建URL就像您所描述的那样简单,因此您并不真正需要一个特殊的方法来完成它。

当更新到Laravel 5.1时,适配器不再支持此方法。不,在你的配置中,你必须有S3_REGION设置,否则你会得到一个无效的主机名错误,其次,我不得不使用命令作为输入来创建presignedRequest。

    public function getFilePathAttribute($value)
{
    $disk = Storage::disk('s3');
    if ($disk->exists($value)) {
        $command = $disk->getDriver()->getAdapter()->getClient()->getCommand('GetObject', [
            'Bucket'                     => Config::get('filesystems.disks.s3.bucket'),
            'Key'                        => $value,
            'ResponseContentDisposition' => 'attachment;'
        ]);
        $request = $disk->getDriver()->getAdapter()->getClient()->createPresignedRequest($command, '+5 minutes');
        return (string) $request->getUri();
    }
    return $value;
}

也许我回答这个问题有点晚了,但是这里有一种使用Laravel 5内置文件系统的方法。

我创建了一个Manager类,它扩展了Laravel的FilesystemManager来处理公共url检索:

class FilesystemPublicUrlManager extends FilesystemManager
{
    public function publicUrl($name = null, $object_path = '')
    {
        $name = $name ?: $this->getDefaultDriver();
        $config = $this->getConfig($name);
        return $this->{'get' . ucfirst($config['driver']) . 'PublicUrl'}($config, $object_path);
    }
    public function getLocalPublicUrl($config, $object_path = '')
    {
        return URL::to('/public') . $object_path;
    }
    public function getS3PublicUrl($config, $object_path = '')
    {
        $config += ['version' => 'latest'];
        if ($config['key'] && $config['secret']) {
            $config['credentials'] = Arr::only($config, ['key', 'secret']);
        }
        return (new S3Client($config))->getObjectUrl($config['bucket'], $object_path);
    }
}
然后,我在register方法下将这个类添加到AppServiceProvider中,这样它就可以访问当前的应用实例:
$this->app->singleton('filesystemPublicUrl', function () {
    return new FilesystemPublicUrlManager($this->app);
});
最后,为了方便静态访问,我创建了一个Facade类:
use Illuminate'Support'Facades'Facade;
class StorageUrl extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'filesystemPublicUrl';
    }
}

现在,我可以很容易地在我的本地和s3文件系统上获得公共对象的公共url(注意,我没有在FilesystemPublicUrlManager中为ftp或rackspace添加任何内容):

$s3Url = StorageUrl::publicUrl('s3') //using the s3 driver
$localUrl = StorageUrl::publicUrl('local') //using the local driver
$defaultUrl = StorageUrl::publicUrl() //default driver
$objectUrl = StorageUrl::publicUrl('s3', '/path/to/object');

另一种形式的存储::cloud():

    /** @var FilesystemAdapter $disk */
    $s3 = Storage::disk('s3');
    return $s3->url($path);

使用预先指定的请求S3:

public function getFileUrl($key) {
        $s3 = Storage::disk('s3');
        $client = $s3->getDriver()->getAdapter()->getClient();
        $bucket = env('AWS_BUCKET');
        $command = $client->getCommand('GetObject', [
            'Bucket' => $bucket,
            'Key' => $key
        ]);
        $request = $client->createPresignedRequest($command, '+20 minutes');
        return (string) $request->getUri();
    }

对于私有云使用

Storage::disk('s3')->temporaryUrl($path);