<?php
namespace App\Service;
use Aws\Exception\AwsException;
use Aws\S3\S3Client;
use Psr\Log\LoggerInterface;
class S3Service
{
private $s3Client;
private $bucket;
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->s3Client = new S3Client([
'region' => $_ENV['AWS_REGION'],
'version' => 'latest',
'credentials' => [
'key' => $_ENV['AWS_ACCESS_KEY_ID'],
'secret' => $_ENV['AWS_SECRET_ACCESS_KEY'],
],
]);
$this->bucket = $_ENV['AWS_BUCKET_NAME'];
$this->logger = $logger;
}
/**
* Valide qu'une clé S3 n'est pas vide
*/
private function validateKey($key)
{
if (empty($key) || trim($key) === '') {
throw new \InvalidArgumentException('La clé S3 ne peut pas être vide');
}
return trim($key);
}
public function listFiles($prefix = '')
{
try {
$objects = $this->s3Client->listObjectsV2([
'Bucket' => $this->bucket,
'Prefix' => $prefix,
]);
return $objects['Contents'] ?? [];
} catch (\Exception $e) {
$this->logger->error("Erreur lors de la récupération des fichiers S3 : " . $e->getMessage());
return [];
}
}
public function uploadDocument($content, $key)
{
try {
// Validation et nettoyage de la clé
$cleanKey = $this->validateKey($key);
$cleanKey = str_replace(" ", "_", $cleanKey);
$result = $this->s3Client->putObject([
'Bucket' => $this->bucket,
'Key' => $cleanKey,
'Body' => $content,
'ACL' => 'private',
'ServerSideEncryption' => 'AES256',
]);
return $result->get('ObjectURL') ?? $result->get('Location');
} catch (\InvalidArgumentException $e) {
$this->logger->error("Clé S3 invalide : " . $e->getMessage());
return false;
} catch (\Exception $e) {
$this->logger->error("Erreur lors de l'upload vers S3 : " . $e->getMessage());
return false;
}
}
public function downloadDocument($s3Key)
{
try {
// Validation de la clé avant utilisation
$cleanKey = $this->validateKey($s3Key);
$result = $this->s3Client->getObject([
'Bucket' => $this->bucket,
'Key' => $cleanKey,
]);
return $result['Body'];
} catch (\InvalidArgumentException $e) {
$this->logger->error("Clé S3 invalide pour le téléchargement : " . $e->getMessage());
return false;
} catch (AwsException $e) {
$this->logger->error("Erreur AWS lors du téléchargement : " . $e->getMessage());
return false;
}
}
public function getSignedUrl($key, $expiration = '+1 hour')
{
try {
// Validation de la clé
$cleanKey = $this->validateKey($key);
$command = $this->s3Client->getCommand('GetObject', [
'Bucket' => $this->bucket,
'Key' => $cleanKey,
]);
$signedUrl = $this->s3Client->createPresignedRequest($command, $expiration)->getUri();
return (string)$signedUrl;
} catch (\InvalidArgumentException $e) {
$this->logger->error("Clé S3 invalide pour l'URL signée : " . $e->getMessage());
return false;
} catch (\Exception $e) {
$this->logger->error("Erreur lors de la génération de l'URL signée : " . $e->getMessage());
return false;
}
}
public function getJson($key)
{
try {
// Validation de la clé
$cleanKey = $this->validateKey($key);
$result = $this->s3Client->getObject([
'Bucket' => $this->bucket,
'Key' => $cleanKey,
]);
return json_decode($result['Body'], true);
} catch (\InvalidArgumentException $e) {
$this->logger->error("Clé S3 invalide pour le JSON : " . $e->getMessage());
throw $e;
} catch (\Exception $e) {
$this->logger->error("Erreur lors de la récupération du JSON depuis S3 : " . $e->getMessage());
throw $e;
}
}
public function extractKeyFromUrl($url)
{
if (empty($url)) {
return '';
}
$parsedUrl = parse_url($url);
if (isset($parsedUrl['path'])) {
// Supprime le premier slash initial "/" et les slashes multiples
$key = ltrim($parsedUrl['path'], '/');
// Nettoie les slashes doubles
$key = preg_replace('/\/+/', '/', $key);
return $key;
}
return $url;
}
public function getFileFromS3($fileName)
{
try {
// Validation de la clé
$cleanFileName = $this->validateKey($fileName);
$result = $this->s3Client->getObject([
'Bucket' => $this->bucket,
'Key' => $cleanFileName,
]);
return $result['Body'];
} catch (\InvalidArgumentException $e) {
$this->logger->error("Nom de fichier S3 invalide : " . $e->getMessage());
return null;
} catch (AwsException $e) {
$this->logger->error("Error retrieving file from S3: " . $e->getMessage());
return null;
}
}
/**
* Vérifie si un objet existe dans S3
*/
public function objectExists($key)
{
try {
$cleanKey = $this->validateKey($key);
$this->s3Client->headObject([
'Bucket' => $this->bucket,
'Key' => $cleanKey,
]);
return true;
} catch (\Exception $e) {
return false;
}
}
}