'latest', 'region' => $config['region'], 'credentials' => [ 'key' => $config['access_key'], 'secret' => $config['secret_key'], ] ]; // Add custom endpoint for MinIO if (!empty($config['endpoint'])) { $s3_config['endpoint'] = $config['endpoint']; $s3_config['use_path_style_endpoint'] = true; } if (!class_exists('Aws\S3\S3Client')) { throw new Exception('🐱 Hiss! AWS SDK not found. Install it with: composer require aws/aws-sdk-php'); } $s3 = new Aws\S3\S3Client($s3_config); // Generate remote path with cat-themed organization $remote_path = $this->generate_cat_remote_path($file_path); // Upload file $result = $s3->putObject([ 'Bucket' => $config['bucket'], 'Key' => $remote_path, 'SourceFile' => $file_path, 'Metadata' => [ 'created-by' => 'tigerstyle-life9', 'backup-type' => 'cat-lives', 'created-at' => date('c'), 'purr-factor' => 'maximum' ] ]); return [ 'url' => $result['ObjectURL'] ?? '', 'remote_path' => $remote_path, 'storage_id' => $remote_path, 'metadata' => [ 'size' => filesize($file_path), 'created' => date('Y-m-d H:i:s'), 'etag' => $result['ETag'] ?? '', 'cat_rating' => '🐱🐱🐱🐱🐱' ] ]; } catch (Exception $e) { throw new Exception('🐱 Cat-astrophic S3 upload failure: ' . $e->getMessage()); } } /** * Retrieve file from S3 storage * * @param string $remote_path Remote file path or ID * @param string $local_path Local destination path * @param array $config Storage configuration * @return bool Success status */ public function retrieve($remote_path, $local_path, $config = []) { try { $s3 = $this->create_s3_client($config); $s3->getObject([ 'Bucket' => $config['bucket'], 'Key' => $remote_path, 'SaveAs' => $local_path ]); return true; } catch (Exception $e) { error_log('🐱 S3 download failed: ' . $e->getMessage()); return false; } } /** * Delete file from S3 storage * * @param string $remote_path Remote file path or ID * @param array $config Storage configuration * @return bool Success status */ public function delete($remote_path, $config = []) { try { $s3 = $this->create_s3_client($config); $s3->deleteObject([ 'Bucket' => $config['bucket'], 'Key' => $remote_path ]); return true; } catch (Exception $e) { error_log('🐱 S3 deletion failed: ' . $e->getMessage()); return false; } } /** * Test S3 storage connection * * @param array $config Storage configuration * @return bool Connection status */ public function test_connection($config = []) { try { $s3 = $this->create_s3_client($config); // Test by checking if bucket exists and is accessible $s3->headBucket(['Bucket' => $config['bucket']]); return true; } catch (Exception $e) { error_log('🐱 S3 connection test failed: ' . $e->getMessage()); return false; } } /** * List backup files in S3 * * @param array $config Storage configuration * @return array List of backup files */ public function list_backups($config = []) { try { $s3 = $this->create_s3_client($config); $result = $s3->listObjects([ 'Bucket' => $config['bucket'], 'Prefix' => 'tigerstyle-life9/' ]); $backups = []; if (isset($result['Contents'])) { foreach ($result['Contents'] as $object) { $backups[] = [ 'key' => $object['Key'], 'size' => $object['Size'], 'modified' => $object['LastModified']->format('Y-m-d H:i:s'), 'cat_rating' => $this->calculate_cat_rating($object['Size']) ]; } } return $backups; } catch (Exception $e) { error_log('🐱 Failed to list S3 backups: ' . $e->getMessage()); return []; } } /** * Create S3 client with proper configuration * * @param array $config Storage configuration * @return Aws\S3\S3Client */ private function create_s3_client($config) { $s3_config = [ 'version' => 'latest', 'region' => $config['region'], 'credentials' => [ 'key' => $config['access_key'], 'secret' => $config['secret_key'], ] ]; // Add custom endpoint for MinIO if (!empty($config['endpoint'])) { $s3_config['endpoint'] = $config['endpoint']; $s3_config['use_path_style_endpoint'] = true; } return new Aws\S3\S3Client($s3_config); } /** * Generate cat-themed remote path * * @param string $file_path Local file path * @return string Remote file path */ protected function generate_cat_remote_path($file_path) { $filename = basename($file_path); $date_path = date('Y/m/d'); $hour = date('H'); // Add cat-themed hour descriptions $cat_time = ''; if ($hour >= 0 && $hour < 6) { $cat_time = 'midnight-prowl'; } elseif ($hour >= 6 && $hour < 12) { $cat_time = 'morning-stretch'; } elseif ($hour >= 12 && $hour < 18) { $cat_time = 'afternoon-nap'; } else { $cat_time = 'evening-hunt'; } return "tigerstyle-life9/{$date_path}/{$cat_time}/{$filename}"; } /** * Calculate cat rating based on file size * * @param int $size File size in bytes * @return string Cat rating */ private function calculate_cat_rating($size) { $size_mb = $size / (1024 * 1024); if ($size_mb < 10) { return '🐱'; } elseif ($size_mb < 50) { return '🐱🐱'; } elseif ($size_mb < 100) { return '🐱🐱🐱'; } elseif ($size_mb < 500) { return '🐱🐱🐱🐱'; } else { return '🐱🐱🐱🐱🐱'; } } }