mirror of
https://github.com/linuxserver/Heimdall.git
synced 2025-10-28 11:37:46 +09:00
Fix uploads and displaying of malicious SVG files
This commit is contained in:
3201
.phpstorm.meta.php
3201
.phpstorm.meta.php
File diff suppressed because it is too large
Load Diff
28474
_ide_helper.php
28474
_ide_helper.php
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use enshrined\svgSanitize\Sanitizer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $bytes
|
* @param $bytes
|
||||||
@@ -129,7 +130,11 @@ function isImage(string $file, string $extension): bool
|
|||||||
fwrite($handle, $file);
|
fwrite($handle, $file);
|
||||||
fclose($handle);
|
fclose($handle);
|
||||||
|
|
||||||
if ($extension == 'svg') {
|
if ($extension === 'svg') {
|
||||||
|
$sanitizer = new Sanitizer();
|
||||||
|
$sanitizedSvg = $sanitizer->sanitize(file_get_contents($tempFileName));
|
||||||
|
file_put_contents($tempFileName, $sanitizedSvg);
|
||||||
|
|
||||||
return 'image/svg+xml' === mime_content_type($tempFileName);
|
return 'image/svg+xml' === mime_content_type($tempFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ use Illuminate\Support\Facades\URL;
|
|||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\StreamInterface;
|
use Psr\Http\Message\StreamInterface;
|
||||||
|
use enshrined\svgSanitize\Sanitizer;
|
||||||
|
|
||||||
class ItemController extends Controller
|
class ItemController extends Controller
|
||||||
{
|
{
|
||||||
@@ -236,7 +237,23 @@ class ItemController extends Controller
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if ($request->hasFile('file')) {
|
if ($request->hasFile('file')) {
|
||||||
$path = $request->file('file')->store('icons', 'public');
|
$image = $request->file('file');
|
||||||
|
$extension = $image->getClientOriginalExtension();
|
||||||
|
|
||||||
|
if ($extension === 'svg') {
|
||||||
|
$sanitizer = new Sanitizer();
|
||||||
|
$sanitizedSvg = $sanitizer->sanitize(file_get_contents($image->getRealPath()));
|
||||||
|
|
||||||
|
// Verify that the sanitization removed malicious content
|
||||||
|
if (strpos($sanitizedSvg, '<script>') !== false) {
|
||||||
|
throw ValidationException::withMessages(['file' => 'SVG contains malicious content and cannot be uploaded.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the sanitized SVG back to the file
|
||||||
|
file_put_contents($image->getRealPath(), $sanitizedSvg);
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = $image->store('icons', 'public');
|
||||||
$request->merge([
|
$request->merge([
|
||||||
'icon' => $path,
|
'icon' => $path,
|
||||||
]);
|
]);
|
||||||
@@ -257,6 +274,16 @@ class ItemController extends Controller
|
|||||||
|
|
||||||
$contents = file_get_contents($request->input('icon'), false, stream_context_create($options));
|
$contents = file_get_contents($request->input('icon'), false, stream_context_create($options));
|
||||||
|
|
||||||
|
if ($extension === 'svg') {
|
||||||
|
$sanitizer = new Sanitizer();
|
||||||
|
$contents = $sanitizer->sanitize($contents);
|
||||||
|
|
||||||
|
// Verify that the sanitization removed malicious content
|
||||||
|
if (strpos($contents, '<script>') !== false) {
|
||||||
|
throw ValidationException::withMessages(['file' => 'SVG contains malicious content and cannot be uploaded.']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!isImage($contents, $extension)) {
|
if (!isImage($contents, $extension)) {
|
||||||
throw ValidationException::withMessages(['file' => 'Icon must be an image.']);
|
throw ValidationException::withMessages(['file' => 'Icon must be an image.']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
|
|||||||
use App\Setting;
|
use App\Setting;
|
||||||
use App\SettingGroup;
|
use App\SettingGroup;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use enshrined\svgSanitize\Sanitizer;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@@ -68,16 +69,30 @@ class SettingsController extends Controller
|
|||||||
|
|
||||||
if ($setting->type === 'image') {
|
if ($setting->type === 'image') {
|
||||||
$validatedData = $request->validate([
|
$validatedData = $request->validate([
|
||||||
'value' => 'image'
|
'value' => 'image',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!$request->hasFile('value')) {
|
if (!$request->hasFile('value')) {
|
||||||
throw new \Exception(
|
throw new \Exception('file_too_big');
|
||||||
'file_too_big'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$path = $request->file('value')->store('backgrounds', 'public');
|
$image = $request->file('value');
|
||||||
|
$extension = $image->getClientOriginalExtension();
|
||||||
|
|
||||||
|
if ($extension === 'svg') {
|
||||||
|
$sanitizer = new Sanitizer();
|
||||||
|
$sanitizedSvg = $sanitizer->sanitize(file_get_contents($image->getRealPath()));
|
||||||
|
|
||||||
|
// Verify that the sanitization removed malicious content
|
||||||
|
if (strpos($sanitizedSvg, '<script>') !== false) {
|
||||||
|
throw new \Exception('SVG contains malicious content and cannot be uploaded.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the sanitized SVG back to the file
|
||||||
|
file_put_contents($image->getRealPath(), $sanitizedSvg);
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = $image->store('backgrounds', 'public');
|
||||||
|
|
||||||
if ($path === null) {
|
if ($path === null) {
|
||||||
throw new \Exception('file_not_stored');
|
throw new \Exception('file_not_stored');
|
||||||
@@ -99,7 +114,7 @@ class SettingsController extends Controller
|
|||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
return redirect($route)
|
return redirect($route)
|
||||||
->with([
|
->with([
|
||||||
'errors' => collect([__('app.alert.error.'.$e->getMessage())]),
|
'errors' => collect([__('app.alert.error.' . $e->getMessage())]),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Session\SessionManager;
|
use Illuminate\Session\SessionManager;
|
||||||
use Illuminate\Session\Store;
|
use Illuminate\Session\Store;
|
||||||
|
use enshrined\svgSanitize\Sanitizer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* App\Setting
|
* App\Setting
|
||||||
@@ -70,9 +71,23 @@ class Setting extends Model
|
|||||||
|
|
||||||
public static function getInput(Request $request): object
|
public static function getInput(Request $request): object
|
||||||
{
|
{
|
||||||
|
$image = $request->file('value');
|
||||||
|
if ($image && $image->getClientOriginalExtension() === 'svg') {
|
||||||
|
$sanitizer = new Sanitizer();
|
||||||
|
$sanitizedSvg = $sanitizer->sanitize(file_get_contents($image->getRealPath()));
|
||||||
|
|
||||||
|
// Verify that the sanitization removed malicious content
|
||||||
|
if (strpos($sanitizedSvg, '<script>') !== false) {
|
||||||
|
throw new \Exception('SVG contains malicious content and cannot be uploaded.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the sanitized SVG back to the file
|
||||||
|
file_put_contents($image->getRealPath(), $sanitizedSvg);
|
||||||
|
}
|
||||||
|
|
||||||
return (object) [
|
return (object) [
|
||||||
'value' => $request->input('value'),
|
'value' => $request->input('value'),
|
||||||
'image' => $request->file('value'),
|
'image' => $image,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +207,7 @@ class Setting extends Model
|
|||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function group(): BelongsTo
|
public function group(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(\App\SettingGroup::class, 'group_id');
|
return $this->belongsTo(\App\SettingGroup::class, 'group_id');
|
||||||
|
|||||||
@@ -9,18 +9,19 @@
|
|||||||
"type": "project",
|
"type": "project",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
|
"ext-intl": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"enshrined/svg-sanitize": "^0.21.0",
|
||||||
"graham-campbell/github": "^12.5",
|
"graham-campbell/github": "^12.5",
|
||||||
"guzzlehttp/guzzle": "^7.8",
|
"guzzlehttp/guzzle": "^7.8",
|
||||||
"laravel/framework": "^11.45",
|
"laravel/framework": "^11.45",
|
||||||
"laravel/tinker": "^2.9",
|
"laravel/tinker": "^2.9",
|
||||||
"laravel/ui": "^4.4",
|
"laravel/ui": "^4.4",
|
||||||
"nunomaduro/collision": "^8.0",
|
|
||||||
"symfony/yaml": "^7.0",
|
|
||||||
"ext-json": "*",
|
|
||||||
"ext-intl": "*",
|
|
||||||
"league/flysystem-aws-s3-v3": "^3.0",
|
"league/flysystem-aws-s3-v3": "^3.0",
|
||||||
|
"nunomaduro/collision": "^8.0",
|
||||||
|
"spatie/laravel-html": "^3.11",
|
||||||
"spatie/laravel-ignition": "^2.4",
|
"spatie/laravel-ignition": "^2.4",
|
||||||
"spatie/laravel-html": "^3.11"
|
"symfony/yaml": "^7.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"barryvdh/laravel-ide-helper": "^3.0",
|
"barryvdh/laravel-ide-helper": "^3.0",
|
||||||
|
|||||||
51
composer.lock
generated
51
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": "5382a1b98508764ed864abf78b69684c",
|
"content-hash": "359cb52315ea7083764b22c6e1bd8a0c",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "aws/aws-crt-php",
|
"name": "aws/aws-crt-php",
|
||||||
@@ -727,6 +727,51 @@
|
|||||||
],
|
],
|
||||||
"time": "2025-03-06T22:45:56+00:00"
|
"time": "2025-03-06T22:45:56+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": "filp/whoops",
|
"name": "filp/whoops",
|
||||||
"version": "2.18.3",
|
"version": "2.18.3",
|
||||||
@@ -10288,8 +10333,8 @@
|
|||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
"ext-json": "*",
|
"ext-intl": "*",
|
||||||
"ext-intl": "*"
|
"ext-json": "*"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": [],
|
||||||
"plugin-api-version": "2.3.0"
|
"plugin-api-version": "2.3.0"
|
||||||
|
|||||||
24
tests/Feature/SVGSanitizerTest.php
Normal file
24
tests/Feature/SVGSanitizerTest.php
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
use Tests\TestCase;
|
||||||
|
use enshrined\svgSanitize\Sanitizer;
|
||||||
|
|
||||||
|
class SVGSanitizerTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testSvgSanitization()
|
||||||
|
{
|
||||||
|
$sanitizer = new Sanitizer();
|
||||||
|
$maliciousSvg = '<svg><script>alert("XSS")</script></svg>';
|
||||||
|
$sanitizedSvg = $sanitizer->sanitize($maliciousSvg);
|
||||||
|
|
||||||
|
$this->assertStringNotContainsString('<script>', $sanitizedSvg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidSvgSanitization()
|
||||||
|
{
|
||||||
|
$sanitizer = new Sanitizer();
|
||||||
|
$validSvg = '<svg><circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" /></svg>';
|
||||||
|
$sanitizedSvg = $sanitizer->sanitize($validSvg);
|
||||||
|
|
||||||
|
$this->assertStringContainsString('<circle', $sanitizedSvg);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
vendor/composer/autoload_classmap.php
vendored
15
vendor/composer/autoload_classmap.php
vendored
@@ -32,6 +32,7 @@ return array(
|
|||||||
'App\\Application' => $baseDir . '/app/Application.php',
|
'App\\Application' => $baseDir . '/app/Application.php',
|
||||||
'App\\Console\\Commands\\RegisterApp' => $baseDir . '/app/Console/Commands/RegisterApp.php',
|
'App\\Console\\Commands\\RegisterApp' => $baseDir . '/app/Console/Commands/RegisterApp.php',
|
||||||
'App\\EnhancedApps' => $baseDir . '/app/EnhancedApps.php',
|
'App\\EnhancedApps' => $baseDir . '/app/EnhancedApps.php',
|
||||||
|
'App\\Facades\\Form' => $baseDir . '/app/Facades/Form.php',
|
||||||
'App\\Http\\Controllers\\Auth\\ForgotPasswordController' => $baseDir . '/app/Http/Controllers/Auth/ForgotPasswordController.php',
|
'App\\Http\\Controllers\\Auth\\ForgotPasswordController' => $baseDir . '/app/Http/Controllers/Auth/ForgotPasswordController.php',
|
||||||
'App\\Http\\Controllers\\Auth\\LoginController' => $baseDir . '/app/Http/Controllers/Auth/LoginController.php',
|
'App\\Http\\Controllers\\Auth\\LoginController' => $baseDir . '/app/Http/Controllers/Auth/LoginController.php',
|
||||||
'App\\Http\\Controllers\\Auth\\RegisterController' => $baseDir . '/app/Http/Controllers/Auth/RegisterController.php',
|
'App\\Http\\Controllers\\Auth\\RegisterController' => $baseDir . '/app/Http/Controllers/Auth/RegisterController.php',
|
||||||
@@ -57,10 +58,13 @@ return array(
|
|||||||
'App\\Providers\\RouteServiceProvider' => $baseDir . '/app/Providers/RouteServiceProvider.php',
|
'App\\Providers\\RouteServiceProvider' => $baseDir . '/app/Providers/RouteServiceProvider.php',
|
||||||
'App\\Search' => $baseDir . '/app/Search.php',
|
'App\\Search' => $baseDir . '/app/Search.php',
|
||||||
'App\\SearchInterface' => $baseDir . '/app/SearchInterface.php',
|
'App\\SearchInterface' => $baseDir . '/app/SearchInterface.php',
|
||||||
|
'App\\Services\\CustomFormBuilder' => $baseDir . '/app/Services/CustomFormBuilder.php',
|
||||||
'App\\Setting' => $baseDir . '/app/Setting.php',
|
'App\\Setting' => $baseDir . '/app/Setting.php',
|
||||||
'App\\SettingGroup' => $baseDir . '/app/SettingGroup.php',
|
'App\\SettingGroup' => $baseDir . '/app/SettingGroup.php',
|
||||||
'App\\SettingUser' => $baseDir . '/app/SettingUser.php',
|
'App\\SettingUser' => $baseDir . '/app/SettingUser.php',
|
||||||
'App\\SupportedApps' => $baseDir . '/app/SupportedApps.php',
|
'App\\SupportedApps' => $baseDir . '/app/SupportedApps.php',
|
||||||
|
'App\\SupportedApps\\Nzbget\\Nzbget' => $baseDir . '/app/SupportedApps/Nzbget/Nzbget.php',
|
||||||
|
'App\\SupportedApps\\SABnzbd\\SABnzbd' => $baseDir . '/app/SupportedApps/SABnzbd/SABnzbd.php',
|
||||||
'App\\User' => $baseDir . '/app/User.php',
|
'App\\User' => $baseDir . '/app/User.php',
|
||||||
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
|
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
|
||||||
'Aws\\ACMPCA\\ACMPCAClient' => $vendorDir . '/aws/aws-sdk-php/src/ACMPCA/ACMPCAClient.php',
|
'Aws\\ACMPCA\\ACMPCAClient' => $vendorDir . '/aws/aws-sdk-php/src/ACMPCA/ACMPCAClient.php',
|
||||||
@@ -8103,6 +8107,17 @@ return array(
|
|||||||
'Whoops\\Util\\Misc' => $vendorDir . '/filp/whoops/src/Whoops/Util/Misc.php',
|
'Whoops\\Util\\Misc' => $vendorDir . '/filp/whoops/src/Whoops/Util/Misc.php',
|
||||||
'Whoops\\Util\\SystemFacade' => $vendorDir . '/filp/whoops/src/Whoops/Util/SystemFacade.php',
|
'Whoops\\Util\\SystemFacade' => $vendorDir . '/filp/whoops/src/Whoops/Util/SystemFacade.php',
|
||||||
'Whoops\\Util\\TemplateHelper' => $vendorDir . '/filp/whoops/src/Whoops/Util/TemplateHelper.php',
|
'Whoops\\Util\\TemplateHelper' => $vendorDir . '/filp/whoops/src/Whoops/Util/TemplateHelper.php',
|
||||||
|
'enshrined\\svgSanitize\\ElementReference\\Resolver' => $vendorDir . '/enshrined/svg-sanitize/src/ElementReference/Resolver.php',
|
||||||
|
'enshrined\\svgSanitize\\ElementReference\\Subject' => $vendorDir . '/enshrined/svg-sanitize/src/ElementReference/Subject.php',
|
||||||
|
'enshrined\\svgSanitize\\ElementReference\\Usage' => $vendorDir . '/enshrined/svg-sanitize/src/ElementReference/Usage.php',
|
||||||
|
'enshrined\\svgSanitize\\Exceptions\\NestingException' => $vendorDir . '/enshrined/svg-sanitize/src/Exceptions/NestingException.php',
|
||||||
|
'enshrined\\svgSanitize\\Helper' => $vendorDir . '/enshrined/svg-sanitize/src/Helper.php',
|
||||||
|
'enshrined\\svgSanitize\\Sanitizer' => $vendorDir . '/enshrined/svg-sanitize/src/Sanitizer.php',
|
||||||
|
'enshrined\\svgSanitize\\data\\AllowedAttributes' => $vendorDir . '/enshrined/svg-sanitize/src/data/AllowedAttributes.php',
|
||||||
|
'enshrined\\svgSanitize\\data\\AllowedTags' => $vendorDir . '/enshrined/svg-sanitize/src/data/AllowedTags.php',
|
||||||
|
'enshrined\\svgSanitize\\data\\AttributeInterface' => $vendorDir . '/enshrined/svg-sanitize/src/data/AttributeInterface.php',
|
||||||
|
'enshrined\\svgSanitize\\data\\TagInterface' => $vendorDir . '/enshrined/svg-sanitize/src/data/TagInterface.php',
|
||||||
|
'enshrined\\svgSanitize\\data\\XPath' => $vendorDir . '/enshrined/svg-sanitize/src/data/XPath.php',
|
||||||
'voku\\helper\\ASCII' => $vendorDir . '/voku/portable-ascii/src/voku/helper/ASCII.php',
|
'voku\\helper\\ASCII' => $vendorDir . '/voku/portable-ascii/src/voku/helper/ASCII.php',
|
||||||
'©' => $vendorDir . '/symfony/cache/Traits/ValueWrapper.php',
|
'©' => $vendorDir . '/symfony/cache/Traits/ValueWrapper.php',
|
||||||
);
|
);
|
||||||
|
|||||||
1
vendor/composer/autoload_psr4.php
vendored
1
vendor/composer/autoload_psr4.php
vendored
@@ -7,6 +7,7 @@ $baseDir = dirname($vendorDir);
|
|||||||
|
|
||||||
return array(
|
return array(
|
||||||
'voku\\' => array($vendorDir . '/voku/portable-ascii/src/voku'),
|
'voku\\' => array($vendorDir . '/voku/portable-ascii/src/voku'),
|
||||||
|
'enshrined\\svgSanitize\\' => array($vendorDir . '/enshrined/svg-sanitize/src'),
|
||||||
'Whoops\\' => array($vendorDir . '/filp/whoops/src/Whoops'),
|
'Whoops\\' => array($vendorDir . '/filp/whoops/src/Whoops'),
|
||||||
'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'),
|
'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'),
|
||||||
'TijsVerkoyen\\CssToInlineStyles\\' => array($vendorDir . '/tijsverkoyen/css-to-inline-styles/src'),
|
'TijsVerkoyen\\CssToInlineStyles\\' => array($vendorDir . '/tijsverkoyen/css-to-inline-styles/src'),
|
||||||
|
|||||||
23
vendor/composer/autoload_static.php
vendored
23
vendor/composer/autoload_static.php
vendored
@@ -54,6 +54,10 @@ class ComposerStaticInitb2555e5ff7197b9e020da74bbd3b7cfa
|
|||||||
array (
|
array (
|
||||||
'voku\\' => 5,
|
'voku\\' => 5,
|
||||||
),
|
),
|
||||||
|
'e' =>
|
||||||
|
array (
|
||||||
|
'enshrined\\svgSanitize\\' => 22,
|
||||||
|
),
|
||||||
'W' =>
|
'W' =>
|
||||||
array (
|
array (
|
||||||
'Whoops\\' => 7,
|
'Whoops\\' => 7,
|
||||||
@@ -227,6 +231,10 @@ class ComposerStaticInitb2555e5ff7197b9e020da74bbd3b7cfa
|
|||||||
array (
|
array (
|
||||||
0 => __DIR__ . '/..' . '/voku/portable-ascii/src/voku',
|
0 => __DIR__ . '/..' . '/voku/portable-ascii/src/voku',
|
||||||
),
|
),
|
||||||
|
'enshrined\\svgSanitize\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/enshrined/svg-sanitize/src',
|
||||||
|
),
|
||||||
'Whoops\\' =>
|
'Whoops\\' =>
|
||||||
array (
|
array (
|
||||||
0 => __DIR__ . '/..' . '/filp/whoops/src/Whoops',
|
0 => __DIR__ . '/..' . '/filp/whoops/src/Whoops',
|
||||||
@@ -720,6 +728,7 @@ class ComposerStaticInitb2555e5ff7197b9e020da74bbd3b7cfa
|
|||||||
'App\\Application' => __DIR__ . '/../..' . '/app/Application.php',
|
'App\\Application' => __DIR__ . '/../..' . '/app/Application.php',
|
||||||
'App\\Console\\Commands\\RegisterApp' => __DIR__ . '/../..' . '/app/Console/Commands/RegisterApp.php',
|
'App\\Console\\Commands\\RegisterApp' => __DIR__ . '/../..' . '/app/Console/Commands/RegisterApp.php',
|
||||||
'App\\EnhancedApps' => __DIR__ . '/../..' . '/app/EnhancedApps.php',
|
'App\\EnhancedApps' => __DIR__ . '/../..' . '/app/EnhancedApps.php',
|
||||||
|
'App\\Facades\\Form' => __DIR__ . '/../..' . '/app/Facades/Form.php',
|
||||||
'App\\Http\\Controllers\\Auth\\ForgotPasswordController' => __DIR__ . '/../..' . '/app/Http/Controllers/Auth/ForgotPasswordController.php',
|
'App\\Http\\Controllers\\Auth\\ForgotPasswordController' => __DIR__ . '/../..' . '/app/Http/Controllers/Auth/ForgotPasswordController.php',
|
||||||
'App\\Http\\Controllers\\Auth\\LoginController' => __DIR__ . '/../..' . '/app/Http/Controllers/Auth/LoginController.php',
|
'App\\Http\\Controllers\\Auth\\LoginController' => __DIR__ . '/../..' . '/app/Http/Controllers/Auth/LoginController.php',
|
||||||
'App\\Http\\Controllers\\Auth\\RegisterController' => __DIR__ . '/../..' . '/app/Http/Controllers/Auth/RegisterController.php',
|
'App\\Http\\Controllers\\Auth\\RegisterController' => __DIR__ . '/../..' . '/app/Http/Controllers/Auth/RegisterController.php',
|
||||||
@@ -745,10 +754,13 @@ class ComposerStaticInitb2555e5ff7197b9e020da74bbd3b7cfa
|
|||||||
'App\\Providers\\RouteServiceProvider' => __DIR__ . '/../..' . '/app/Providers/RouteServiceProvider.php',
|
'App\\Providers\\RouteServiceProvider' => __DIR__ . '/../..' . '/app/Providers/RouteServiceProvider.php',
|
||||||
'App\\Search' => __DIR__ . '/../..' . '/app/Search.php',
|
'App\\Search' => __DIR__ . '/../..' . '/app/Search.php',
|
||||||
'App\\SearchInterface' => __DIR__ . '/../..' . '/app/SearchInterface.php',
|
'App\\SearchInterface' => __DIR__ . '/../..' . '/app/SearchInterface.php',
|
||||||
|
'App\\Services\\CustomFormBuilder' => __DIR__ . '/../..' . '/app/Services/CustomFormBuilder.php',
|
||||||
'App\\Setting' => __DIR__ . '/../..' . '/app/Setting.php',
|
'App\\Setting' => __DIR__ . '/../..' . '/app/Setting.php',
|
||||||
'App\\SettingGroup' => __DIR__ . '/../..' . '/app/SettingGroup.php',
|
'App\\SettingGroup' => __DIR__ . '/../..' . '/app/SettingGroup.php',
|
||||||
'App\\SettingUser' => __DIR__ . '/../..' . '/app/SettingUser.php',
|
'App\\SettingUser' => __DIR__ . '/../..' . '/app/SettingUser.php',
|
||||||
'App\\SupportedApps' => __DIR__ . '/../..' . '/app/SupportedApps.php',
|
'App\\SupportedApps' => __DIR__ . '/../..' . '/app/SupportedApps.php',
|
||||||
|
'App\\SupportedApps\\Nzbget\\Nzbget' => __DIR__ . '/../..' . '/app/SupportedApps/Nzbget/Nzbget.php',
|
||||||
|
'App\\SupportedApps\\SABnzbd\\SABnzbd' => __DIR__ . '/../..' . '/app/SupportedApps/SABnzbd/SABnzbd.php',
|
||||||
'App\\User' => __DIR__ . '/../..' . '/app/User.php',
|
'App\\User' => __DIR__ . '/../..' . '/app/User.php',
|
||||||
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
|
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
|
||||||
'Aws\\ACMPCA\\ACMPCAClient' => __DIR__ . '/..' . '/aws/aws-sdk-php/src/ACMPCA/ACMPCAClient.php',
|
'Aws\\ACMPCA\\ACMPCAClient' => __DIR__ . '/..' . '/aws/aws-sdk-php/src/ACMPCA/ACMPCAClient.php',
|
||||||
@@ -8791,6 +8803,17 @@ class ComposerStaticInitb2555e5ff7197b9e020da74bbd3b7cfa
|
|||||||
'Whoops\\Util\\Misc' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Util/Misc.php',
|
'Whoops\\Util\\Misc' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Util/Misc.php',
|
||||||
'Whoops\\Util\\SystemFacade' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Util/SystemFacade.php',
|
'Whoops\\Util\\SystemFacade' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Util/SystemFacade.php',
|
||||||
'Whoops\\Util\\TemplateHelper' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Util/TemplateHelper.php',
|
'Whoops\\Util\\TemplateHelper' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Util/TemplateHelper.php',
|
||||||
|
'enshrined\\svgSanitize\\ElementReference\\Resolver' => __DIR__ . '/..' . '/enshrined/svg-sanitize/src/ElementReference/Resolver.php',
|
||||||
|
'enshrined\\svgSanitize\\ElementReference\\Subject' => __DIR__ . '/..' . '/enshrined/svg-sanitize/src/ElementReference/Subject.php',
|
||||||
|
'enshrined\\svgSanitize\\ElementReference\\Usage' => __DIR__ . '/..' . '/enshrined/svg-sanitize/src/ElementReference/Usage.php',
|
||||||
|
'enshrined\\svgSanitize\\Exceptions\\NestingException' => __DIR__ . '/..' . '/enshrined/svg-sanitize/src/Exceptions/NestingException.php',
|
||||||
|
'enshrined\\svgSanitize\\Helper' => __DIR__ . '/..' . '/enshrined/svg-sanitize/src/Helper.php',
|
||||||
|
'enshrined\\svgSanitize\\Sanitizer' => __DIR__ . '/..' . '/enshrined/svg-sanitize/src/Sanitizer.php',
|
||||||
|
'enshrined\\svgSanitize\\data\\AllowedAttributes' => __DIR__ . '/..' . '/enshrined/svg-sanitize/src/data/AllowedAttributes.php',
|
||||||
|
'enshrined\\svgSanitize\\data\\AllowedTags' => __DIR__ . '/..' . '/enshrined/svg-sanitize/src/data/AllowedTags.php',
|
||||||
|
'enshrined\\svgSanitize\\data\\AttributeInterface' => __DIR__ . '/..' . '/enshrined/svg-sanitize/src/data/AttributeInterface.php',
|
||||||
|
'enshrined\\svgSanitize\\data\\TagInterface' => __DIR__ . '/..' . '/enshrined/svg-sanitize/src/data/TagInterface.php',
|
||||||
|
'enshrined\\svgSanitize\\data\\XPath' => __DIR__ . '/..' . '/enshrined/svg-sanitize/src/data/XPath.php',
|
||||||
'voku\\helper\\ASCII' => __DIR__ . '/..' . '/voku/portable-ascii/src/voku/helper/ASCII.php',
|
'voku\\helper\\ASCII' => __DIR__ . '/..' . '/voku/portable-ascii/src/voku/helper/ASCII.php',
|
||||||
'©' => __DIR__ . '/..' . '/symfony/cache/Traits/ValueWrapper.php',
|
'©' => __DIR__ . '/..' . '/symfony/cache/Traits/ValueWrapper.php',
|
||||||
);
|
);
|
||||||
|
|||||||
48
vendor/composer/installed.json
vendored
48
vendor/composer/installed.json
vendored
@@ -1061,6 +1061,54 @@
|
|||||||
],
|
],
|
||||||
"install-path": "../egulias/email-validator"
|
"install-path": "../egulias/email-validator"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "enshrined/svg-sanitize",
|
||||||
|
"version": "0.21.0",
|
||||||
|
"version_normalized": "0.21.0.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"
|
||||||
|
},
|
||||||
|
"time": "2025-01-13T09:32:25+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"installation-source": "dist",
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"install-path": "../enshrined/svg-sanitize"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "fakerphp/faker",
|
"name": "fakerphp/faker",
|
||||||
"version": "v1.24.1",
|
"version": "v1.24.1",
|
||||||
|
|||||||
25
vendor/composer/installed.php
vendored
25
vendor/composer/installed.php
vendored
@@ -3,7 +3,7 @@
|
|||||||
'name' => 'laravel/laravel',
|
'name' => 'laravel/laravel',
|
||||||
'pretty_version' => '2.x-dev',
|
'pretty_version' => '2.x-dev',
|
||||||
'version' => '2.9999999.9999999.9999999-dev',
|
'version' => '2.9999999.9999999.9999999-dev',
|
||||||
'reference' => 'd972cbcd0aba44c298c54bfdf11739f3748cd16c',
|
'reference' => 'd1801d1088c2fc7174006c04808761e2b91389f7',
|
||||||
'type' => 'project',
|
'type' => 'project',
|
||||||
'install_path' => __DIR__ . '/../../',
|
'install_path' => __DIR__ . '/../../',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
@@ -148,6 +148,15 @@
|
|||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
|
'enshrined/svg-sanitize' => array(
|
||||||
|
'pretty_version' => '0.21.0',
|
||||||
|
'version' => '0.21.0.0',
|
||||||
|
'reference' => '5e477468fac5c5ce933dce53af3e8e4e58dcccc9',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../enshrined/svg-sanitize',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
'fakerphp/faker' => array(
|
'fakerphp/faker' => array(
|
||||||
'pretty_version' => 'v1.24.1',
|
'pretty_version' => 'v1.24.1',
|
||||||
'version' => '1.24.1.0',
|
'version' => '1.24.1.0',
|
||||||
@@ -487,7 +496,7 @@
|
|||||||
'laravel/laravel' => array(
|
'laravel/laravel' => array(
|
||||||
'pretty_version' => '2.x-dev',
|
'pretty_version' => '2.x-dev',
|
||||||
'version' => '2.9999999.9999999.9999999-dev',
|
'version' => '2.9999999.9999999.9999999-dev',
|
||||||
'reference' => 'd972cbcd0aba44c298c54bfdf11739f3748cd16c',
|
'reference' => 'd1801d1088c2fc7174006c04808761e2b91389f7',
|
||||||
'type' => 'project',
|
'type' => 'project',
|
||||||
'install_path' => __DIR__ . '/../../',
|
'install_path' => __DIR__ . '/../../',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
@@ -940,8 +949,8 @@
|
|||||||
'psr/http-client-implementation' => array(
|
'psr/http-client-implementation' => array(
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
'provided' => array(
|
'provided' => array(
|
||||||
0 => '*',
|
0 => '1.0',
|
||||||
1 => '1.0',
|
1 => '*',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'psr/http-factory' => array(
|
'psr/http-factory' => array(
|
||||||
@@ -956,8 +965,8 @@
|
|||||||
'psr/http-factory-implementation' => array(
|
'psr/http-factory-implementation' => array(
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
'provided' => array(
|
'provided' => array(
|
||||||
0 => '*',
|
0 => '1.0',
|
||||||
1 => '1.0',
|
1 => '*',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'psr/http-message' => array(
|
'psr/http-message' => array(
|
||||||
@@ -972,8 +981,8 @@
|
|||||||
'psr/http-message-implementation' => array(
|
'psr/http-message-implementation' => array(
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
'provided' => array(
|
'provided' => array(
|
||||||
0 => '*',
|
0 => '1.0',
|
||||||
1 => '1.0',
|
1 => '*',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'psr/log' => array(
|
'psr/log' => array(
|
||||||
|
|||||||
340
vendor/enshrined/svg-sanitize/LICENSE
vendored
Normal file
340
vendor/enshrined/svg-sanitize/LICENSE
vendored
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
{description}
|
||||||
|
Copyright (C) {year} {fullname}
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
{signature of Ty Coon}, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
||||||
|
|
||||||
93
vendor/enshrined/svg-sanitize/README.md
vendored
Normal file
93
vendor/enshrined/svg-sanitize/README.md
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# svg-sanitizer
|
||||||
|
|
||||||
|
[](https://travis-ci.org/darylldoyle/svg-sanitizer) [](https://codeclimate.com/github/darylldoyle/svg-sanitizer/coverage)
|
||||||
|
|
||||||
|
This is my attempt at building a decent SVG sanitizer in PHP. The work is largely borrowed from [DOMPurify](https://github.com/cure53/DOMPurify).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Either require `enshrined/svg-sanitize` through composer or download the repo and include the old way!
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Using this is fairly easy. Create a new instance of `enshrined\svgSanitize\Sanitizer` and then call the `sanitize` whilst passing in your dirty SVG/XML
|
||||||
|
|
||||||
|
**Basic Example**
|
||||||
|
|
||||||
|
```php
|
||||||
|
use enshrined\svgSanitize\Sanitizer;
|
||||||
|
|
||||||
|
// Create a new sanitizer instance
|
||||||
|
$sanitizer = new Sanitizer();
|
||||||
|
|
||||||
|
// Load the dirty svg
|
||||||
|
$dirtySVG = file_get_contents('filthy.svg');
|
||||||
|
|
||||||
|
// Pass it to the sanitizer and get it back clean
|
||||||
|
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
||||||
|
|
||||||
|
// Now do what you want with your clean SVG/XML data
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
This will either return a sanitized SVG/XML string or boolean `false` if XML parsing failed (usually due to a badly formatted file).
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
You may pass your own whitelist of tags and attributes by using the `Sanitizer::setAllowedTags` and `Sanitizer::setAllowedAttrs` methods respectively.
|
||||||
|
|
||||||
|
These methods require that you implement the `enshrined\svgSanitize\data\TagInterface` or `enshrined\svgSanitize\data\AttributeInterface`.
|
||||||
|
|
||||||
|
## Remove remote references
|
||||||
|
|
||||||
|
You have the option to remove attributes that reference remote files, this will stop HTTP leaks but will add an overhead to the sanitizer.
|
||||||
|
|
||||||
|
This defaults to false, set to true to remove references.
|
||||||
|
|
||||||
|
`$sanitizer->removeRemoteReferences(true);`
|
||||||
|
|
||||||
|
## Viewing Sanitization Issues
|
||||||
|
|
||||||
|
You may use the `getXmlIssues()` method to return an array of issues that occurred during sanitization.
|
||||||
|
|
||||||
|
This may be useful for logging or providing feedback to the user on why an SVG was refused.
|
||||||
|
|
||||||
|
`$issues = $sanitizer->getXmlIssues();`
|
||||||
|
|
||||||
|
## Minification
|
||||||
|
|
||||||
|
You can minify the XML output by calling `$sanitizer->minify(true);`.
|
||||||
|
|
||||||
|
## Demo
|
||||||
|
There is a demo available at: [http://svg.enshrined.co.uk/](http://svg.enshrined.co.uk/)
|
||||||
|
|
||||||
|
## WordPress
|
||||||
|
|
||||||
|
I've just released a WordPress plugin containing this code so you can sanitize your WordPress uploads. It's available from the WordPress plugin directory: [https://wordpress.org/plugins/safe-svg/](https://wordpress.org/plugins/safe-svg/)
|
||||||
|
|
||||||
|
## Drupal
|
||||||
|
|
||||||
|
[Michael Potter](https://github.com/heyMP) has kindly created a Drupal module for this library which is available at: [https://www.drupal.org/project/svg_sanitizer](https://www.drupal.org/project/svg_sanitizer)
|
||||||
|
|
||||||
|
## TYPO3
|
||||||
|
|
||||||
|
This SVG sanitizer library is used per default in the core of TYPO3 v9 and later versions.
|
||||||
|
See [corresponding changelog entry](https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/9.5.x/Important-94492-IntroduceSVGSanitizer.html) for more details.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
You can run these by running `vendor/bin/phpunit` from the base directory of this package.
|
||||||
|
|
||||||
|
## Standalone scanning of files via CLI
|
||||||
|
|
||||||
|
Thanks to the work by [gudmdharalds](https://github.com/gudmdharalds) there's now a standalone scanner that can be used via the CLI.
|
||||||
|
|
||||||
|
Any errors will be output in JSON format. See [the PR](https://github.com/darylldoyle/svg-sanitizer/pull/25) for an example.
|
||||||
|
|
||||||
|
Use it as follows: `php svg-scanner.php ~/svgs/myfile.svg`
|
||||||
|
|
||||||
|
## To-Do
|
||||||
|
|
||||||
|
More extensive testing for the SVGs/XML would be lovely, I'll try and add these soon. If you feel like doing it for me, please do and make a PR!
|
||||||
33
vendor/enshrined/svg-sanitize/composer.json
vendored
Normal file
33
vendor/enshrined/svg-sanitize/composer.json
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "enshrined/svg-sanitize",
|
||||||
|
"description": "An SVG sanitizer for PHP",
|
||||||
|
"license": "GPL-2.0-or-later",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Daryll Doyle",
|
||||||
|
"email": "daryll@enshrined.co.uk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"test": "phpunit --no-coverage",
|
||||||
|
"test:coverage": "phpunit"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"enshrined\\svgSanitize\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"enshrined\\svgSanitize\\Tests\\": "tests"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-libxml": "*",
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^6.5 || ^8.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
169
vendor/enshrined/svg-sanitize/src/ElementReference/Resolver.php
vendored
Normal file
169
vendor/enshrined/svg-sanitize/src/ElementReference/Resolver.php
vendored
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize\ElementReference;
|
||||||
|
|
||||||
|
use enshrined\svgSanitize\data\XPath;
|
||||||
|
use enshrined\svgSanitize\Exceptions\NestingException;
|
||||||
|
use enshrined\svgSanitize\Helper;
|
||||||
|
|
||||||
|
class Resolver
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var XPath
|
||||||
|
*/
|
||||||
|
protected $xPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Subject[]
|
||||||
|
*/
|
||||||
|
protected $subjects = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array DOMElement[]
|
||||||
|
*/
|
||||||
|
protected $elementsToRemove = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $useNestingLimit;
|
||||||
|
|
||||||
|
public function __construct(XPath $xPath, $useNestingLimit)
|
||||||
|
{
|
||||||
|
$this->xPath = $xPath;
|
||||||
|
$this->useNestingLimit = $useNestingLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function collect()
|
||||||
|
{
|
||||||
|
$this->collectIdentifiedElements();
|
||||||
|
$this->processReferences();
|
||||||
|
$this->determineInvalidSubjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves one subject by element.
|
||||||
|
*
|
||||||
|
* @param \DOMElement $element
|
||||||
|
* @param bool $considerChildren Whether to search in Subject's children as well
|
||||||
|
* @return Subject|null
|
||||||
|
*/
|
||||||
|
public function findByElement(\DOMElement $element, $considerChildren = false)
|
||||||
|
{
|
||||||
|
foreach ($this->subjects as $subject) {
|
||||||
|
if (
|
||||||
|
$element === $subject->getElement()
|
||||||
|
|| $considerChildren && Helper::isElementContainedIn($element, $subject->getElement())
|
||||||
|
) {
|
||||||
|
return $subject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves subjects (plural!) by element id - in theory malformed
|
||||||
|
* DOM might have same ids assigned to different elements and leaving
|
||||||
|
* it to client/browser implementation which element to actually use.
|
||||||
|
*
|
||||||
|
* @param string $elementId
|
||||||
|
* @return Subject[]
|
||||||
|
*/
|
||||||
|
public function findByElementId($elementId)
|
||||||
|
{
|
||||||
|
return array_filter(
|
||||||
|
$this->subjects,
|
||||||
|
function (Subject $subject) use ($elementId) {
|
||||||
|
return $elementId === $subject->getElementId();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects elements having `id` attribute (those that can be referenced).
|
||||||
|
*/
|
||||||
|
protected function collectIdentifiedElements()
|
||||||
|
{
|
||||||
|
/** @var \DOMNodeList|\DOMElement[] $elements */
|
||||||
|
$elements = $this->xPath->query('//*[@id]');
|
||||||
|
foreach ($elements as $element) {
|
||||||
|
$this->subjects[$element->getAttribute('id')] = new Subject($element, $this->useNestingLimit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes references from and to elements having `id` attribute concerning
|
||||||
|
* their occurrence in `<use ... xlink:href="#identifier">` statements.
|
||||||
|
*/
|
||||||
|
protected function processReferences()
|
||||||
|
{
|
||||||
|
$useNodeName = $this->xPath->createNodeName('use');
|
||||||
|
foreach ($this->subjects as $subject) {
|
||||||
|
$useElements = $this->xPath->query(
|
||||||
|
$useNodeName . '[@href or @xlink:href]',
|
||||||
|
$subject->getElement()
|
||||||
|
);
|
||||||
|
|
||||||
|
/** @var \DOMElement $useElement */
|
||||||
|
foreach ($useElements as $useElement) {
|
||||||
|
$useId = Helper::extractIdReferenceFromHref(
|
||||||
|
Helper::getElementHref($useElement)
|
||||||
|
);
|
||||||
|
if ($useId === null || !isset($this->subjects[$useId])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$subject->addUse($this->subjects[$useId]);
|
||||||
|
$this->subjects[$useId]->addUsedIn($subject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines and tags infinite loops.
|
||||||
|
*/
|
||||||
|
protected function determineInvalidSubjects()
|
||||||
|
{
|
||||||
|
foreach ($this->subjects as $subject) {
|
||||||
|
|
||||||
|
if (in_array($subject->getElement(), $this->elementsToRemove)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$useId = Helper::extractIdReferenceFromHref(
|
||||||
|
Helper::getElementHref($subject->getElement())
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($useId === $subject->getElementId()) {
|
||||||
|
$this->markSubjectAsInvalid($subject);
|
||||||
|
} elseif ($subject->hasInfiniteLoop()) {
|
||||||
|
$this->markSubjectAsInvalid($subject);
|
||||||
|
}
|
||||||
|
} catch (NestingException $e) {
|
||||||
|
$this->elementsToRemove[] = $e->getElement();
|
||||||
|
$this->markSubjectAsInvalid($subject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the elements that caused a nesting exception.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getElementsToRemove() {
|
||||||
|
return $this->elementsToRemove;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Subject is invalid for some reason, therefore we should
|
||||||
|
* remove it and all it's child usages.
|
||||||
|
*
|
||||||
|
* @param Subject $subject
|
||||||
|
*/
|
||||||
|
protected function markSubjectAsInvalid(Subject $subject) {
|
||||||
|
$this->elementsToRemove = array_merge(
|
||||||
|
$this->elementsToRemove,
|
||||||
|
$subject->clearInternalAndGetAffectedElements()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
153
vendor/enshrined/svg-sanitize/src/ElementReference/Subject.php
vendored
Normal file
153
vendor/enshrined/svg-sanitize/src/ElementReference/Subject.php
vendored
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize\ElementReference;
|
||||||
|
|
||||||
|
class Subject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \DOMElement
|
||||||
|
*/
|
||||||
|
protected $element;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Usage[]
|
||||||
|
*/
|
||||||
|
protected $useCollection = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Usage[]
|
||||||
|
*/
|
||||||
|
protected $usedInCollection = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $useNestingLimit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subject constructor.
|
||||||
|
*
|
||||||
|
* @param \DOMElement $element
|
||||||
|
* @param int $useNestingLimit
|
||||||
|
*/
|
||||||
|
public function __construct(\DOMElement $element, $useNestingLimit)
|
||||||
|
{
|
||||||
|
$this->element = $element;
|
||||||
|
$this->useNestingLimit = $useNestingLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \DOMElement
|
||||||
|
*/
|
||||||
|
public function getElement()
|
||||||
|
{
|
||||||
|
return $this->element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getElementId()
|
||||||
|
{
|
||||||
|
return $this->element->getAttribute('id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $subjects Previously processed subjects
|
||||||
|
* @param int $level The current level of nesting.
|
||||||
|
* @return bool
|
||||||
|
* @throws \enshrined\svgSanitize\Exceptions\NestingException
|
||||||
|
*/
|
||||||
|
public function hasInfiniteLoop(array $subjects = [], $level = 1)
|
||||||
|
{
|
||||||
|
if ($level > $this->useNestingLimit) {
|
||||||
|
throw new \enshrined\svgSanitize\Exceptions\NestingException('Nesting level too high, aborting', 1570713498, null, $this->getElement());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($this, $subjects, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$subjects[] = $this;
|
||||||
|
foreach ($this->useCollection as $usage) {
|
||||||
|
if ($usage->getSubject()->hasInfiniteLoop($subjects, $level + 1)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Subject $subject
|
||||||
|
*/
|
||||||
|
public function addUse(Subject $subject)
|
||||||
|
{
|
||||||
|
if ($subject === $this) {
|
||||||
|
throw new \LogicException('Cannot add self usage', 1570713416);
|
||||||
|
}
|
||||||
|
$identifier = $subject->getElementId();
|
||||||
|
if (isset($this->useCollection[$identifier])) {
|
||||||
|
$this->useCollection[$identifier]->increment();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->useCollection[$identifier] = new Usage($subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Subject $subject
|
||||||
|
*/
|
||||||
|
public function addUsedIn(Subject $subject)
|
||||||
|
{
|
||||||
|
if ($subject === $this) {
|
||||||
|
throw new \LogicException('Cannot add self as usage', 1570713417);
|
||||||
|
}
|
||||||
|
$identifier = $subject->getElementId();
|
||||||
|
if (isset($this->usedInCollection[$identifier])) {
|
||||||
|
$this->usedInCollection[$identifier]->increment();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->usedInCollection[$identifier] = new Usage($subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $accumulated
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function countUse($accumulated = false)
|
||||||
|
{
|
||||||
|
$count = 0;
|
||||||
|
foreach ($this->useCollection as $use) {
|
||||||
|
$useCount = $use->getSubject()->countUse();
|
||||||
|
$count += $use->getCount() * ($accumulated ? 1 + $useCount : max(1, $useCount));
|
||||||
|
}
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function countUsedIn()
|
||||||
|
{
|
||||||
|
$count = 0;
|
||||||
|
foreach ($this->usedInCollection as $usedIn) {
|
||||||
|
$count += $usedIn->getCount() * max(1, $usedIn->getSubject()->countUsedIn());
|
||||||
|
}
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the internal arrays (to free up memory as they can get big)
|
||||||
|
* and return all the child usages DOMElement's
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function clearInternalAndGetAffectedElements()
|
||||||
|
{
|
||||||
|
$elements = array_map(function(Usage $usage) {
|
||||||
|
return $usage->getSubject()->getElement();
|
||||||
|
}, $this->useCollection);
|
||||||
|
|
||||||
|
$this->usedInCollection = [];
|
||||||
|
$this->useCollection = [];
|
||||||
|
|
||||||
|
return $elements;
|
||||||
|
}
|
||||||
|
}
|
||||||
49
vendor/enshrined/svg-sanitize/src/ElementReference/Usage.php
vendored
Normal file
49
vendor/enshrined/svg-sanitize/src/ElementReference/Usage.php
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize\ElementReference;
|
||||||
|
|
||||||
|
class Usage
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Subject
|
||||||
|
*/
|
||||||
|
protected $subject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Subject $subject
|
||||||
|
* @param int $count
|
||||||
|
*/
|
||||||
|
public function __construct(Subject $subject, $count = 1)
|
||||||
|
{
|
||||||
|
$this->subject = $subject;
|
||||||
|
$this->count = (int)$count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $by
|
||||||
|
*/
|
||||||
|
public function increment($by = 1)
|
||||||
|
{
|
||||||
|
$this->count += (int)$by;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Subject
|
||||||
|
*/
|
||||||
|
public function getSubject()
|
||||||
|
{
|
||||||
|
return $this->subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getCount()
|
||||||
|
{
|
||||||
|
return $this->count;
|
||||||
|
}
|
||||||
|
}
|
||||||
36
vendor/enshrined/svg-sanitize/src/Exceptions/NestingException.php
vendored
Normal file
36
vendor/enshrined/svg-sanitize/src/Exceptions/NestingException.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class NestingException extends \Exception
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \DOMElement
|
||||||
|
*/
|
||||||
|
protected $element;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NestingException constructor.
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @param int $code
|
||||||
|
* @param Exception|null $previous
|
||||||
|
* @param \DOMElement|null $element
|
||||||
|
*/
|
||||||
|
public function __construct($message = "", $code = 0, ?Exception $previous = null, ?\DOMElement $element = null)
|
||||||
|
{
|
||||||
|
$this->element = $element;
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the element that caused the exception.
|
||||||
|
*
|
||||||
|
* @return \DOMElement
|
||||||
|
*/
|
||||||
|
public function getElement()
|
||||||
|
{
|
||||||
|
return $this->element;
|
||||||
|
}
|
||||||
|
}
|
||||||
53
vendor/enshrined/svg-sanitize/src/Helper.php
vendored
Normal file
53
vendor/enshrined/svg-sanitize/src/Helper.php
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize;
|
||||||
|
|
||||||
|
class Helper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param \DOMElement $element
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public static function getElementHref(\DOMElement $element)
|
||||||
|
{
|
||||||
|
if ($element->hasAttribute('href')) {
|
||||||
|
return $element->getAttribute('href');
|
||||||
|
}
|
||||||
|
if ($element->hasAttributeNS('http://www.w3.org/1999/xlink', 'href')) {
|
||||||
|
return $element->getAttributeNS('http://www.w3.org/1999/xlink', 'href');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $href
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public static function extractIdReferenceFromHref($href)
|
||||||
|
{
|
||||||
|
if (!is_string($href) || strpos($href, '#') !== 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return substr($href, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \DOMElement $needle
|
||||||
|
* @param \DOMElement $haystack
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isElementContainedIn(\DOMElement $needle, \DOMElement $haystack)
|
||||||
|
{
|
||||||
|
if ($needle === $haystack) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
foreach ($haystack->childNodes as $childNode) {
|
||||||
|
if (!$childNode instanceof \DOMElement) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (self::isElementContainedIn($needle, $childNode)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
724
vendor/enshrined/svg-sanitize/src/Sanitizer.php
vendored
Normal file
724
vendor/enshrined/svg-sanitize/src/Sanitizer.php
vendored
Normal file
@@ -0,0 +1,724 @@
|
|||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize;
|
||||||
|
|
||||||
|
use enshrined\svgSanitize\data\AllowedAttributes;
|
||||||
|
use enshrined\svgSanitize\data\AllowedTags;
|
||||||
|
use enshrined\svgSanitize\data\AttributeInterface;
|
||||||
|
use enshrined\svgSanitize\data\TagInterface;
|
||||||
|
use enshrined\svgSanitize\data\XPath;
|
||||||
|
use enshrined\svgSanitize\ElementReference\Resolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Sanitizer
|
||||||
|
*
|
||||||
|
* @package enshrined\svgSanitize
|
||||||
|
*/
|
||||||
|
class Sanitizer
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \DOMDocument
|
||||||
|
*/
|
||||||
|
protected $xmlDocument;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $allowedTags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $allowedAttrs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
protected $xmlLoaderValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $xmlErrorHandlerPreviousValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $minifyXML = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $removeRemoteReferences = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $useThreshold = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $removeXMLTag = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $xmlOptions = LIBXML_NOEMPTYTAG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $xmlIssues = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Resolver
|
||||||
|
*/
|
||||||
|
protected $elementReferenceResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $useNestingLimit = 15;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $allowHugeFiles = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
// Load default tags/attributes
|
||||||
|
$this->allowedAttrs = array_map('strtolower', AllowedAttributes::getAttributes());
|
||||||
|
$this->allowedTags = array_map('strtolower', AllowedTags::getTags());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the DOMDocument
|
||||||
|
*/
|
||||||
|
protected function resetInternal()
|
||||||
|
{
|
||||||
|
$this->xmlDocument = new \DOMDocument();
|
||||||
|
$this->xmlDocument->preserveWhiteSpace = false;
|
||||||
|
$this->xmlDocument->strictErrorChecking = false;
|
||||||
|
$this->xmlDocument->formatOutput = !$this->minifyXML;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set XML options to use when saving XML
|
||||||
|
* See: DOMDocument::saveXML
|
||||||
|
*
|
||||||
|
* @param int $xmlOptions
|
||||||
|
*/
|
||||||
|
public function setXMLOptions($xmlOptions)
|
||||||
|
{
|
||||||
|
$this->xmlOptions = $xmlOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get XML options to use when saving XML
|
||||||
|
* See: DOMDocument::saveXML
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getXMLOptions()
|
||||||
|
{
|
||||||
|
return $this->xmlOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the array of allowed tags
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAllowedTags()
|
||||||
|
{
|
||||||
|
return $this->allowedTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set custom allowed tags
|
||||||
|
*
|
||||||
|
* @param TagInterface $allowedTags
|
||||||
|
*/
|
||||||
|
public function setAllowedTags(TagInterface $allowedTags)
|
||||||
|
{
|
||||||
|
$this->allowedTags = array_map('strtolower', $allowedTags::getTags());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the array of allowed attributes
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAllowedAttrs()
|
||||||
|
{
|
||||||
|
return $this->allowedAttrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set custom allowed attributes
|
||||||
|
*
|
||||||
|
* @param AttributeInterface $allowedAttrs
|
||||||
|
*/
|
||||||
|
public function setAllowedAttrs(AttributeInterface $allowedAttrs)
|
||||||
|
{
|
||||||
|
$this->allowedAttrs = array_map('strtolower', $allowedAttrs::getAttributes());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should we remove references to remote files?
|
||||||
|
*
|
||||||
|
* @param bool $removeRemoteRefs
|
||||||
|
*/
|
||||||
|
public function removeRemoteReferences($removeRemoteRefs = false)
|
||||||
|
{
|
||||||
|
$this->removeRemoteReferences = $removeRemoteRefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get XML issues.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getXmlIssues() {
|
||||||
|
return $this->xmlIssues;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can we allow huge files?
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getAllowHugeFiles() {
|
||||||
|
return $this->allowHugeFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether we can allow huge files.
|
||||||
|
*
|
||||||
|
* @param bool $allowHugeFiles
|
||||||
|
*/
|
||||||
|
public function setAllowHugeFiles( $allowHugeFiles ) {
|
||||||
|
$this->allowHugeFiles = $allowHugeFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitize the passed string
|
||||||
|
*
|
||||||
|
* @param string $dirty
|
||||||
|
* @return string|false
|
||||||
|
*/
|
||||||
|
public function sanitize($dirty)
|
||||||
|
{
|
||||||
|
// Don't run on an empty string
|
||||||
|
if (empty($dirty)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
/*
|
||||||
|
* recursively remove php tags because they can be hidden inside tags
|
||||||
|
* i.e. <?p<?php test?>hp echo . ' danger! ';?>
|
||||||
|
*/
|
||||||
|
$dirty = preg_replace('/<\?(=|php)(.+?)\?>/i', '', $dirty);
|
||||||
|
} while (preg_match('/<\?(=|php)(.+?)\?>/i', $dirty) != 0);
|
||||||
|
|
||||||
|
$this->resetInternal();
|
||||||
|
$this->setUpBefore();
|
||||||
|
|
||||||
|
$loaded = $this->xmlDocument->loadXML($dirty, $this->getAllowHugeFiles() ? LIBXML_PARSEHUGE : 0);
|
||||||
|
|
||||||
|
// If we couldn't parse the XML then we go no further. Reset and return false
|
||||||
|
if (!$loaded) {
|
||||||
|
$this->xmlIssues = self::getXmlErrors();
|
||||||
|
$this->resetAfter();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-process all identified elements
|
||||||
|
$xPath = new XPath($this->xmlDocument);
|
||||||
|
$this->elementReferenceResolver = new Resolver($xPath, $this->useNestingLimit);
|
||||||
|
$this->elementReferenceResolver->collect();
|
||||||
|
$elementsToRemove = $this->elementReferenceResolver->getElementsToRemove();
|
||||||
|
|
||||||
|
// Start the cleaning process
|
||||||
|
$this->startClean($this->xmlDocument->childNodes, $elementsToRemove);
|
||||||
|
|
||||||
|
// Save cleaned XML to a variable
|
||||||
|
if ($this->removeXMLTag) {
|
||||||
|
$clean = $this->xmlDocument->saveXML($this->xmlDocument->documentElement, $this->xmlOptions);
|
||||||
|
} else {
|
||||||
|
$clean = $this->xmlDocument->saveXML($this->xmlDocument, $this->xmlOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->resetAfter();
|
||||||
|
|
||||||
|
// Remove any extra whitespaces when minifying
|
||||||
|
if ($this->minifyXML) {
|
||||||
|
$clean = preg_replace('/\s+/', ' ', $clean);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return result
|
||||||
|
return $clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up libXML before we start
|
||||||
|
*/
|
||||||
|
protected function setUpBefore()
|
||||||
|
{
|
||||||
|
// This function has been deprecated in PHP 8.0 because in libxml 2.9.0, external entity loading is
|
||||||
|
// disabled by default, so this function is no longer needed to protect against XXE attacks.
|
||||||
|
if (\LIBXML_VERSION < 20900) {
|
||||||
|
// Turn off the entity loader
|
||||||
|
$this->xmlLoaderValue = libxml_disable_entity_loader(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Suppress the errors because we don't really have to worry about formation before cleansing.
|
||||||
|
// See reset in resetAfter().
|
||||||
|
$this->xmlErrorHandlerPreviousValue = libxml_use_internal_errors(true);
|
||||||
|
|
||||||
|
// Reset array of altered XML
|
||||||
|
$this->xmlIssues = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the class after use
|
||||||
|
*/
|
||||||
|
protected function resetAfter()
|
||||||
|
{
|
||||||
|
// This function has been deprecated in PHP 8.0 because in libxml 2.9.0, external entity loading is
|
||||||
|
// disabled by default, so this function is no longer needed to protect against XXE attacks.
|
||||||
|
if (\LIBXML_VERSION < 20900) {
|
||||||
|
// Reset the entity loader
|
||||||
|
libxml_disable_entity_loader($this->xmlLoaderValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
libxml_clear_errors();
|
||||||
|
libxml_use_internal_errors($this->xmlErrorHandlerPreviousValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the cleaning with tags, then we move onto attributes and hrefs later
|
||||||
|
*
|
||||||
|
* @param \DOMNodeList $elements
|
||||||
|
* @param array $elementsToRemove
|
||||||
|
*/
|
||||||
|
protected function startClean(\DOMNodeList $elements, array $elementsToRemove)
|
||||||
|
{
|
||||||
|
// loop through all elements
|
||||||
|
// we do this backwards so we don't skip anything if we delete a node
|
||||||
|
// see comments at: http://php.net/manual/en/class.domnamednodemap.php
|
||||||
|
for ($i = $elements->length - 1; $i >= 0; $i--) {
|
||||||
|
/** @var \DOMElement $currentElement */
|
||||||
|
$currentElement = $elements->item($i);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the element has exceeded the nesting limit, we should remove it.
|
||||||
|
*
|
||||||
|
* As it's only <use> elements that cause us issues with nesting DOS attacks
|
||||||
|
* we should check what the element is before removing it. For now we'll only
|
||||||
|
* remove <use> elements.
|
||||||
|
*/
|
||||||
|
if (in_array($currentElement, $elementsToRemove) && 'use' === $currentElement->nodeName) {
|
||||||
|
$currentElement->parentNode->removeChild($currentElement);
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Invalid \'' . $currentElement->tagName . '\'',
|
||||||
|
'line' => $currentElement->getLineNo(),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($currentElement instanceof \DOMElement) {
|
||||||
|
// If the tag isn't in the whitelist, remove it and continue with next iteration
|
||||||
|
if (!in_array(strtolower($currentElement->tagName), $this->allowedTags)) {
|
||||||
|
$currentElement->parentNode->removeChild($currentElement);
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious tag \'' . $currentElement->tagName . '\'',
|
||||||
|
'line' => $currentElement->getLineNo(),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cleanHrefs( $currentElement );
|
||||||
|
|
||||||
|
$this->cleanXlinkHrefs( $currentElement );
|
||||||
|
|
||||||
|
$this->cleanAttributesOnWhitelist($currentElement);
|
||||||
|
|
||||||
|
if (strtolower($currentElement->tagName) === 'use') {
|
||||||
|
if ($this->isUseTagDirty($currentElement)
|
||||||
|
|| $this->isUseTagExceedingThreshold($currentElement)
|
||||||
|
) {
|
||||||
|
$currentElement->parentNode->removeChild($currentElement);
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious \'' . $currentElement->tagName . '\'',
|
||||||
|
'line' => $currentElement->getLineNo(),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip out font elements that will break out of foreign content.
|
||||||
|
if (strtolower($currentElement->tagName) === 'font') {
|
||||||
|
$breaksOutOfForeignContent = false;
|
||||||
|
for ($x = $currentElement->attributes->length - 1; $x >= 0; $x--) {
|
||||||
|
// get attribute name
|
||||||
|
$attrName = $currentElement->attributes->item( $x )->nodeName;
|
||||||
|
|
||||||
|
if (in_array(strtolower($attrName), ['face', 'color', 'size'])) {
|
||||||
|
$breaksOutOfForeignContent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($breaksOutOfForeignContent) {
|
||||||
|
$currentElement->parentNode->removeChild($currentElement);
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious tag \'' . $currentElement->tagName . '\'',
|
||||||
|
'line' => $currentElement->getLineNo(),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cleanUnsafeNodes($currentElement);
|
||||||
|
|
||||||
|
if ($currentElement->hasChildNodes()) {
|
||||||
|
$this->startClean($currentElement->childNodes, $elementsToRemove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only allow attributes that are on the whitelist
|
||||||
|
*
|
||||||
|
* @param \DOMElement $element
|
||||||
|
*/
|
||||||
|
protected function cleanAttributesOnWhitelist(\DOMElement $element)
|
||||||
|
{
|
||||||
|
for ($x = $element->attributes->length - 1; $x >= 0; $x--) {
|
||||||
|
// get attribute name
|
||||||
|
$attrName = $element->attributes->item($x)->nodeName;
|
||||||
|
|
||||||
|
// Remove attribute if not in whitelist
|
||||||
|
if (!in_array(strtolower($attrName), $this->allowedAttrs) && !$this->isAriaAttribute(strtolower($attrName)) && !$this->isDataAttribute(strtolower($attrName))) {
|
||||||
|
|
||||||
|
$element->removeAttribute($attrName);
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious attribute \'' . $attrName . '\'',
|
||||||
|
'line' => $element->getLineNo(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is used for when a namespace isn't imported properly.
|
||||||
|
* Such as xlink:href when the xlink namespace isn't imported.
|
||||||
|
* We have to do this as the link is still ran in this case.
|
||||||
|
*/
|
||||||
|
if (false !== strpos($attrName, 'href')) {
|
||||||
|
$href = $element->getAttribute($attrName);
|
||||||
|
if (false === $this->isHrefSafeValue($href)) {
|
||||||
|
$element->removeAttribute($attrName);
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious attribute \'href\'',
|
||||||
|
'line' => $element->getLineNo(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do we want to strip remote references?
|
||||||
|
if($this->removeRemoteReferences) {
|
||||||
|
// Remove attribute if it has a remote reference
|
||||||
|
if (isset($element->attributes->item($x)->value) && $this->hasRemoteReference($element->attributes->item($x)->value)) {
|
||||||
|
$element->removeAttribute($attrName);
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious attribute \'' . $attrName . '\'',
|
||||||
|
'line' => $element->getLineNo(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean the xlink:hrefs of script and data embeds
|
||||||
|
*
|
||||||
|
* @param \DOMElement $element
|
||||||
|
*/
|
||||||
|
protected function cleanXlinkHrefs(\DOMElement $element)
|
||||||
|
{
|
||||||
|
$xlinks = $element->getAttributeNS('http://www.w3.org/1999/xlink', 'href');
|
||||||
|
if (false === $this->isHrefSafeValue($xlinks)) {
|
||||||
|
$element->removeAttributeNS( 'http://www.w3.org/1999/xlink', 'href' );
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious attribute \'href\'',
|
||||||
|
'line' => $element->getLineNo(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean the hrefs of script and data embeds
|
||||||
|
*
|
||||||
|
* @param \DOMElement $element
|
||||||
|
*/
|
||||||
|
protected function cleanHrefs(\DOMElement $element)
|
||||||
|
{
|
||||||
|
$href = $element->getAttribute('href');
|
||||||
|
if (false === $this->isHrefSafeValue($href)) {
|
||||||
|
$element->removeAttribute('href');
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious attribute \'href\'',
|
||||||
|
'line' => $element->getLineNo(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only allow whitelisted starts to be within the href.
|
||||||
|
*
|
||||||
|
* This will stop scripts etc from being passed through, with or without attempting to hide bypasses.
|
||||||
|
* This stops the need for us to use a complicated script regex.
|
||||||
|
*
|
||||||
|
* @param $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isHrefSafeValue($value) {
|
||||||
|
|
||||||
|
// Allow empty values
|
||||||
|
if (empty($value)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow fragment identifiers.
|
||||||
|
if ('#' === substr($value, 0, 1)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow relative URIs.
|
||||||
|
if ('/' === substr($value, 0, 1)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow HTTPS domains.
|
||||||
|
if ('https://' === substr($value, 0, 8)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow HTTP domains.
|
||||||
|
if ('http://' === substr($value, 0, 7)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow known data URIs.
|
||||||
|
if (in_array(substr($value, 0, 14), array(
|
||||||
|
'data:image/png', // PNG
|
||||||
|
'data:image/gif', // GIF
|
||||||
|
'data:image/jpg', // JPG
|
||||||
|
'data:image/jpe', // JPEG
|
||||||
|
'data:image/pjp', // PJPEG
|
||||||
|
))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow known short data URIs.
|
||||||
|
if (in_array(substr($value, 0, 12), array(
|
||||||
|
'data:img/png', // PNG
|
||||||
|
'data:img/gif', // GIF
|
||||||
|
'data:img/jpg', // JPG
|
||||||
|
'data:img/jpe', // JPEG
|
||||||
|
'data:img/pjp', // PJPEG
|
||||||
|
))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes non-printable ASCII characters from string & trims it
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function removeNonPrintableCharacters($value)
|
||||||
|
{
|
||||||
|
return trim(preg_replace('/[^ -~]/xu','',$value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this attribute value have a remote reference?
|
||||||
|
*
|
||||||
|
* @param $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function hasRemoteReference($value)
|
||||||
|
{
|
||||||
|
$value = $this->removeNonPrintableCharacters($value);
|
||||||
|
|
||||||
|
$wrapped_in_url = preg_match('~^url\(\s*[\'"]\s*(.*)\s*[\'"]\s*\)$~xi', $value, $match);
|
||||||
|
if (!$wrapped_in_url){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = trim($match[1], '\'"');
|
||||||
|
|
||||||
|
return preg_match('~^((https?|ftp|file):)?//~xi', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should we minify the output?
|
||||||
|
*
|
||||||
|
* @param bool $shouldMinify
|
||||||
|
*/
|
||||||
|
public function minify($shouldMinify = false)
|
||||||
|
{
|
||||||
|
$this->minifyXML = (bool) $shouldMinify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should we remove the XML tag in the header?
|
||||||
|
*
|
||||||
|
* @param bool $removeXMLTag
|
||||||
|
*/
|
||||||
|
public function removeXMLTag($removeXMLTag = false)
|
||||||
|
{
|
||||||
|
$this->removeXMLTag = (bool) $removeXMLTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether `<use ... xlink:href="#identifier">` elements shall be
|
||||||
|
* removed in case expansion would exceed this threshold.
|
||||||
|
*
|
||||||
|
* @param int $useThreshold
|
||||||
|
*/
|
||||||
|
public function useThreshold($useThreshold = 1000)
|
||||||
|
{
|
||||||
|
$this->useThreshold = (int)$useThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if an attribute is an aria attribute or not
|
||||||
|
*
|
||||||
|
* @param $attributeName
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isAriaAttribute($attributeName)
|
||||||
|
{
|
||||||
|
return strpos($attributeName, 'aria-') === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if an attribute is an data attribute or not
|
||||||
|
*
|
||||||
|
* @param $attributeName
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isDataAttribute($attributeName)
|
||||||
|
{
|
||||||
|
return strpos($attributeName, 'data-') === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure our use tag is only referencing internal resources
|
||||||
|
*
|
||||||
|
* @param \DOMElement $element
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isUseTagDirty(\DOMElement $element)
|
||||||
|
{
|
||||||
|
$href = Helper::getElementHref($element);
|
||||||
|
return $href && strpos($href, '#') !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether `<use ... xlink:href="#identifier">` is expanded
|
||||||
|
* recursively in order to create DoS scenarios. The amount of a actually
|
||||||
|
* used element needs to be below `$this->useThreshold`.
|
||||||
|
*
|
||||||
|
* @param \DOMElement $element
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isUseTagExceedingThreshold(\DOMElement $element)
|
||||||
|
{
|
||||||
|
if ($this->useThreshold <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$useId = Helper::extractIdReferenceFromHref(
|
||||||
|
Helper::getElementHref($element)
|
||||||
|
);
|
||||||
|
if ($useId === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach ($this->elementReferenceResolver->findByElementId($useId) as $subject) {
|
||||||
|
if ($subject->countUse() >= $this->useThreshold) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the nesting limit for <use> tags.
|
||||||
|
*
|
||||||
|
* @param $limit
|
||||||
|
*/
|
||||||
|
public function setUseNestingLimit($limit)
|
||||||
|
{
|
||||||
|
$this->useNestingLimit = (int) $limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove nodes that are either invalid or malformed.
|
||||||
|
*
|
||||||
|
* @param \DOMNode $currentElement The current element.
|
||||||
|
*/
|
||||||
|
protected function cleanUnsafeNodes(\DOMNode $currentElement) {
|
||||||
|
// Replace CDATA node with encoded text node
|
||||||
|
if ($currentElement instanceof \DOMCdataSection) {
|
||||||
|
$textNode = $currentElement->ownerDocument->createTextNode($currentElement->nodeValue);
|
||||||
|
$currentElement->parentNode->replaceChild($textNode, $currentElement);
|
||||||
|
// If the element doesn't have a tagname, remove it and continue with next iteration
|
||||||
|
} elseif (!$currentElement instanceof \DOMElement && !$currentElement instanceof \DOMText) {
|
||||||
|
$currentElement->parentNode->removeChild($currentElement);
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious node \'' . $currentElement->nodeName . '\'',
|
||||||
|
'line' => $currentElement->getLineNo(),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $currentElement->childNodes && $currentElement->childNodes->length > 0 ) {
|
||||||
|
for ($j = $currentElement->childNodes->length - 1; $j >= 0; $j--) {
|
||||||
|
/** @var \DOMElement $childElement */
|
||||||
|
$childElement = $currentElement->childNodes->item($j);
|
||||||
|
$this->cleanUnsafeNodes($childElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve array of errors
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private static function getXmlErrors()
|
||||||
|
{
|
||||||
|
$errors = [];
|
||||||
|
foreach (libxml_get_errors() as $error) {
|
||||||
|
$errors[] = [
|
||||||
|
'message' => trim($error->message),
|
||||||
|
'line' => $error->line,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
}
|
||||||
357
vendor/enshrined/svg-sanitize/src/data/AllowedAttributes.php
vendored
Normal file
357
vendor/enshrined/svg-sanitize/src/data/AllowedAttributes.php
vendored
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize\data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AllowedAttributes
|
||||||
|
*
|
||||||
|
* @package enshrined\svgSanitize\data
|
||||||
|
*/
|
||||||
|
class AllowedAttributes implements AttributeInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of attributes
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getAttributes()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
// HTML
|
||||||
|
'about',
|
||||||
|
'accept',
|
||||||
|
'action',
|
||||||
|
'align',
|
||||||
|
'alt',
|
||||||
|
'autocomplete',
|
||||||
|
'background',
|
||||||
|
'bgcolor',
|
||||||
|
'border',
|
||||||
|
'cellpadding',
|
||||||
|
'cellspacing',
|
||||||
|
'checked',
|
||||||
|
'cite',
|
||||||
|
'class',
|
||||||
|
'clear',
|
||||||
|
'color',
|
||||||
|
'cols',
|
||||||
|
'colspan',
|
||||||
|
'coords',
|
||||||
|
'crossorigin',
|
||||||
|
'datetime',
|
||||||
|
'default',
|
||||||
|
'dir',
|
||||||
|
'disabled',
|
||||||
|
'download',
|
||||||
|
'enctype',
|
||||||
|
'encoding',
|
||||||
|
'face',
|
||||||
|
'for',
|
||||||
|
'headers',
|
||||||
|
'height',
|
||||||
|
'hidden',
|
||||||
|
'high',
|
||||||
|
'href',
|
||||||
|
'hreflang',
|
||||||
|
'id',
|
||||||
|
'integrity',
|
||||||
|
'ismap',
|
||||||
|
'label',
|
||||||
|
'lang',
|
||||||
|
'list',
|
||||||
|
'loop',
|
||||||
|
'low',
|
||||||
|
'max',
|
||||||
|
'maxlength',
|
||||||
|
'media',
|
||||||
|
'method',
|
||||||
|
'min',
|
||||||
|
'multiple',
|
||||||
|
'name',
|
||||||
|
'noshade',
|
||||||
|
'novalidate',
|
||||||
|
'nowrap',
|
||||||
|
'open',
|
||||||
|
'optimum',
|
||||||
|
'pattern',
|
||||||
|
'placeholder',
|
||||||
|
'poster',
|
||||||
|
'preload',
|
||||||
|
'pubdate',
|
||||||
|
'radiogroup',
|
||||||
|
'readonly',
|
||||||
|
'rel',
|
||||||
|
'required',
|
||||||
|
'rev',
|
||||||
|
'reversed',
|
||||||
|
'role',
|
||||||
|
'rows',
|
||||||
|
'rowspan',
|
||||||
|
'spellcheck',
|
||||||
|
'scope',
|
||||||
|
'selected',
|
||||||
|
'shape',
|
||||||
|
'size',
|
||||||
|
'sizes',
|
||||||
|
'span',
|
||||||
|
'srclang',
|
||||||
|
'start',
|
||||||
|
'src',
|
||||||
|
'srcset',
|
||||||
|
'step',
|
||||||
|
'style',
|
||||||
|
'summary',
|
||||||
|
'tabindex',
|
||||||
|
'title',
|
||||||
|
'type',
|
||||||
|
'usemap',
|
||||||
|
'valign',
|
||||||
|
'value',
|
||||||
|
'version',
|
||||||
|
'width',
|
||||||
|
'xmlns',
|
||||||
|
|
||||||
|
// SVG
|
||||||
|
'accent-height',
|
||||||
|
'accumulate',
|
||||||
|
'additivive',
|
||||||
|
'alignment-baseline',
|
||||||
|
'ascent',
|
||||||
|
'attributename',
|
||||||
|
'attributetype',
|
||||||
|
'azimuth',
|
||||||
|
'basefrequency',
|
||||||
|
'baseline-shift',
|
||||||
|
'begin',
|
||||||
|
'bias',
|
||||||
|
'by',
|
||||||
|
'class',
|
||||||
|
'clip',
|
||||||
|
'clip-path',
|
||||||
|
'clip-rule',
|
||||||
|
'color',
|
||||||
|
'color-interpolation',
|
||||||
|
'color-interpolation-filters',
|
||||||
|
'color-profile',
|
||||||
|
'color-rendering',
|
||||||
|
'cx',
|
||||||
|
'cy',
|
||||||
|
'd',
|
||||||
|
'dx',
|
||||||
|
'dy',
|
||||||
|
'diffuseconstant',
|
||||||
|
'direction',
|
||||||
|
'display',
|
||||||
|
'divisor',
|
||||||
|
'dominant-baseline',
|
||||||
|
'dur',
|
||||||
|
'edgemode',
|
||||||
|
'elevation',
|
||||||
|
'end',
|
||||||
|
'fill',
|
||||||
|
'fill-opacity',
|
||||||
|
'fill-rule',
|
||||||
|
'filter',
|
||||||
|
'filterUnits',
|
||||||
|
'flood-color',
|
||||||
|
'flood-opacity',
|
||||||
|
'font-family',
|
||||||
|
'font-size',
|
||||||
|
'font-size-adjust',
|
||||||
|
'font-stretch',
|
||||||
|
'font-style',
|
||||||
|
'font-variant',
|
||||||
|
'font-weight',
|
||||||
|
'fx',
|
||||||
|
'fy',
|
||||||
|
'g1',
|
||||||
|
'g2',
|
||||||
|
'glyph-name',
|
||||||
|
'glyphref',
|
||||||
|
'gradientunits',
|
||||||
|
'gradienttransform',
|
||||||
|
'height',
|
||||||
|
'href',
|
||||||
|
'id',
|
||||||
|
'image-rendering',
|
||||||
|
'in',
|
||||||
|
'in2',
|
||||||
|
'k',
|
||||||
|
'k1',
|
||||||
|
'k2',
|
||||||
|
'k3',
|
||||||
|
'k4',
|
||||||
|
'kerning',
|
||||||
|
'keypoints',
|
||||||
|
'keysplines',
|
||||||
|
'keytimes',
|
||||||
|
'lang',
|
||||||
|
'lengthadjust',
|
||||||
|
'letter-spacing',
|
||||||
|
'kernelmatrix',
|
||||||
|
'kernelunitlength',
|
||||||
|
'lighting-color',
|
||||||
|
'local',
|
||||||
|
'marker-end',
|
||||||
|
'marker-mid',
|
||||||
|
'marker-start',
|
||||||
|
'markerheight',
|
||||||
|
'markerunits',
|
||||||
|
'markerwidth',
|
||||||
|
'maskcontentunits',
|
||||||
|
'maskunits',
|
||||||
|
'max',
|
||||||
|
'mask',
|
||||||
|
'media',
|
||||||
|
'method',
|
||||||
|
'mode',
|
||||||
|
'min',
|
||||||
|
'name',
|
||||||
|
'numoctaves',
|
||||||
|
'offset',
|
||||||
|
'operator',
|
||||||
|
'opacity',
|
||||||
|
'order',
|
||||||
|
'orient',
|
||||||
|
'orientation',
|
||||||
|
'origin',
|
||||||
|
'overflow',
|
||||||
|
'paint-order',
|
||||||
|
'path',
|
||||||
|
'pathlength',
|
||||||
|
'patterncontentunits',
|
||||||
|
'patterntransform',
|
||||||
|
'patternunits',
|
||||||
|
'points',
|
||||||
|
'preservealpha',
|
||||||
|
'preserveaspectratio',
|
||||||
|
'r',
|
||||||
|
'rx',
|
||||||
|
'ry',
|
||||||
|
'radius',
|
||||||
|
'refx',
|
||||||
|
'refy',
|
||||||
|
'repeatcount',
|
||||||
|
'repeatdur',
|
||||||
|
'restart',
|
||||||
|
'result',
|
||||||
|
'rotate',
|
||||||
|
'scale',
|
||||||
|
'seed',
|
||||||
|
'shape-rendering',
|
||||||
|
'specularconstant',
|
||||||
|
'specularexponent',
|
||||||
|
'spreadmethod',
|
||||||
|
'stddeviation',
|
||||||
|
'stitchtiles',
|
||||||
|
'stop-color',
|
||||||
|
'stop-opacity',
|
||||||
|
'stroke-dasharray',
|
||||||
|
'stroke-dashoffset',
|
||||||
|
'stroke-linecap',
|
||||||
|
'stroke-linejoin',
|
||||||
|
'stroke-miterlimit',
|
||||||
|
'stroke-opacity',
|
||||||
|
'stroke',
|
||||||
|
'stroke-width',
|
||||||
|
'style',
|
||||||
|
'surfacescale',
|
||||||
|
'tabindex',
|
||||||
|
'targetx',
|
||||||
|
'targety',
|
||||||
|
'transform',
|
||||||
|
'text-anchor',
|
||||||
|
'text-decoration',
|
||||||
|
'text-rendering',
|
||||||
|
'textlength',
|
||||||
|
'type',
|
||||||
|
'u1',
|
||||||
|
'u2',
|
||||||
|
'unicode',
|
||||||
|
'values',
|
||||||
|
'viewbox',
|
||||||
|
'visibility',
|
||||||
|
'vector-effect',
|
||||||
|
'vert-adv-y',
|
||||||
|
'vert-origin-x',
|
||||||
|
'vert-origin-y',
|
||||||
|
'width',
|
||||||
|
'word-spacing',
|
||||||
|
'wrap',
|
||||||
|
'writing-mode',
|
||||||
|
'xchannelselector',
|
||||||
|
'ychannelselector',
|
||||||
|
'x',
|
||||||
|
'x1',
|
||||||
|
'x2',
|
||||||
|
'xmlns',
|
||||||
|
'y',
|
||||||
|
'y1',
|
||||||
|
'y2',
|
||||||
|
'z',
|
||||||
|
'zoomandpan',
|
||||||
|
|
||||||
|
// MathML
|
||||||
|
'accent',
|
||||||
|
'accentunder',
|
||||||
|
'align',
|
||||||
|
'bevelled',
|
||||||
|
'close',
|
||||||
|
'columnsalign',
|
||||||
|
'columnlines',
|
||||||
|
'columnspan',
|
||||||
|
'denomalign',
|
||||||
|
'depth',
|
||||||
|
'dir',
|
||||||
|
'display',
|
||||||
|
'displaystyle',
|
||||||
|
'fence',
|
||||||
|
'frame',
|
||||||
|
'height',
|
||||||
|
'href',
|
||||||
|
'id',
|
||||||
|
'largeop',
|
||||||
|
'length',
|
||||||
|
'linethickness',
|
||||||
|
'lspace',
|
||||||
|
'lquote',
|
||||||
|
'mathbackground',
|
||||||
|
'mathcolor',
|
||||||
|
'mathsize',
|
||||||
|
'mathvariant',
|
||||||
|
'maxsize',
|
||||||
|
'minsize',
|
||||||
|
'movablelimits',
|
||||||
|
'notation',
|
||||||
|
'numalign',
|
||||||
|
'open',
|
||||||
|
'rowalign',
|
||||||
|
'rowlines',
|
||||||
|
'rowspacing',
|
||||||
|
'rowspan',
|
||||||
|
'rspace',
|
||||||
|
'rquote',
|
||||||
|
'scriptlevel',
|
||||||
|
'scriptminsize',
|
||||||
|
'scriptsizemultiplier',
|
||||||
|
'selection',
|
||||||
|
'separator',
|
||||||
|
'separators',
|
||||||
|
'slope',
|
||||||
|
'stretchy',
|
||||||
|
'subscriptshift',
|
||||||
|
'supscriptshift',
|
||||||
|
'symmetric',
|
||||||
|
'voffset',
|
||||||
|
'width',
|
||||||
|
'xmlns',
|
||||||
|
|
||||||
|
// XML
|
||||||
|
'xlink:href',
|
||||||
|
'xml:id',
|
||||||
|
'xlink:title',
|
||||||
|
'xml:space',
|
||||||
|
'xmlns:xlink',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
99
vendor/enshrined/svg-sanitize/src/data/AllowedTags.php
vendored
Normal file
99
vendor/enshrined/svg-sanitize/src/data/AllowedTags.php
vendored
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize\data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AllowedTags
|
||||||
|
*
|
||||||
|
* @package enshrined\svgSanitize\data
|
||||||
|
*/
|
||||||
|
class AllowedTags implements TagInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of tags
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getTags()
|
||||||
|
{
|
||||||
|
return array (
|
||||||
|
// HTML
|
||||||
|
'a',
|
||||||
|
'font',
|
||||||
|
'image',
|
||||||
|
'style',
|
||||||
|
|
||||||
|
// SVG
|
||||||
|
'svg',
|
||||||
|
'altglyph',
|
||||||
|
'altglyphdef',
|
||||||
|
'altglyphitem',
|
||||||
|
'animatecolor',
|
||||||
|
'animatemotion',
|
||||||
|
'animatetransform',
|
||||||
|
'circle',
|
||||||
|
'clippath',
|
||||||
|
'defs',
|
||||||
|
'desc',
|
||||||
|
'ellipse',
|
||||||
|
'filter',
|
||||||
|
'font',
|
||||||
|
'g',
|
||||||
|
'glyph',
|
||||||
|
'glyphref',
|
||||||
|
'hkern',
|
||||||
|
'image',
|
||||||
|
'line',
|
||||||
|
'lineargradient',
|
||||||
|
'marker',
|
||||||
|
'mask',
|
||||||
|
'metadata',
|
||||||
|
'mpath',
|
||||||
|
'path',
|
||||||
|
'pattern',
|
||||||
|
'polygon',
|
||||||
|
'polyline',
|
||||||
|
'radialgradient',
|
||||||
|
'rect',
|
||||||
|
'stop',
|
||||||
|
'switch',
|
||||||
|
'symbol',
|
||||||
|
'text',
|
||||||
|
'textpath',
|
||||||
|
'title',
|
||||||
|
'tref',
|
||||||
|
'tspan',
|
||||||
|
'use',
|
||||||
|
'view',
|
||||||
|
'vkern',
|
||||||
|
|
||||||
|
// SVG Filters
|
||||||
|
'feBlend',
|
||||||
|
'feColorMatrix',
|
||||||
|
'feComponentTransfer',
|
||||||
|
'feComposite',
|
||||||
|
'feConvolveMatrix',
|
||||||
|
'feDiffuseLighting',
|
||||||
|
'feDisplacementMap',
|
||||||
|
'feDistantLight',
|
||||||
|
'feFlood',
|
||||||
|
'feFuncA',
|
||||||
|
'feFuncB',
|
||||||
|
'feFuncG',
|
||||||
|
'feFuncR',
|
||||||
|
'feGaussianBlur',
|
||||||
|
'feMerge',
|
||||||
|
'feMergeNode',
|
||||||
|
'feMorphology',
|
||||||
|
'feOffset',
|
||||||
|
'fePointLight',
|
||||||
|
'feSpecularLighting',
|
||||||
|
'feSpotLight',
|
||||||
|
'feTile',
|
||||||
|
'feTurbulence',
|
||||||
|
|
||||||
|
//text
|
||||||
|
'#text'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
vendor/enshrined/svg-sanitize/src/data/AttributeInterface.php
vendored
Normal file
18
vendor/enshrined/svg-sanitize/src/data/AttributeInterface.php
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize\data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AttributeInterface
|
||||||
|
*
|
||||||
|
* @package enshrined\svgSanitize\data
|
||||||
|
*/
|
||||||
|
interface AttributeInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of attributes
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getAttributes();
|
||||||
|
}
|
||||||
19
vendor/enshrined/svg-sanitize/src/data/TagInterface.php
vendored
Normal file
19
vendor/enshrined/svg-sanitize/src/data/TagInterface.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize\data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface TagInterface
|
||||||
|
*
|
||||||
|
* @package enshrined\svgSanitize\tags
|
||||||
|
*/
|
||||||
|
interface TagInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of tags
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getTags();
|
||||||
|
|
||||||
|
}
|
||||||
64
vendor/enshrined/svg-sanitize/src/data/XPath.php
vendored
Normal file
64
vendor/enshrined/svg-sanitize/src/data/XPath.php
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize\data;
|
||||||
|
|
||||||
|
class XPath extends \DOMXPath
|
||||||
|
{
|
||||||
|
const DEFAULT_NAMESPACE_PREFIX = 'svg';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $defaultNamespaceURI;
|
||||||
|
|
||||||
|
public function __construct(\DOMDocument $doc)
|
||||||
|
{
|
||||||
|
parent::__construct($doc);
|
||||||
|
$this->handleDefaultNamespace();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $nodeName
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function createNodeName($nodeName)
|
||||||
|
{
|
||||||
|
if (empty($this->defaultNamespaceURI)) {
|
||||||
|
return $nodeName;
|
||||||
|
}
|
||||||
|
return self::DEFAULT_NAMESPACE_PREFIX . ':' . $nodeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleDefaultNamespace()
|
||||||
|
{
|
||||||
|
$rootElements = $this->getRootElements();
|
||||||
|
|
||||||
|
if (count($rootElements) !== 1) {
|
||||||
|
throw new \LogicException(
|
||||||
|
sprintf('Got %d svg elements, expected exactly one', count($rootElements)),
|
||||||
|
1570870568
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$this->defaultNamespaceURI = (string)$rootElements[0]->namespaceURI;
|
||||||
|
|
||||||
|
if ($this->defaultNamespaceURI !== '') {
|
||||||
|
$this->registerNamespace(self::DEFAULT_NAMESPACE_PREFIX, $this->defaultNamespaceURI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \DOMElement[]
|
||||||
|
*/
|
||||||
|
protected function getRootElements()
|
||||||
|
{
|
||||||
|
$rootElements = [];
|
||||||
|
$elements = $this->document->getElementsByTagName('svg');
|
||||||
|
/** @var \DOMElement $element */
|
||||||
|
foreach ($elements as $element) {
|
||||||
|
if ($element->parentNode !== $this->document) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$rootElements[] = $element;
|
||||||
|
}
|
||||||
|
return $rootElements;
|
||||||
|
}
|
||||||
|
}
|
||||||
192
vendor/enshrined/svg-sanitize/src/svg-scanner.php
vendored
Normal file
192
vendor/enshrined/svg-sanitize/src/svg-scanner.php
vendored
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple program that uses svg-sanitizer
|
||||||
|
* to find issues in files specified on the
|
||||||
|
* command line, and prints a JSON output with
|
||||||
|
* the issues found on exit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once( __DIR__ . '/data/AttributeInterface.php' );
|
||||||
|
require_once( __DIR__ . '/data/TagInterface.php' );
|
||||||
|
require_once( __DIR__ . '/data/AllowedAttributes.php' );
|
||||||
|
require_once( __DIR__ . '/data/AllowedTags.php' );
|
||||||
|
require_once( __DIR__ . '/data/XPath.php' );
|
||||||
|
require_once( __DIR__ . '/ElementReference/Resolver.php' );
|
||||||
|
require_once( __DIR__ . '/ElementReference/Subject.php' );
|
||||||
|
require_once( __DIR__ . '/ElementReference/Usage.php' );
|
||||||
|
require_once( __DIR__ . '/Exceptions/NestingException.php' );
|
||||||
|
require_once( __DIR__ . '/Helper.php' );
|
||||||
|
require_once( __DIR__ . '/Sanitizer.php' );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print array as JSON and then
|
||||||
|
* exit program with a particular
|
||||||
|
* exit-code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function sysexit(
|
||||||
|
$results,
|
||||||
|
$status
|
||||||
|
) {
|
||||||
|
echo json_encode(
|
||||||
|
$results,
|
||||||
|
JSON_PRETTY_PRINT
|
||||||
|
);
|
||||||
|
|
||||||
|
exit( $status );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Main part begins
|
||||||
|
*/
|
||||||
|
|
||||||
|
global $argv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up results array, to
|
||||||
|
* be printed on exit.
|
||||||
|
*/
|
||||||
|
$results = array(
|
||||||
|
'totals' => array(
|
||||||
|
'errors' => 0,
|
||||||
|
),
|
||||||
|
|
||||||
|
'files' => array(
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Catch files to scan from $argv.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$files_to_scan = $argv;
|
||||||
|
unset( $files_to_scan[0] );
|
||||||
|
|
||||||
|
$files_to_scan = array_values(
|
||||||
|
$files_to_scan
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Catch no file specified.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( empty( $files_to_scan ) ) {
|
||||||
|
$results['totals']['errors']++;
|
||||||
|
$results['messages'] = array(
|
||||||
|
array( 'No files to scan specified' ),
|
||||||
|
);
|
||||||
|
|
||||||
|
sysexit(
|
||||||
|
$results,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the SVG scanner.
|
||||||
|
*
|
||||||
|
* Make sure to allow custom attributes,
|
||||||
|
* and to remove remote references.
|
||||||
|
*/
|
||||||
|
$sanitizer = new enshrined\svgSanitize\Sanitizer();
|
||||||
|
|
||||||
|
$sanitizer->removeRemoteReferences( true );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scan each file specified to be scanned.
|
||||||
|
*/
|
||||||
|
|
||||||
|
foreach( $files_to_scan as $file_name ) {
|
||||||
|
/*
|
||||||
|
* Read SVG file.
|
||||||
|
*/
|
||||||
|
$svg_file = @file_get_contents( $file_name );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If not found, report that and continue.
|
||||||
|
*/
|
||||||
|
if ( false === $svg_file ) {
|
||||||
|
$results['totals']['errors']++;
|
||||||
|
|
||||||
|
$results['files'][ $file_name ][] = array(
|
||||||
|
'errors' => 1,
|
||||||
|
'messages' => array(
|
||||||
|
array(
|
||||||
|
'message' => 'File specified could not be read (' . $file_name . ')',
|
||||||
|
'line' => null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanitize file and get issues found.
|
||||||
|
*/
|
||||||
|
$sanitize_status = $sanitizer->sanitize( $svg_file );
|
||||||
|
|
||||||
|
$xml_issues = $sanitizer->getXmlIssues();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we find no issues, simply note that.
|
||||||
|
*/
|
||||||
|
if ( empty( $xml_issues ) && ( false !== $sanitize_status ) ) {
|
||||||
|
$results['files'][ $file_name ] = array(
|
||||||
|
'errors' => 0,
|
||||||
|
'messages' => array()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Could not sanitize the file.
|
||||||
|
*/
|
||||||
|
else if (
|
||||||
|
( '' === $sanitize_status ) ||
|
||||||
|
( false === $sanitize_status )
|
||||||
|
) {
|
||||||
|
$results['totals']['errors']++;
|
||||||
|
|
||||||
|
$results['files'][ $file_name ] = array(
|
||||||
|
'errors' => 1,
|
||||||
|
'messages' => array(
|
||||||
|
array(
|
||||||
|
'message' => 'Unable to sanitize file \'' . $file_name . '\'' ,
|
||||||
|
'line' => null,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we find issues, note it and update statistics.
|
||||||
|
*/
|
||||||
|
|
||||||
|
else {
|
||||||
|
$results['totals']['errors'] += count( $xml_issues );
|
||||||
|
|
||||||
|
$results['files'][ $file_name ] = array(
|
||||||
|
'errors' => count( $xml_issues ),
|
||||||
|
'messages' => $xml_issues,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
unset( $svg_file );
|
||||||
|
unset( $xml_issues );
|
||||||
|
unset( $sanitize_status );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exit with a status
|
||||||
|
* that reflects what issues
|
||||||
|
* we found.
|
||||||
|
*/
|
||||||
|
sysexit(
|
||||||
|
$results,
|
||||||
|
( $results['totals']['errors'] === 0 ? 0 : 1 )
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user