268 lines
8.5 KiB
PHP
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()
|
|
];
|
|
}
|
|
}
|
|
} |