HTMLPurifier mit dem Zend Framework nutzen

Pádraic Brady hat in seinem Blog über Zend_Filter_StripTags und seine mögliche missbräuchliche Verwendung als XSS-Filter geschrieben und damit einiges an Aufsehen erregt. Ich selbst bin zufällig kürzlich über die Klasse gestolpert. Ohne sie groß zu testen war mir der Code aber relativ suspekt und ich habe sie nicht verwendet.

Stattdessen nutze ich wie bisher HTMLPurifier (wird übrigens auch von Pádraic in seinem Artikel empfohlen).

HTML Purifier is a standards-compliant HTML filter library written in PHP. HTML Purifier will not only remove all malicious code (better known as XSS) with a thoroughly audited, secure yet permissive whitelist, it will also make sure your documents are standards compliant, something only achievable with a comprehensive knowledge of W3C’s specifications. Tired of using BBCode due to the current landscape of deficient or insecure HTML filters? Have a WYSIWYG editor but never been able to use it? Looking for high-quality, standards-compliant, open-source components for that application you’re building? HTML Purifier is for you!

Glücklicherweise lässt sich HTMLPurifier sehr leicht in das Zend Framework integrieren.

Installation von HTMLPurifier

Am einfachsten lässt sich HTMLPurifier über PEAR installieren:

$ pear channel-discover htmlpurifier.org
$ pear install hp/HTMLPurifier

Alternativ kann man sich die Bibliothek auch herunterladen und im library-Ordner (Parallen zum Zend-Ordner) installieren.

Filtern mit HTMLPurifier

Um HTMLPurifier in Zend Framework-Projekten nutzen zu können, erstellen wir uns einen Filter der Zend_Filter_Interface implementiert.

Wir erstellen uns den Filter in library/App/Filter/HtmlPurifier.php:

<?php
/**
 * @see Zend_Filter_Interface
 */
require_once 'Zend/Filter/Interface.php';
 
/**
 * @category App
 * @package App_Filter
 */
class App_Filter_HtmlPurifier implements Zend_Filter_Interface
{
    /**
     * The HTMLPurifier instance
     *
     * @var HTMLPurifier
     */
    protected $_instance;
 
    /**
     * Constructor
     *
     * @param mixed $config
     * @return void
     */
    public function __construct($config = null)
    {
    	if (!class_exists('HTMLPurifier_Bootstrap', false)) {
            require_once 'HTMLPurifier/Bootstrap.php';
            spl_autoload_register(array('HTMLPurifier_Bootstrap', 'autoload'));
    	}
 
        $this->_instance = new HTMLPurifier($config);
    }
 
    /**
     * Defined by Zend_Filter_Interface
     *
     * Returns the string $value, purified by HTMLPurifier
     *
     * @param string $value
     * @return string
     */
    public function filter($value)
    {
        return $this->_instance->purify($value);
    }
}

Die einfachste Variante um HTML zu filtern ist nun:

$filter = new App_Filter_HtmlPurifier($config);
$cleanHtml = $filter->filter($dirtyHtml);

Die Variable $config, die wir dem Konstruktor übergeben, kann dabei ein HTMLPurifier_Config-Objekt, ein Array oder der Pfad zu einer .ini-Datei sein. Mehr Informationen dazu findet man in der INSTALL-Datei von HTMLPurifier.

Warum aber HTMLPurifier in einem Filter verstecken? Wir könnten doch auch direkt das HTMLPurifier-Objekt nutzen? Der Vorteil ist, dass wir so den Filter in andere Komponenten des Zend Frameworks integrieren können.

Als erstes kommt uns da natürlich Zend_Form in den Sinn. Man kann so den Filter für seine Formular-Elemente nutzen, z. B. für Textfelder in die HTML-Code eingetragen werden kann um den Markup valide zu machen oder um nur bestimmte Tags zu erlauben.

Als Beispiel hier ein Kommentar-Textfeld in dem nur <b>, <strong> und <a>-Tags erlaubt sind. Bei den <b> und <strong>-Tags sind keine Attribute erlaubt, beim <a>-Tag nur das href-Attribut.

$form->addElementPrefixPath('App_Filter', 'App/Filter', Zend_Form_Element::FILTER);
$form->addElement('textarea', 'comment_text', array(
    'label' => 'Kommentar',
    'filters' => array(
        array('HtmlPurifier', array(array('HTML.Allowed' => 'b,strong,a[href]'))),
    ),
));

HTMLPurifier akzeptiert eine Vielzahl von Konfigurations-Optionen. Ein Blick in die Dokumentation hilft.

Somit haben wir den ersten Teil von “Filter input, Escape output” erledigt. Im 2. Teil werden wir dann einen Blick auf die Implementierung eines Zend_View_Helpers werfen mit dem wir Variablen in View-Skripten entsprechend filtern können.

Links zum Thema