Search code examples
phphtmlpurifier

Allow classes with a certain prefix in HTMLPurifier


Is it possible to configure HTMLPurifier to allow all classes with a certain prefix? For example, I'm using FontAwesome and would like to give the user the ability to use its icons, but there are too many to reasonably hardcode in an array.

This is what I'd like to do, but it doesn't work this way:

$config = HTMLPurifier_Config::createDefault() ;
$config->set('Attr.AllowedClasses', array('fa', 'fa-*')) ;

I found this example, which suggests that it is possible, but the code on that page doesn't actually seem to do as advertised, and some parts look wrong to me. From what I can understand of it, it only allows a tags with a target attribute, but not a class attribute even though it supposedly checks for prefixed classes.


Solution

  • Using the example from the link in the question as a base, I managed to hack together this solution. It seems to work like a charm. It is limited to a per-element basis, but that's actually great for my purposes.

    I don't know if this is the best solution, but it works for me.

    class CustomClassDef extends HTMLPurifier_AttrDef {
        private $classes, $prefixes ;
    
        public function __construct($classes, $prefixes) {
            $this->classes = $classes ;
            $this->prefixes = is_array($prefixes) ? join('|', $prefixes) : $prefixes ;
        }
    
        public function validate($string, $config, $context) {
            $classes = preg_split('/\s+/', $string) ;
            $validclasses = array() ;
    
            foreach ($classes as $class) {
                if (in_array($class, $this->classes) or
                    preg_match("/^({$this->prefixes})/i", $class)) {
    
                    $validclasses[] = $class ;
                }
            }
    
            return join(' ', $validclasses) ;
        }
    }
    
    $config = HTMLPurifier_Config::createDefault() ;
    // Allow no classes by default
    $config->set('Attr.AllowedClasses', array()) ;
    
    $def = $config->getHTMLDefinition(true) ;
    // Allow the class 'fa', and classes prefixed 'fa-' or 'foo-', on i tags
    $def->addAttribute('i', 'class', new CustomClassDef(array('fa'), array('fa-', 'foo-'))) ;
    
    // Allow classes prefixed 'language-' on code tags
    $def->addAttribute('code', 'class', new CustomClassDef(array(), 'language-')) ;
    
    $purifier = new HTMLPurifier($config) ;