Bereinigungeasy_svg_sanitizer()

easy_svg_sanitizer()

Liefert einen frischen SVG-Sanitizer, eingestellt wie die Uploads dieser Site, damit dein Add-on genau das behält und entfernt, was Easy SVG auch tut.

Funktion · Easy SVG · Status: Stabil

easy_svg_sanitizer() gibt deinem Plugin denselben SVG-Bereiniger, den Easy SVG für Uploads benutzt, mit den Erlaubnislisten und der Einstellung für fremde Verweise dieser Site. Nimm ihn immer dann, wenn dein Code SVG-Markup annimmt, das er nicht selbst geschrieben hat. Es ist die eine Funktion, die Easy SVG Add-ons dauerhaft zusagt.

Verwendung

easy_svg_sanitizer(): \enshrined\svgSanitize\Sanitizer|null
$sanitizer = easy_svg_sanitizer();
$clean     = $sanitizer ? $sanitizer->sanitize( $markup ) : false;

Wann du es brauchst

  • Dein Plugin lässt Benutzer SVG-Markup einfügen oder hochladen (ein Formularfeld, ein REST-Endpunkt, ein Block-Attribut), und du speicherst oder gibst es aus.
  • Du importierst SVGs von anderswo, etwa aus einer fremden API, bevor du sie speicherst.
  • Du baust eine Funktion auf Easy SVG auf und willst respektieren, was der Site-Betreiber über esw_svg_allowed_tags, esw_svg_allowed_attributes und esw_svg_remove_remote_references erlaubt hat.

Lass es bleiben:

  • Für Dateien, die über den WordPress-Uploader kommen. Die bereinigt Easy SVG schon, ein zweiter Durchlauf ändert nichts und kostet nur Zeit.
  • Als Ersatz für die Klassen esw_svg_tags und esw_svg_attributes oder einen eigenen new \enshrined\svgSanitize\Sanitizer(). Das sind Interna, und ein anders gebauter Sanitizer ignoriert die Filter der Site.
  • Als einzige Prüfung für fremde Eingaben. Siehe „Was die Funktion nicht tut“ weiter unten.

Parameter

Diese Funktion hat keine Parameter.

Rückgabewert

returnenshrined\svgSanitize\Sanitizer|null

Bei jedem Aufruf eine neue Sanitizer-Instanz, eingestellt für diese Site. null, wenn die Klasse \enshrined\svgSanitize\Sanitizer nicht existiert, also wenn der vendor-Ordner des Plugins fehlt.

Die Instanz gehört dir. Änderst du sie (zum Beispiel mit removeXMLTag( true )), betrifft das nichts anderes. Die Methoden, die du am häufigsten brauchst:

MethodeErgebnis
sanitize( $markup )Bereinigtes Markup als String. '', wenn die Eingabe im Sinne von PHP leer ist ('' und '0'). false, wenn sich das XML nicht lesen lässt. Wirft eine LogicException, wenn das XML zwar lesbar ist, aber nicht genau eine svg-Wurzel hat, zum Beispiel bei einer HTML-Seite.
getXmlIssues()Was der letzte sanitize()-Aufruf entfernt hat, als array( array( 'message' => ..., 'line' => ... ) ).
removeXMLTag( true )Lässt die ?xml-Deklaration weg, was du für die direkte Ausgabe im HTML willst.
minify( true )Fasst Leerraum im Ergebnis zusammen.
removeRemoteReferences( true )Macht deine Kopie strenger als die Site.

Beispiele

Markup aus einem Formularfeld bereinigen

/**
 * Vom Benutzer geliefertes SVG-Markup bereinigen, sonst '' zurückgeben.
 *
 * @param string $markup Rohes Markup.
 * @return string
 */
function myplugin_clean_svg( $markup ) {
	if ( ! function_exists( 'easy_svg_sanitizer' ) ) {
		return '';
	}

	$sanitizer = easy_svg_sanitizer();
	if ( null === $sanitizer ) {
		return '';
	}

	$sanitizer->removeXMLTag( true );

	try {
		$clean = $sanitizer->sanitize( (string) $markup );
	} catch ( \Throwable $e ) {
		return '';
	}

	if ( ! is_string( $clean ) || '' === trim( $clean ) ) {
		return '';
	}

	return $clean;
}

Behandle false, '' und eine Exception gleich: Die Eingabe war kein brauchbares SVG.

Ein SVG aus einer fremden API mit eigenen Grenzen importieren

/**
 * Ein SVG abrufen, bereinigen und als Datei in uploads speichern.
 *
 * @param string $url Adresse des SVG.
 * @return string|WP_Error Öffentliche URL der gespeicherten Datei.
 */
function myplugin_import_remote_svg( $url ) {
	$max_bytes = 512 * KB_IN_BYTES;

	$response = wp_safe_remote_get( $url, array( 'timeout' => 10, 'limit_response_size' => $max_bytes ) );
	if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
		return new WP_Error( 'myplugin_fetch', __( 'The SVG could not be downloaded.', 'myplugin' ) );
	}

	$markup = wp_remote_retrieve_body( $response );
	if ( strlen( $markup ) >= $max_bytes || substr_count( strtolower( $markup ), '<use' ) > 200 ) {
		return new WP_Error( 'myplugin_too_big', __( 'The SVG is too large or too complex.', 'myplugin' ) );
	}

	$sanitizer = function_exists( 'easy_svg_sanitizer' ) ? easy_svg_sanitizer() : null;
	if ( null === $sanitizer ) {
		return new WP_Error( 'myplugin_no_sanitizer', __( 'Easy SVG is not active.', 'myplugin' ) );
	}

	try {
		$clean = $sanitizer->sanitize( $markup );
	} catch ( \Throwable $e ) {
		$clean = false;
	}
	if ( ! is_string( $clean ) || '' === trim( $clean ) ) {
		return new WP_Error( 'myplugin_not_svg', __( 'This is not a usable SVG.', 'myplugin' ) );
	}

	$upload = wp_upload_bits( 'myplugin-' . md5( $url ) . '.svg', null, $clean );
	if ( ! empty( $upload['error'] ) ) {
		return new WP_Error( 'myplugin_write', $upload['error'] );
	}

	return $upload['url'];
}

// Ausgabe: ein img-Tag, escaped wie jede andere URL.
$src = myplugin_import_remote_svg( 'https://icons.example.com/logo.svg' );
if ( ! is_wp_error( $src ) ) {
	printf( '<img src="%s" alt="%s" />', esc_url( $src ), esc_attr__( 'Logo', 'myplugin' ) );
}

Die Grenzen für Größe und use setzt du bewusst selbst: easy_svg_sanitizer() wendet die Upload-Grenzen der Site nicht an (siehe „Was die Funktion nicht tut“). Das Schreiben über wp_upload_bits() besteht auch die eigene Prüfung von Easy SVG auf diesem Weg, weil die Datei schon sauber ist. wp_upload_bits() akzeptiert den Namen .svg allerdings nur, wenn SVG auf der Site ein erlaubter Upload-Typ ist (der Schalter SVG-Uploads in der Mediathek erlauben) oder der aktuelle Benutzer unfiltered_upload hat.

Versionsprüfung und Protokoll der entfernten Teile

/**
 * Markup bereinigen und protokollieren, was der Sanitizer entfernt hat.
 *
 * @param string $markup Rohes Markup.
 * @return string Sauberes Markup oder ''.
 */
function myplugin_clean_and_report( $markup ) {
	// EASY_SVG_API und easy_svg_sanitizer() kamen gemeinsam mit Easy SVG 5.0.0.
	if ( ! defined( 'EASY_SVG_API' ) || EASY_SVG_API < 1 || ! function_exists( 'easy_svg_sanitizer' ) ) {
		return '';
	}

	try {
		$sanitizer = easy_svg_sanitizer();
		$clean     = $sanitizer ? $sanitizer->sanitize( $markup ) : false;
	} catch ( \Throwable $e ) {
		return '';
	}

	if ( $sanitizer && defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
		foreach ( $sanitizer->getXmlIssues() as $issue ) {
			error_log( sprintf( 'myplugin SVG: %s (line %d)', $issue['message'], $issue['line'] ) );
		}
	}

	return is_string( $clean ) ? trim( $clean ) : '';
}

Das try umschließt auch den Aufruf von easy_svg_sanitizer(): Gibt ein Filter der Site für die Erlaubnislisten etwas anderes als ein Array zurück, wirft schon der Aufbau des Sanitizers einen TypeError.

Nimm diese Funktion, nicht die Klassen esw_svg_tags oder esw_svg_attributes und keinen selbst gebauten Sanitizer. Ein anders gebauter sieht die Filter der Site nicht: Er entfernt, was die Site behält, und, schlimmer, er behält, was die Site entfernt. Gib nie Markup aus, das nicht durch sanitize() gelaufen ist, und nie die rohe Eingabe, wenn sanitize() false geliefert oder geworfen hat.

So funktioniert es

  1. Easy SVG legt beim Laden einen globalen $sanitizer an, aber nur, wenn die Klasse existiert und der Name noch frei ist. Er dient als Vorlage: Snippets aus Version 4.1 stellen ihn noch ein (etwa mit removeXMLTag( true )), und diese Einstellungen gehen auf jede Kopie über.
  2. Die Funktion klont diesen globalen Sanitizer, wenn darin ein echter Sanitizer steckt, sonst fängt sie neu an. Liegt unter dem Namen etwas anderes (das Objekt eines anderen Plugins), wird es ignoriert und nicht aufgerufen.
  3. Erlaubnislisten und Einstellung für fremde Verweise werden immer an der Kopie gesetzt. Sie gewinnen also gegen alles, was am globalen Objekt eingestellt ist.
  4. Eine Instanz pro Aufruf: Zwei Aufrufer teilen sich nie einen Zustand, und deine Änderungen an deiner Kopie wirken nirgends sonst.

Easy SVG nutzt diese Funktion selbst auf jedem Weg: Uploads und Sideloads (esw_svg_file_checker()), die Prüfung in wp_upload_bits (easy_svg_markup_is_clean()), die Prüfung jedes neuen Anhangs und die Icon-Bibliothek (anlegen, ersetzen und easy_svg_update_icon_markup()).

Was die Funktion nicht tut

Diese Schritte laufen in den Upload-Wegen von Easy SVG, rund um den Sanitizer, nicht in ihm. Wenn du fremde Eingaben verarbeitest, sorge selbst für etwas Gleichwertiges:

  • Größengrenze. Uploads über der Einstellung Maximale SVG-Größe (MB) werden abgelehnt (Filter easy_svg_max_bytes).
  • Komplexitätsgrenze. Dateien mit mehr als 10 PHP-Verarbeitungsanweisungen oder 1000 use-Elementen werden vor dem Parsen abgelehnt (Filter easy_svg_max_php_tags, easy_svg_max_use_tags), weil solche Strukturen den Parser minutenlang beschäftigen können.
  • Leeres Ergebnis. Ein Ergebnis, das nach trim() leer ist, wird abgelehnt.
  • Animationsprüfung. Hat eine Site animate oder set erlaubt, entfernen Uploads zusätzlich Animationselemente, die auf href oder on*-Attribute zielen.
  • Icon-Härtung. Icons verlieren außerdem script, style, foreignObject, jedes Animationselement, jedes on*-Attribut und jedes href, das nicht mit # beginnt.

Stolperfallen

  • Ruf sie spät genug auf. Die Funktion existiert, sobald die Hauptdatei von Easy SVG geladen ist. Auf oberster Ebene deiner eigenen Plugin-Datei gibt es sie unter Umständen noch nicht. Ruf sie in einem Hook auf (init oder später) oder prüf dort mit function_exists().
  • null ist eine echte Antwort. Eine kaputte Installation ohne vendor-Ordner liefert null. Ruf ->sanitize() nie ungeprüft auf dem Rückgabewert auf.
  • Drei Arten zu scheitern. false (nicht lesbar), '' (leere Eingabe) und eine LogicException (nicht genau eine svg-Wurzel) heißen alle „nicht brauchbar“. Fang \Throwable ab, nicht nur Exception.
  • Die Ausgabe ist eingerückt und beginnt mit einer XML-Deklaration. Ruf removeXMLTag( true ) auf, bevor du sie direkt ins HTML schreibst.
  • Eine veraltete Bibliothek kann gewinnen. Hat ein anderes Plugin zuerst eine ältere Version von enshrined/svg-sanitize geladen, bekommst du diese Klasse. Easy SVG zeigt Admins dann eine Warnung im Dashboard, auf der Plugin-Seite und in der Mediathek. easy_svg_sanitizer() liefert trotzdem eine Instanz dieser älteren Klasse.
  • Sie bereinigt, sie prüft kein Design. Eine Datei, die ein nicht erlaubtes Element verliert, kommt trotzdem als gültiger String zurück. Mit getXmlIssues() kannst du dem Benutzer sagen, was entfernt wurde.

Siehe auch