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() ]; } } }