mirror of
https://github.com/appwrite/appwrite
synced 2026-05-24 09:28:40 +00:00
Merge pull request #10255 from appwrite/chore-support-svg-favicon
chore: add support for svg favicons
This commit is contained in:
commit
d28e0152fd
4 changed files with 91 additions and 7 deletions
|
|
@ -10,6 +10,7 @@ use Appwrite\URL\URL as URLParse;
|
||||||
use Appwrite\Utopia\Response;
|
use Appwrite\Utopia\Response;
|
||||||
use chillerlan\QRCode\QRCode;
|
use chillerlan\QRCode\QRCode;
|
||||||
use chillerlan\QRCode\QROptions;
|
use chillerlan\QRCode\QROptions;
|
||||||
|
use enshrined\svgSanitize\Sanitizer as SvgSanitizer;
|
||||||
use Utopia\App;
|
use Utopia\App;
|
||||||
use Utopia\Config\Config;
|
use Utopia\Config\Config;
|
||||||
use Utopia\Database\Database;
|
use Utopia\Database\Database;
|
||||||
|
|
@ -362,7 +363,8 @@ App::get('/v1/avatars/favicon')
|
||||||
$client = new Client();
|
$client = new Client();
|
||||||
try {
|
try {
|
||||||
$res = $client
|
$res = $client
|
||||||
->setAllowRedirects(false)
|
->setAllowRedirects(true)
|
||||||
|
->setMaxRedirects(5)
|
||||||
->setUserAgent(\sprintf(
|
->setUserAgent(\sprintf(
|
||||||
APP_USERAGENT,
|
APP_USERAGENT,
|
||||||
System::getEnv('_APP_VERSION', 'UNKNOWN'),
|
System::getEnv('_APP_VERSION', 'UNKNOWN'),
|
||||||
|
|
@ -399,6 +401,12 @@ App::get('/v1/avatars/favicon')
|
||||||
$ext = \pathinfo(\parse_url($absolute, PHP_URL_PATH), PATHINFO_EXTENSION);
|
$ext = \pathinfo(\parse_url($absolute, PHP_URL_PATH), PATHINFO_EXTENSION);
|
||||||
|
|
||||||
switch ($ext) {
|
switch ($ext) {
|
||||||
|
case 'svg':
|
||||||
|
// SVG icons are prioritized by assigning the maximum possible value.
|
||||||
|
$space = PHP_INT_MAX;
|
||||||
|
$outputHref = $absolute;
|
||||||
|
$outputExt = $ext;
|
||||||
|
break;
|
||||||
case 'ico':
|
case 'ico':
|
||||||
case 'png':
|
case 'png':
|
||||||
case 'jpg':
|
case 'jpg':
|
||||||
|
|
@ -437,7 +445,8 @@ App::get('/v1/avatars/favicon')
|
||||||
$client = new Client();
|
$client = new Client();
|
||||||
try {
|
try {
|
||||||
$res = $client
|
$res = $client
|
||||||
->setAllowRedirects(false)
|
->setAllowRedirects(true)
|
||||||
|
->setMaxRedirects(5)
|
||||||
->fetch($outputHref);
|
->fetch($outputHref);
|
||||||
} catch (\Throwable) {
|
} catch (\Throwable) {
|
||||||
throw new Exception(Exception::AVATAR_REMOTE_URL_FAILED);
|
throw new Exception(Exception::AVATAR_REMOTE_URL_FAILED);
|
||||||
|
|
@ -449,14 +458,33 @@ App::get('/v1/avatars/favicon')
|
||||||
|
|
||||||
$data = $res->getBody();
|
$data = $res->getBody();
|
||||||
|
|
||||||
if ('ico' == $outputExt) { // Skip crop, Imagick isn\'t supporting icon files
|
if ('ico' === $outputExt) { // Skip crop, Imagick isn\'t supporting icon files
|
||||||
if (empty($data) || (\mb_substr($data, 0, 5) === '<html') || \mb_substr($data, 0, 5) === '<!doc') {
|
if (
|
||||||
|
empty($data) ||
|
||||||
|
stripos($data, '<html') === 0 ||
|
||||||
|
stripos($data, '<!doc') === 0
|
||||||
|
) {
|
||||||
throw new Exception(Exception::AVATAR_ICON_NOT_FOUND, 'Favicon not found');
|
throw new Exception(Exception::AVATAR_ICON_NOT_FOUND, 'Favicon not found');
|
||||||
}
|
}
|
||||||
$response
|
$response
|
||||||
->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days
|
->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days
|
||||||
->setContentType('image/x-icon')
|
->setContentType('image/x-icon')
|
||||||
->file($data);
|
->file($data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('svg' === $outputExt) { // Skip crop, Imagick isn\'t supporting svg files
|
||||||
|
$sanitizer = new SvgSanitizer();
|
||||||
|
$sanitizer->minify(true);
|
||||||
|
$cleanSvg = $sanitizer->sanitize($data);
|
||||||
|
if ($cleanSvg === false) {
|
||||||
|
throw new \Exception('SVG sanitization failed');
|
||||||
|
}
|
||||||
|
$response
|
||||||
|
->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days
|
||||||
|
->setContentType('image/svg+xml')
|
||||||
|
->file($cleanSvg);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$image = new Image($data);
|
$image = new Image($data);
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,8 @@
|
||||||
"adhocore/jwt": "1.1.*",
|
"adhocore/jwt": "1.1.*",
|
||||||
"spomky-labs/otphp": "^10.0",
|
"spomky-labs/otphp": "^10.0",
|
||||||
"webonyx/graphql-php": "14.11.*",
|
"webonyx/graphql-php": "14.11.*",
|
||||||
"league/csv": "9.14.*"
|
"league/csv": "9.14.*",
|
||||||
|
"enshrined/svg-sanitize": "0.21.*"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"ext-fileinfo": "*",
|
"ext-fileinfo": "*",
|
||||||
|
|
|
||||||
47
composer.lock
generated
47
composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "edbe5912c45e1f467f398541a75a77de",
|
"content-hash": "7b2ef6192403daf5c492219822ce0aa1",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "adhocore/jwt",
|
"name": "adhocore/jwt",
|
||||||
|
|
@ -628,6 +628,51 @@
|
||||||
],
|
],
|
||||||
"time": "2023-08-10T19:36:49+00:00"
|
"time": "2023-08-10T19:36:49+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "enshrined/svg-sanitize",
|
||||||
|
"version": "0.21.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/darylldoyle/svg-sanitizer.git",
|
||||||
|
"reference": "5e477468fac5c5ce933dce53af3e8e4e58dcccc9"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/5e477468fac5c5ce933dce53af3e8e4e58dcccc9",
|
||||||
|
"reference": "5e477468fac5c5ce933dce53af3e8e4e58dcccc9",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-libxml": "*",
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^6.5 || ^8.5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"enshrined\\svgSanitize\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"GPL-2.0-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Daryll Doyle",
|
||||||
|
"email": "daryll@enshrined.co.uk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "An SVG sanitizer for PHP",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/darylldoyle/svg-sanitizer/issues",
|
||||||
|
"source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.21.0"
|
||||||
|
},
|
||||||
|
"time": "2025-01-13T09:32:25+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "giggsey/libphonenumber-for-php-lite",
|
"name": "giggsey/libphonenumber-for-php-lite",
|
||||||
"version": "8.13.36",
|
"version": "8.13.36",
|
||||||
|
|
|
||||||
|
|
@ -284,7 +284,17 @@ trait AvatarsBase
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals(200, $response['headers']['status-code']);
|
$this->assertEquals(200, $response['headers']['status-code']);
|
||||||
$this->assertEquals('image/x-icon', $response['headers']['content-type']);
|
$this->assertEquals('image/svg+xml', $response['headers']['content-type']);
|
||||||
|
$this->assertNotEmpty($response['body']);
|
||||||
|
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/avatars/favicon', [
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
], [
|
||||||
|
'url' => 'https://appwrite.io/',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals(200, $response['headers']['status-code']);
|
||||||
|
$this->assertEquals('image/svg+xml', $response['headers']['content-type']);
|
||||||
$this->assertNotEmpty($response['body']);
|
$this->assertNotEmpty($response['body']);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue