Laravel-Flysystem and Creating Time Limited Public Urls on S3
We needed to offer timed links to the urls and we are using Laravel-Flysystem
Aaron Smith found this how to but I wanted it to work with existing use of FlySystem.
I ended up moving the code into a trait so we could use this one feature
<?php namespace AlfredNutileInc\CoreApp\Helpers;
use GrahamCampbell\Flysystem\Facades\Flysystem;
use Illuminate\Support\Facades\Log;
trait S3Helper {
protected $path_for_assets;
protected $expire_time;
public $driver = 'awss3';
/**
* @return string
*/
public function getDriver()
{
return $this->driver;
}
/**
* @param string $driver
*/
public function setDriver($driver)
{
$this->driver = $driver;
}
public function iterateOverFiles($files)
{
foreach($files as $key => $file)
{
if(isset($file['path'])) {
$files[$key]['url'] = $this->getSignedUrl($file['path']);
}
}
return $files;
}
protected function getFiles()
{
$this->path_for_assets = $this->project_id . '/' . $this->id;
$files = Flysystem::listContents($this->path_for_assets);
if(!$files)
return [];
return $this->iterateOverFiles($files);
}
/**
* https://coderwall.com/p/pr-gwg/create-aws-s3-signed-requests-with-php
*/
protected function getSignedUrl($filename)
{
$awsKeyId = Flysystem::getConnectionConfig($this->getDriver())['key'];
$awsSecret = Flysystem::getConnectionConfig($this->getDriver())['secret'];
$expires = $this->getExpireTime();
$httpVerb = "GET";
$contentMD5 = "";
$contentType = "";
$amzHeaders = "";
$amzResource = "/" . Flysystem::getConnectionConfig($this->getDriver())['bucket'] . "/" . $filename;
$request = sprintf("%s\n%s\n%s\n%s\n%s%s" , $httpVerb , $contentMD5 , $contentType , $expires , $amzHeaders , $amzResource );
$base64signed = urlencode(base64_encode( hash_hmac( 'sha1' , $request, $awsSecret , true ) ));
$url = "http://s3.amazonaws.com%s?AWSAccessKeyId=%s&Expires=%s&Signature=%s";
$url = sprintf( $url , $amzResource , $awsKeyId , $expires , $base64signed );
return $url;
}
public function setExpireTime($time = false)
{
if($time == false)
{
$time = time() + (10*60);
}
$this->expire_time = $time;
}
public function getExpireTime()
{
if($this->expire_time == false)
{
$this->setExpireTime();
}
return $this->expire_time;
}
}
Ideally seconds could be passed in too.
Then in any model/repo I can use it like this
public function assets()
{
try
{
$files = $this->getFiles();
return ['images' => $files, 'videos' => []];
} catch(\Exception $e)
{
throw new \Exception(sprintf("Error getting files %s", $e->getMessage()));
}
}
comments powered by Disqus