2019-02-20 11:11:38 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace Bluesquare\StorageBundle\Adaptors;
|
|
|
|
|
|
|
|
use Aws\S3\S3Client;
|
2019-02-21 12:28:32 +01:00
|
|
|
use Bluesquare\StorageBundle\Exceptions\InvalidStorageConfiguration;
|
2019-02-20 12:53:07 +01:00
|
|
|
use Symfony\Component\Config\Definition\Exception\Exception;
|
2019-02-20 11:11:38 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Interface de manipulation du stockage S3
|
|
|
|
* Usage: $storage = new S3Storage('my_storage_name', $config);
|
|
|
|
* @author Maxime Renou
|
|
|
|
*/
|
2019-02-21 12:28:32 +01:00
|
|
|
class S3Storage implements StorageAdaptor
|
2019-02-20 11:11:38 +01:00
|
|
|
{
|
|
|
|
const MODE_PRIVATE = 'private';
|
|
|
|
const MODE_PUBLIC = 'public-read';
|
|
|
|
|
|
|
|
protected $client;
|
|
|
|
protected $bucket;
|
|
|
|
protected $region;
|
|
|
|
|
|
|
|
public function __construct ($storage_name, $config)
|
|
|
|
{
|
2019-02-20 13:03:37 +01:00
|
|
|
if (!($this->configIsNormed($config)))
|
2019-02-21 12:28:32 +01:00
|
|
|
throw new InvalidStorageConfiguration("Invalid $storage_name storage configuration");
|
2019-02-20 12:53:07 +01:00
|
|
|
|
2019-02-20 11:11:38 +01:00
|
|
|
$this->config = $config;
|
|
|
|
$this->bucket = $config['bucket'];
|
2019-02-21 13:20:53 +01:00
|
|
|
$this->bucket_url = $config['bucket_url'];
|
2019-02-20 11:11:38 +01:00
|
|
|
|
|
|
|
$this->client = new S3Client([
|
|
|
|
'version' => isset($config['version']) ? $config['version'] : 'latest',
|
|
|
|
'region' => $config['region'],
|
|
|
|
'endpoint' => $config['endpoint'],
|
|
|
|
'credentials' => [
|
|
|
|
'key' => $config['credentials']['key'],
|
|
|
|
'secret' => $config['credentials']['secret']
|
|
|
|
]
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
2019-07-11 16:55:43 +02:00
|
|
|
public function getClient()
|
|
|
|
{
|
|
|
|
return $this->client;
|
|
|
|
}
|
|
|
|
|
2019-02-21 12:28:32 +01:00
|
|
|
public function mode($name)
|
|
|
|
{
|
|
|
|
if ($name == 'public') return self::MODE_PUBLIC;
|
|
|
|
return self::MODE_PRIVATE;
|
|
|
|
}
|
|
|
|
|
2019-02-20 13:03:37 +01:00
|
|
|
private function configIsNormed($config)
|
2019-02-20 12:53:07 +01:00
|
|
|
{
|
2019-02-20 13:01:22 +01:00
|
|
|
return (
|
|
|
|
isset($config['type']) &&
|
|
|
|
isset($config['bucket']) &&
|
2019-02-21 13:20:53 +01:00
|
|
|
isset($config['bucket_url']) &&
|
2019-02-20 13:01:22 +01:00
|
|
|
isset($config['region']) &&
|
|
|
|
isset($config['endpoint']) &&
|
|
|
|
isset($config['credentials']) &&
|
|
|
|
isset($config['credentials']['key']) &&
|
|
|
|
isset($config['credentials']['secret'])
|
|
|
|
);
|
2019-02-20 12:53:07 +01:00
|
|
|
}
|
|
|
|
|
2019-02-20 11:11:38 +01:00
|
|
|
protected function getPrefix($prefix = null)
|
|
|
|
{
|
|
|
|
$ret = '';
|
2019-07-11 16:55:43 +02:00
|
|
|
if (isset($this->config['path']) && !empty($this->config['path']))
|
|
|
|
{
|
2019-02-20 11:11:38 +01:00
|
|
|
$ret = trim($this->config['path'], '/').'/';
|
2019-07-11 16:55:43 +02:00
|
|
|
if (trim($ret) == '/') $ret = '';
|
2019-02-20 11:11:38 +01:00
|
|
|
}
|
|
|
|
if (!is_null($prefix)) {
|
|
|
|
$ret = ltrim($prefix, '/');
|
|
|
|
}
|
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function index($prefix = null)
|
|
|
|
{
|
|
|
|
return ($this->client->listObjectsV2([
|
|
|
|
'Bucket' => $this->bucket,
|
|
|
|
'Prefix' => $this->getPrefix($prefix)
|
|
|
|
]));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Permet d'obtenir l'URL vers une ressource S3
|
|
|
|
* Cette ressource n'est accessible que si le fichier a été stocké en mode public
|
|
|
|
* @param $target_path
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function url ($target_path)
|
|
|
|
{
|
2019-02-21 13:20:53 +01:00
|
|
|
return rtrim($this->bucket_url, '/').'/'.$this->getPrefix().ltrim($target_path, '/');
|
2019-02-20 11:11:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Permet de stocker un fichier dans S3
|
|
|
|
* @param $source_path
|
|
|
|
* @param $target_path
|
|
|
|
* @param string $permissions
|
|
|
|
* @return \Aws\Result
|
|
|
|
*/
|
|
|
|
public function store ($source_path, $target_path, $permissions = self::MODE_PRIVATE)
|
|
|
|
{
|
|
|
|
return $this->client->putObject([
|
|
|
|
'Bucket' => $this->bucket,
|
|
|
|
'Path' => $this->getPrefix().$target_path,
|
|
|
|
'Key' => $this->getPrefix().$target_path,
|
|
|
|
'Body' => file_get_contents($source_path),
|
|
|
|
'ACL' => $permissions
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Permet de récupérer un fichier dans S3 pour le stocker en local
|
|
|
|
* @param $distant_path
|
|
|
|
* @param $local_path
|
|
|
|
*/
|
|
|
|
public function retrieve ($distant_path, $local_path)
|
|
|
|
{
|
|
|
|
$file_stream = fopen($local_path, 'w');
|
|
|
|
|
|
|
|
$aws_stream = $this->client->getObject([
|
|
|
|
'Bucket' => $this->bucket,
|
|
|
|
'Key' => $this->getPrefix().$distant_path,
|
|
|
|
'Path' => $this->getPrefix().$distant_path,
|
|
|
|
])->get('Body')->detach();
|
|
|
|
|
|
|
|
stream_copy_to_stream($aws_stream, $file_stream);
|
|
|
|
fclose($file_stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Permet de stream un fichier stocké dans S3
|
|
|
|
* @param $distant_path
|
|
|
|
* @param $target_stream
|
|
|
|
*/
|
|
|
|
public function stream ($distant_path, $target_stream)
|
|
|
|
{
|
|
|
|
$aws_stream = $this->client->getObject([
|
|
|
|
'Bucket' => $this->bucket,
|
|
|
|
'Key' => $this->getPrefix().$distant_path,
|
|
|
|
'Path' => $this->getPrefix().$distant_path,
|
|
|
|
])->get('Body')->detach();
|
|
|
|
|
|
|
|
stream_copy_to_stream($aws_stream, $target_stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Permet de supprimer un fichier stocké dans S3
|
|
|
|
* @param $distant_path
|
|
|
|
*/
|
|
|
|
public function delete ($distant_path)
|
|
|
|
{
|
|
|
|
$this->client->deleteObject([
|
|
|
|
'Bucket' => $this->bucket,
|
|
|
|
'Path' => $this->getPrefix().$distant_path,
|
|
|
|
'Key' => $this->getPrefix().$distant_path,
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
}
|