nineskeletor/src/Service/MinioService.php

247 lines
7.3 KiB
PHP
Executable File

<?php
namespace App\Service;
use Aws\S3\Exception\S3Exception;
use Exception;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class MinioService
{
public const ERR_UNAVAILABLE = 'Service de gestion de fichiers momentanément indisponible.';
public const ERR_FILE_NOT_FOUND = 'messages.minio.404';
private $rootPath;
private $client;
private $listClient;
private $minioBucket;
private $minioRoot;
private $minioPathStyle;
private $minioSecure;
public function __construct($rootPath, $minioUrl, $minioKey, $minioSecret, $minioBucket, $minioRoot, $minioPathstyle, $minioSecure)
{
$this->rootPath = $rootPath;
$this->minioBucket = $minioBucket;
$this->minioPathStyle = (1 == $minioPathstyle ? true : false);
$this->minioRoot = $minioRoot;
$this->client = $this->getClient($minioUrl, $minioKey, $minioSecret, $minioPathstyle, $minioSecure);
$this->initBucket();
}
public function image(string $file, string $filename)
{
try {
$result = $this->client->getObject([
'Bucket' => $this->minioBucket,
'Key' => $this->minioRoot.$file,
]);
} catch (S3Exception $e) {
switch ($e->getResponse()->getStatusCode()) {
case 404:
throw new NotFoundHttpException(self::ERR_FILE_NOT_FOUND);
break;
default:
\Sentry\captureException($e);
throw new Exception(self::ERR_UNAVAILABLE);
break;
}
} catch (Exception $e) {
\Sentry\captureException($e);
throw new Exception(self::ERR_UNAVAILABLE);
}
return $result->get('Body');
}
public function download(string $file, string $filename, bool $usecache = true)
{
// On s'assure que le repertoire temporaire de destination existe bien
$fs = new Filesystem();
$tmpdir = $this->rootPath.'/var/tmp';
$fs->mkdir($tmpdir.'/'.dirname($filename));
// Approche repassant par le serveur d'appel
if (!$usecache || !$fs->exists($tmpdir.'/'.$filename)) {
try {
$result = $this->client->getObject([
'Bucket' => $this->minioBucket,
'Key' => $this->minioRoot.$file,
'SaveAs' => $tmpdir.'/'.$filename,
]);
} catch (S3Exception $e) {
switch ($e->getResponse()->getStatusCode()) {
case 404:
throw new NotFoundHttpException(self::ERR_FILE_NOT_FOUND);
break;
default:
\Sentry\captureException($e);
throw new Exception(self::ERR_UNAVAILABLE);
break;
}
} catch (Exception $e) {
\Sentry\captureException($e);
throw new Exception(self::ERR_UNAVAILABLE);
}
}
return $tmpdir.'/'.$filename;
}
public function upload($file, $filename, $deleteSource = false)
{
try {
$this->client->putObject([
'Bucket' => $this->minioBucket,
'Key' => $this->minioRoot.$filename,
'SourceFile' => $file,
]);
} catch (Exception $e) {
\Sentry\captureException($e);
throw new Exception(self::ERR_UNAVAILABLE);
}
if ($deleteSource) {
$tmpdir = $this->rootPath.'/var/tmp';
@unlink($tmpdir.'/'.$filename);
}
}
/**
* move.
*
* @param bool $deleteSource
*
* @return void
*/
public function move(string $from, string $to, $deleteSource = false)
{
try {
$this->client->copyObject([
'Bucket' => $this->minioBucket,
'Key' => $this->minioRoot.$to,
'CopySource' => $this->minioBucket.'/'.$this->minioRoot.$from,
]);
} catch (Exception $e) {
\Sentry\captureException($e);
throw new Exception(self::ERR_UNAVAILABLE);
}
if ($deleteSource) {
$this->delete($from);
}
}
/**
* delete.
*
* @return void
*/
public function delete(string $file)
{
try {
$this->client->deleteObject([
'Bucket' => $this->minioBucket,
'Key' => $this->minioRoot.$file,
]);
} catch (Exception $e) {
\Sentry\captureException($e);
throw new Exception(self::ERR_UNAVAILABLE);
}
}
/**
* countKeys.
*
* @return int
*/
public function countKeys(string $prefix)
{
// On utilise un path spécifique car listObjectsV2 utilise une autre config de client
try {
$response = $this->client->listObjectsV2([
'Bucket' => $this->minioBucket,
'Prefix' => $prefix,
]);
return $response->get('KeyCount');
} catch (Exception $e) {
\Sentry\captureException($e);
throw new Exception(self::ERR_UNAVAILABLE);
}
}
/**
* listKeys.
*
* @return array
*/
public function listKeys(string $prefix)
{
// On utilise un path spécifique car listObjectsV2 utilise une autre config de client
try {
$response = $this->client->listObjectsV2([
'Bucket' => $this->minioBucket,
'Prefix' => $prefix,
]);
return $response->get('Contents');
} catch (Exception $e) {
\Sentry\captureException($e);
throw new Exception(self::ERR_UNAVAILABLE);
}
}
/**
* download.
*
* @param string $file Nom du fichier dans minio
* @param string $filename Nom du fichier dans la réponse
* @param bool $returnFile Retourner un fichier ou une réponse
*/
protected function getClient($minioUrl, $minioKey, $minioSecret, bool $minioPathstyle, bool $minioSecure)
{
$client = new \Aws\S3\S3Client([
'version' => 'latest',
'region' => 'eu-west-1',
'endpoint' => $minioUrl,
// On force le mode DNS
'use_path_style_endpoint' => $minioPathstyle,
'credentials' => [
'key' => $minioKey,
'secret' => $minioSecret,
],
// On désactive les checks SSL pour le moment
'http' => [
'verify' => $minioSecure,
],
]);
return $client;
}
protected function initBucket()
{
try {
$bucketExists = false;
$buckets = $this->client->listBuckets()->toArray()['Buckets'];
foreach ($buckets as $bucket) {
if ($this->minioBucket == $bucket['Name']) {
$bucketExists = true;
}
}
if (!$bucketExists) {
$this->client->createBucket([
'Bucket' => $this->minioBucket,
]);
}
} catch (Exception $e) {
throw new Exception(self::ERR_UNAVAILABLE);
}
}
}