nhance/app/Libraries/S3Service.php
2025-12-24 18:41:31 +05:30

268 lines
8.5 KiB
PHP

<?php
namespace App\Libraries;
use Aws\S3\S3Client;
use Aws\Exception\AwsException;
use CodeIgniter\HTTP\ResponseInterface;
class S3Service
{
protected $s3Client;
protected $bucket;
protected $region;
protected $baseUrl;
public function __construct()
{
$this->bucket = getenv('AWS_BUCKET');
$this->region = getenv('AWS_DEFAULT_REGION');
$this->s3Client = new S3Client([
'version' => 'latest',
'region' => $this->region,
'credentials' => [
'key' => getenv('AWS_ACCESS_KEY_ID'),
'secret' => getenv('AWS_SECRET_ACCESS_KEY'),
],
]);
$this->baseUrl = "https://{$this->bucket}.s3.{$this->region}.amazonaws.com/";
// echo $this->baseUrl;die();
}
/**
* Upload file to S3
*
* @param mixed $file File object or file path
* @param string $folder Folder path in S3 bucket (optional)
* @param string $fileName Custom file name (optional)
* @return array ['success' => bool, 'url' => string, 'key' => string, 'message' => string]
*/
public function upload($file, string $folder = '', string $fileName = null): array
{
try {
// Handle CodeIgniter file upload object
if (is_object($file) && method_exists($file, 'isValid')) {
if (!$file->isValid()) {
return [
'success' => false,
'message' => 'Invalid file upload',
'url' => null,
'key' => null
];
}
$filePath = $file->getTempName();
$originalName = $fileName ?? $file->getClientName();
} else {
// Handle file path string
$filePath = $file;
$originalName = $fileName ?? basename($file);
}
// Generate unique file name
$extension = pathinfo($originalName, PATHINFO_EXTENSION);
// $uniqueName = pathinfo($originalName, PATHINFO_FILENAME) . '_' . time() . '.' . $extension;
$uniqueName = pathinfo($originalName, PATHINFO_FILENAME) . '.' . $extension;
// Build S3 key (path)
$key = $folder ? rtrim($folder, '/') . '/' . $uniqueName : $uniqueName;
// Upload to S3
// NEW - Faster with streaming and proper content type
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $filePath);
finfo_close($finfo);
$result = $this->s3Client->putObject([
'Bucket' => $this->bucket,
'Key' => $key,
'Body' => fopen($filePath, 'rb'), // Stream instead of loading into memory
'ContentType' => $mimeType,
// 'ACL' => 'public-read',
]);
return [
'success' => true,
'url' => $this->baseUrl . $key,
'key' => $key,
'message' => 'File uploaded successfully'
];
} catch (AwsException $e) {
log_message('error', 'S3 Upload Error: ' . $e->getMessage());
return [
'success' => false,
'message' => 'Upload failed: ' . $e->getMessage(),
'url' => null,
'key' => null
];
}
}
/**
* Download file from S3
*
* @param string $key S3 object key (file path in bucket)
* @param string $savePath Local path to save the file (optional)
* @return array ['success' => bool, 'path' => string, 'content' => string, 'message' => string]
*/
public function download(string $key, string $savePath = null): array
{
try {
$result = $this->s3Client->getObject([
'Bucket' => $this->bucket,
'Key' => $key,
]);
$content = (string) $result['Body'];
// If save path is provided, save to local file
if ($savePath) {
$directory = dirname($savePath);
if (!is_dir($directory)) {
mkdir($directory, 0755, true);
}
file_put_contents($savePath, $content);
return [
'success' => true,
'path' => $savePath,
'content' => $content,
'message' => 'File downloaded successfully'
];
}
return [
'success' => true,
'path' => null,
'content' => $content,
'message' => 'File content retrieved successfully'
];
} catch (AwsException $e) {
log_message('error', 'S3 Download Error: ' . $e->getMessage());
return [
'success' => false,
'path' => null,
'content' => null,
'message' => 'Download failed: ' . $e->getMessage()
];
}
}
/**
* Get a pre-signed URL for temporary access to a private file
*
* @param string $key S3 object key
* @param int $expiration Expiration time in minutes (default: 60)
* @return array ['success' => bool, 'url' => string, 'message' => string]
*/
public function getPresignedUrl(string $key, int $expiration = 60): array
{
try {
$cmd = $this->s3Client->getCommand('GetObject', [
'Bucket' => $this->bucket,
'Key' => $key
]);
$request = $this->s3Client->createPresignedRequest($cmd, "+{$expiration} minutes");
$presignedUrl = (string) $request->getUri();
return [
'success' => true,
'url' => $presignedUrl,
'message' => 'Pre-signed URL generated successfully'
];
} catch (AwsException $e) {
log_message('error', 'S3 Presigned URL Error: ' . $e->getMessage());
return [
'success' => false,
'url' => null,
'message' => 'Failed to generate URL: ' . $e->getMessage()
];
}
}
/**
* Delete file from S3
*
* @param string $key S3 object key
* @return array ['success' => bool, 'message' => string]
*/
public function delete(string $key): array
{
try {
$this->s3Client->deleteObject([
'Bucket' => $this->bucket,
'Key' => $key,
]);
return [
'success' => true,
'message' => 'File deleted successfully'
];
} catch (AwsException $e) {
log_message('error', 'S3 Delete Error: ' . $e->getMessage());
return [
'success' => false,
'message' => 'Delete failed: ' . $e->getMessage()
];
}
}
/**
* Check if file exists in S3
*
* @param string $key S3 object key
* @return bool
*/
public function exists(string $key): bool
{
return $this->s3Client->doesObjectExist($this->bucket, $key);
}
/**
* List files in S3 bucket
*
* @param string $prefix Folder prefix (optional)
* @return array ['success' => bool, 'files' => array, 'message' => string]
*/
public function listFiles(string $prefix = ''): array
{
try {
$result = $this->s3Client->listObjectsV2([
'Bucket' => $this->bucket,
'Prefix' => $prefix,
]);
$files = [];
if (isset($result['Contents'])) {
foreach ($result['Contents'] as $object) {
$files[] = [
'key' => $object['Key'],
'size' => $object['Size'],
'last_modified' => $object['LastModified']->format('Y-m-d H:i:s'),
'url' => $this->baseUrl . $object['Key']
];
}
}
return [
'success' => true,
'files' => $files,
'message' => 'Files retrieved successfully'
];
} catch (AwsException $e) {
log_message('error', 'S3 List Error: ' . $e->getMessage());
return [
'success' => false,
'files' => [],
'message' => 'Failed to list files: ' . $e->getMessage()
];
}
}
}