get_full_path($filename)); } function about() { return array(null, "File cache backend using S3 protocol (experimental)", "fox", true); } function init($host) { Config::add(self::CACHE_S3_ENDPOINT, "", Config::T_STRING); Config::add(self::CACHE_S3_BUCKET, "", Config::T_STRING); Config::add(self::CACHE_S3_REGION, "", Config::T_STRING); Config::add(self::CACHE_S3_ACCESS_KEY, "", Config::T_STRING); Config::add(self::CACHE_S3_SECRET_KEY, "", Config::T_STRING); $s3_client_props = [ 'version' => 'latest', 'region' => Config::get(self::CACHE_S3_REGION), 'endpoint' => Config::get(self::CACHE_S3_ENDPOINT), 'use_path_style_endpoint' => true, ]; if (Config::get(self::CACHE_S3_ACCESS_KEY) && Config::get(self::CACHE_S3_SECRET_KEY)) { $s3_client_props['credentials'] = [ 'key' => Config::get(self::CACHE_S3_ACCESS_KEY), 'secret' => Config::get(self::CACHE_S3_SECRET_KEY), ]; } /** @phpstan-ignore-next-line */ $this->s3 = new Aws\S3\S3Client($s3_client_props); /** @phpstan-ignore-next-line */ $this->s3->registerStreamWrapper(); } public function get_mtime(string $filename) { return filemtime($this->get_full_path($filename)); } public function set_dir(string $dir): void { $this->dir = $dir; } public function get_dir(): string { return $this->dir; } public function make_dir(): bool { return true; } public function is_writable(?string $filename = null): bool { return true; } public function exists(string $filename): bool { return file_exists($this->get_full_path($filename)); } public function get_size(string $filename) { return filesize($this->get_full_path($filename)); } public function put(string $filename, $data) { return file_put_contents($this->get_full_path($filename), $data); } public function get(string $filename): ?string { return file_get_contents($this->get_full_path($filename)); } public function get_full_path(string $filename): string { return 's3://' . Config::get(self::CACHE_S3_BUCKET) . '/' . ($this->dir ? $this->dir . '/' : '') . basename(clean($filename)); } public function get_mime_type(string $filename) { $fh = fopen($this->get_full_path($filename), 'r'); if ($fh) { $mimetype = mime_content_type($fh); fclose($fh); return $mimetype; } return false; } public function send(string $filename) { return readfile($this->get_full_path($filename)); } public function expire_all(): void { $dh = opendir('s3://' . Config::get(self::CACHE_S3_BUCKET)); $rules = []; if ($dh) { while (($file = readdir($dh)) !== false) { $full_path = $this->get_full_path($file); if (is_dir($full_path) && !file_exists("$full_path/.no-auto-expiry")) { array_push($rules, [ 'ID' => $file, 'Expiration' => [ 'Days' => (int) Config::get(Config::CACHE_MAX_DAYS), ], 'Filter' => [ 'Prefix' => $file ], 'Status' => 'Enabled' ] ); } } closedir($dh); } try { /** @phpstan-ignore-next-line */ $this->s3->putBucketLifecycleConfiguration([ 'Bucket' => Config::get(self::CACHE_S3_BUCKET), 'LifecycleConfiguration' => [ 'Rules' => $rules ] ]); Debug::log("Set lifecycle policy on " . count($rules) . " prefixe(s)."); } catch (Exception $e) { user_error($e, E_USER_WARNING); } } function api_version() { return 2; } }