Laravel league/flysystem getting file URL with AWS

2019-01-17 12:26发布

问题:

I am trying to build a file management system in Laravel based on league/flysystem: https://github.com/thephpleague/flysystem

I am using the S3 adapter and I have it working to save the uploaded files using:

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

Now I am stuck on generating the download file URL when using the S3 adapter.

The files are saved correctly in the S3 bucket, I have permissions to access them, I just don't know how to get to the S3 getObjectUrl method through the league/flysystem package.

I have tried:

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

but that returns the content of the file.

$contents = $filemanager->listContents();

or

$paths = $filemanager->listPaths();

but they give me the relative paths to my files.

What I need is something like "ht...//[s3-region].amazonaws.com/[bucket]/[dir]/[file]..."

回答1:

I'm not sure what the correct way of doing this is with Flysystem, but the underlying S3Client object has a method for doing that. You could do $filesystem->getAdapter()->getClient()->getObjectUrl($bucket, $key);. Of course, building the URL is as trivial as you described, so you don't really need a special method to do it.



回答2:

I am using Laravel 5.2 and the code below seemed to work fine.

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


回答3:

When updating to Laravel 5.1 this method no longer supported by the adapter. No in your config you must have the S3_REGION set or you will get a invalid hostname error and secondly I had to use the command as input to create the 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;
}


回答4:

Maybe I'm a little late to this question, but here's a way to use Laravel 5's built-in Filesystem.

I created a Manager class that extends Laravel's FilesystemManager to handle the public url retrieval:

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);
    }
}

Then, I added this class to the AppServiceProvider under the register method so it has access to the current app instance:

$this->app->singleton('filesystemPublicUrl', function () {
    return new FilesystemPublicUrlManager($this->app);
});

Finally, for easy static access, I created a Facade class:

use Illuminate\Support\Facades\Facade;

class StorageUrl extends Facade
{

    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'filesystemPublicUrl';
    }
}

Now, I can easily get the public url for my public objects on my local and s3 filesystems (note that I didn't add anything for ftp or rackspace in the FilesystemPublicUrlManager):

$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');


回答5:

Another form of Storage::cloud():

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