feat: add CloudFlare ImgBed attachment driver

This commit is contained in:
fei152
2026-07-23 04:15:04 +08:00
parent 78f00fb474
commit 5b83fa1722
8 changed files with 327 additions and 3 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ class Chevereto extends Storage {
{
$api = get_setting("image_hosting_chevereto.upload_api_endpoint");
$token = get_setting("image_hosting_chevereto.upload_token");
$logPrefix = "filepath: $filepath, api: $api, token: $token";
$logPrefix = "filepath: $filepath, api: $api";
$httpClient = new \GuzzleHttp\Client();
$response = $httpClient->request('POST', $api, [
'headers' => [
@@ -0,0 +1,145 @@
<?php
namespace Nexus\Attachment\Drivers;
use GuzzleHttp\Client;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\Psr7\UriResolver;
use Nexus\Attachment\Storage;
class CloudflareImgBed extends Storage
{
private ?ClientInterface $httpClient;
public function __construct(?ClientInterface $httpClient = null)
{
$this->httpClient = $httpClient;
}
function upload(string $filepath): string
{
$api = trim((string) $this->setting('upload_api_endpoint'));
if ($api === '') {
throw new \RuntimeException('CloudFlare ImgBed upload endpoint is required.');
}
$uri = new Uri($api);
if (!in_array(strtolower($uri->getScheme()), ['http', 'https'], true) || $uri->getHost() === '') {
throw new \RuntimeException('Invalid CloudFlare ImgBed upload endpoint.');
}
$uri = Uri::withQueryValue($uri, 'returnFormat', 'full');
$querySettings = [
'uploadChannel' => 'upload_channel',
'channelName' => 'channel_name',
'uploadFolder' => 'upload_folder',
];
foreach ($querySettings as $queryName => $settingName) {
$value = trim((string) $this->setting($settingName));
if ($value !== '') {
$uri = Uri::withQueryValue($uri, $queryName, $value);
}
}
$headers = [];
$token = trim((string) $this->setting('upload_token'));
if ($token !== '') {
$headers['Authorization'] = "Bearer $token";
}
try {
$response = $this->httpClient()->request('POST', $uri, [
'headers' => $headers,
'multipart' => [
[
'name' => 'file',
'contents' => Psr7\Utils::tryFopen($filepath, 'r'),
'filename' => basename($filepath),
],
],
'connect_timeout' => 10,
'timeout' => 60,
'http_errors' => false,
]);
} catch (GuzzleException $e) {
do_log(sprintf('CloudFlare ImgBed upload request failed: %s', $e->getMessage()), 'error');
throw new \RuntimeException('CloudFlare ImgBed upload request failed.', 0, $e);
}
$statusCode = $response->getStatusCode();
$body = (string) $response->getBody();
if ($statusCode < 200 || $statusCode >= 300) {
do_log(sprintf(
'CloudFlare ImgBed upload failed, status code: %d, body: %s',
$statusCode,
mb_substr($body, 0, 2000)
), 'error');
throw new \RuntimeException("CloudFlare ImgBed upload failed, status code $statusCode.");
}
try {
$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
do_log('CloudFlare ImgBed returned invalid JSON.', 'error');
throw new \RuntimeException('CloudFlare ImgBed returned invalid JSON.', 0, $e);
}
$first = is_array($result) ? ($result[0] ?? null) : null;
if (!is_array($first)) {
throw new \RuntimeException('CloudFlare ImgBed response does not contain an uploaded file.');
}
$url = trim((string) ($first['publicUrl'] ?? ''));
if ($url === '') {
$url = trim((string) ($first['src'] ?? ''));
}
if ($url === '') {
throw new \RuntimeException('CloudFlare ImgBed response does not contain a file URL.');
}
return $this->absoluteUrl($uri, $url);
}
function getBaseUrl(): string
{
$baseUrl = trim((string) $this->setting('base_url'));
if ($baseUrl !== '') {
return rtrim($baseUrl, '/');
}
$api = trim((string) $this->setting('upload_api_endpoint'));
if ($api === '') {
return '';
}
$uri = new Uri($api);
return (string) $uri->withPath('')->withQuery('')->withFragment('');
}
function getDriverName(): string
{
return static::DRIVER_CLOUDFLARE_IMGBED;
}
protected function setting(string $name, mixed $default = ''): mixed
{
return get_setting("image_hosting_cloudflare_imgbed.$name", $default);
}
private function httpClient(): ClientInterface
{
return $this->httpClient ??= new Client();
}
private function absoluteUrl(Uri $endpoint, string $url): string
{
$result = new Uri($url);
if ($result->getScheme() !== '') {
return (string) $result;
}
$origin = $endpoint->withPath('/')->withQuery('')->withFragment('');
return (string) UriResolver::resolve($origin, $result);
}
}
+1 -1
View File
@@ -10,7 +10,7 @@ class Lsky extends Storage {
{
$api = get_setting("image_hosting_lsky.upload_api_endpoint");
$token = get_setting("image_hosting_lsky.upload_token");
$logPrefix = "filepath: $filepath, api: $api, token: $token";
$logPrefix = "filepath: $filepath, api: $api";
$httpClient = new \GuzzleHttp\Client();
$response = $httpClient->request('POST', $api, [
'headers' => [