s3 = new S3Client([ 'version' => 'latest', 'region' => $config->s3['region'], 'endpoint' => $config->s3['endpoint'], 'credentials' => new Credentials((string) $config->s3['key'], (string) $config->s3['secret']), 'debug' => $config->s3['debug'], 'use_path_style_endpoint' => $config->s3['path_style_endpoint'], ]); try { // create bucket if it does not already exist if (! $this->s3->doesBucketExist((string) $this->config->s3['bucket'])) { try { $this->s3->createBucket([ 'Bucket' => $this->config->s3['bucket'], ]); } catch (Exception $exception) { log_message('critical', $exception->getMessage()); } } } catch (Exception $exception) { throw new Exception($exception->getMessage(), $exception->getCode(), $exception); } } public function save(File $file, string $key): string|false { try { $this->s3->putObject([ 'Bucket' => $this->config->s3['bucket'], 'Key' => $key, 'SourceFile' => $file, ]); } catch (Exception) { return false; } // delete file after storage in s3 unlink($file->getRealPath()); return $key; } public function delete(string $key): bool { try { $this->s3->deleteObject([ 'Bucket' => $this->config->s3['bucket'], 'Key' => $key, ]); } catch (Exception) { return false; } return true; } public function getUrl(string $key): string { $url = new URI((string) $this->config->s3['endpoint']); if ($this->config->s3['path_style_endpoint'] === true) { $url->setPath($this->config->s3['bucket'] . '/' . $key); return (string) $url; } $url->setHost($this->config->s3['bucket'] . '.' . $url->getHost()); $url->setPath($key); return (string) $url; } public function rename(string $oldKey, string $newKey): bool { try { // copy old object with new key $this->s3->copyObject([ 'Bucket' => $this->config->s3['bucket'], 'CopySource' => $this->config->s3['bucket'] . '/' . $oldKey, 'Key' => $newKey, ]); } catch (Exception) { return false; } // delete old object return $this->delete($oldKey); } public function getFileContents(string $key): string { $result = $this->s3->getObject([ 'Bucket' => $this->config->s3['bucket'], 'Key' => $key, ]); return (string) $result->get('Body'); } public function getFileInput(string $key): string { return $this->getUrl($key); } public function deletePodcastImageSizes(string $podcastHandle): bool { $results = $this->s3->getPaginator('ListObjectsV2', [ 'Bucket' => $this->config->s3['bucket'], 'Prefix' => 'podcasts/' . $podcastHandle . '/', ]); $keys = []; foreach ($results as $result) { $key = array_map(static function ($object) { return $object['Key']; }, $result['Contents']); array_push($keys, ...preg_grep("~^podcasts\/{$podcastHandle}\/.*_.*.\.(jpg|png|webp)$~", $key)); } $objectsToDelete = array_map(static function ($key): array { return [ 'Key' => $key, ]; }, $keys); if ($objectsToDelete === []) { return true; } try { $this->s3->deleteObjects([ 'Bucket' => $this->config->s3['bucket'], 'Delete' => [ 'Objects' => $objectsToDelete, ], ]); } catch (Exception) { return false; } return true; } public function deletePersonImagesSizes(): bool { $objects = $this->s3->getIterator('ListObjectsV2', [ 'Bucket' => $this->config->s3['bucket'], 'prefix' => 'persons/', ]); $objectsKeys = array_map(static function ($object) { return $object['Key']; }, iterator_to_array($objects)); $podcastImageKeys = preg_grep("~^persons\/.*_.*.\.(jpg|png|webp)$~", $objectsKeys); return (bool) $podcastImageKeys; } public function isHealthy(): bool { try { // ok if bucket exists and you have permission to access it $this->s3->headBucket([ 'Bucket' => $this->config->s3['bucket'], ]); } catch (Exception) { return false; } return true; } }