mirror of
https://github.com/ezyang/htmlpurifier.git
synced 2024-12-22 08:21:52 +00:00
Implement %Attr.AllowedClasses and %Attr.ForbiddenClasses.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
This commit is contained in:
parent
bf71c3f392
commit
baf053b016
3
NEWS
3
NEWS
@ -31,6 +31,9 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
|
||||
tags that contain non-breaking spaces as well other whitespace. You
|
||||
can also modify which tags should have maintained with
|
||||
%AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.
|
||||
! Implement %Attr.AllowedClasses, which allows administrators to restrict
|
||||
classes users can use to a specified finite set of classes, and
|
||||
%Attr.ForbiddenClasses, which is the logical inverse.
|
||||
. Created script maintenance/rename-config.php for renaming a configuration
|
||||
directive while maintaining its alias. This script does not change source code.
|
||||
|
||||
|
3
TODO
3
TODO
@ -17,10 +17,11 @@ afraid to cast your vote for the next feature to be implemented!
|
||||
- Incorporate data: support as implemented here:
|
||||
http://htmlpurifier.org/phorum/read.php?3,3491,3548
|
||||
- Fix ImgRequired to handle data correctly
|
||||
- Provide callback/lookup table of allowed class attributes
|
||||
- Think about allowing explicit order of operations hooks for transforms
|
||||
- Allow more relaxed "class" definition than NMTOKENS for appropriate
|
||||
doctypes
|
||||
- Lock when configuring Definition objects so we CAN'T access configuration
|
||||
directives outside of what dependency has been registered.
|
||||
|
||||
FUTURE VERSIONS
|
||||
---------------
|
||||
|
@ -98,6 +98,8 @@ require 'HTMLPurifier/AttrDef/CSS/Percentage.php';
|
||||
require 'HTMLPurifier/AttrDef/CSS/TextDecoration.php';
|
||||
require 'HTMLPurifier/AttrDef/CSS/URI.php';
|
||||
require 'HTMLPurifier/AttrDef/HTML/Bool.php';
|
||||
require 'HTMLPurifier/AttrDef/HTML/Nmtokens.php';
|
||||
require 'HTMLPurifier/AttrDef/HTML/Class.php';
|
||||
require 'HTMLPurifier/AttrDef/HTML/Color.php';
|
||||
require 'HTMLPurifier/AttrDef/HTML/FrameTarget.php';
|
||||
require 'HTMLPurifier/AttrDef/HTML/ID.php';
|
||||
@ -105,7 +107,6 @@ require 'HTMLPurifier/AttrDef/HTML/Pixels.php';
|
||||
require 'HTMLPurifier/AttrDef/HTML/Length.php';
|
||||
require 'HTMLPurifier/AttrDef/HTML/LinkTypes.php';
|
||||
require 'HTMLPurifier/AttrDef/HTML/MultiLength.php';
|
||||
require 'HTMLPurifier/AttrDef/HTML/Nmtokens.php';
|
||||
require 'HTMLPurifier/AttrDef/URI/Email.php';
|
||||
require 'HTMLPurifier/AttrDef/URI/Host.php';
|
||||
require 'HTMLPurifier/AttrDef/URI/IPv4.php';
|
||||
|
@ -92,6 +92,8 @@ require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Percentage.php';
|
||||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/TextDecoration.php';
|
||||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/URI.php';
|
||||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Bool.php';
|
||||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Nmtokens.php';
|
||||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Class.php';
|
||||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Color.php';
|
||||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/FrameTarget.php';
|
||||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/ID.php';
|
||||
@ -99,7 +101,6 @@ require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Pixels.php';
|
||||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Length.php';
|
||||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/LinkTypes.php';
|
||||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/MultiLength.php';
|
||||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Nmtokens.php';
|
||||
require_once $__dir . '/HTMLPurifier/AttrDef/URI/Email.php';
|
||||
require_once $__dir . '/HTMLPurifier/AttrDef/URI/Host.php';
|
||||
require_once $__dir . '/HTMLPurifier/AttrDef/URI/IPv4.php';
|
||||
|
22
library/HTMLPurifier/AttrDef/HTML/Class.php
Normal file
22
library/HTMLPurifier/AttrDef/HTML/Class.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Implements special behavior for class attribute (normally NMTOKENS)
|
||||
*/
|
||||
class HTMLPurifier_AttrDef_HTML_Class extends HTMLPurifier_AttrDef_HTML_Nmtokens
|
||||
{
|
||||
protected function filter($tokens, $config, $context) {
|
||||
$allowed = $config->get('Attr.AllowedClasses');
|
||||
$forbidden = $config->get('Attr.ForbiddenClasses');
|
||||
$ret = array();
|
||||
foreach ($tokens as $token) {
|
||||
if (
|
||||
($allowed === null || isset($allowed[$token])) &&
|
||||
!isset($forbidden[$token])
|
||||
) {
|
||||
$ret[] = $token;
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
}
|
@ -2,10 +2,6 @@
|
||||
|
||||
/**
|
||||
* Validates contents based on NMTOKENS attribute type.
|
||||
* @note The only current use for this is the class attribute in HTML
|
||||
* @note Could have some functionality factored out into Nmtoken class
|
||||
* @warning We cannot assume this class will be used only for 'class'
|
||||
* attributes. Not sure how to hook in magic behavior, then.
|
||||
*/
|
||||
class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef
|
||||
{
|
||||
@ -17,6 +13,17 @@ class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef
|
||||
// early abort: '' and '0' (strings that convert to false) are invalid
|
||||
if (!$string) return false;
|
||||
|
||||
$tokens = $this->split($string);
|
||||
$tokens = $this->filter($tokens, $config, $context);
|
||||
if (empty($tokens)) return false;
|
||||
return implode(' ', $tokens);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits a space separated list of tokens into its constituent parts.
|
||||
*/
|
||||
protected function split($string) {
|
||||
// OPTIMIZABLE!
|
||||
// do the preg_match, capture all subpatterns for reformulation
|
||||
|
||||
@ -24,23 +31,20 @@ class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef
|
||||
// escaping because I don't know how to do that with regexps
|
||||
// and plus it would complicate optimization efforts (you never
|
||||
// see that anyway).
|
||||
$matches = array();
|
||||
$pattern = '/(?:(?<=\s)|\A)'. // look behind for space or string start
|
||||
'((?:--|-?[A-Za-z_])[A-Za-z_\-0-9]*)'.
|
||||
'(?:(?=\s)|\z)/'; // look ahead for space or string end
|
||||
preg_match_all($pattern, $string, $matches);
|
||||
|
||||
if (empty($matches[1])) return false;
|
||||
|
||||
// reconstruct string
|
||||
$new_string = '';
|
||||
foreach ($matches[1] as $token) {
|
||||
$new_string .= $token . ' ';
|
||||
return $matches[1];
|
||||
}
|
||||
$new_string = rtrim($new_string);
|
||||
|
||||
return $new_string;
|
||||
|
||||
/**
|
||||
* Template method for removing certain tokens based on arbitrary criteria.
|
||||
* @note If we wanted to be really functional, we'd do an array_filter
|
||||
* with a callback. But... we're not.
|
||||
*/
|
||||
protected function filter($tokens, $config, $context) {
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,6 +36,9 @@ class HTMLPurifier_AttrTypes
|
||||
$this->info['Charsets'] = new HTMLPurifier_AttrDef_Text();
|
||||
$this->info['Character'] = new HTMLPurifier_AttrDef_Text();
|
||||
|
||||
// "proprietary" types
|
||||
$this->info['Class'] = new HTMLPurifier_AttrDef_HTML_Class();
|
||||
|
||||
// number is really a positive integer (one or more digits)
|
||||
// FIXME: ^^ not always, see start and value of list items
|
||||
$this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true);
|
||||
|
Binary file not shown.
@ -0,0 +1,8 @@
|
||||
Attr.AllowedClasses
|
||||
TYPE: lookup/null
|
||||
VERSION: 4.0.0
|
||||
DEFAULT: null
|
||||
--DESCRIPTION--
|
||||
List of allowed class values in the class attribute. By default, this is null,
|
||||
which means all classes are allowed.
|
||||
--# vim: et sw=4 sts=4
|
@ -0,0 +1,8 @@
|
||||
Attr.ForbiddenClasses
|
||||
TYPE: lookup
|
||||
VERSION: 4.0.0
|
||||
DEFAULT: array()
|
||||
--DESCRIPTION--
|
||||
List of forbidden class values in the class attribute. By default, this is
|
||||
empty, which means that no classes are forbidden. See also %Attr.AllowedClasses.
|
||||
--# vim: et sw=4 sts=4
|
@ -8,7 +8,7 @@ class HTMLPurifier_HTMLModule_CommonAttributes extends HTMLPurifier_HTMLModule
|
||||
'Core' => array(
|
||||
0 => array('Style'),
|
||||
// 'xml:space' => false,
|
||||
'class' => 'NMTOKENS',
|
||||
'class' => 'Class',
|
||||
'id' => 'ID',
|
||||
'title' => 'CDATA',
|
||||
),
|
||||
@ -20,6 +20,7 @@ class HTMLPurifier_HTMLModule_CommonAttributes extends HTMLPurifier_HTMLModule
|
||||
0 => array('Core', 'I18N')
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// vim: et sw=4 sts=4
|
||||
|
21
tests/HTMLPurifier/AttrDef/HTML/ClassTest.php
Normal file
21
tests/HTMLPurifier/AttrDef/HTML/ClassTest.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
class HTMLPurifier_AttrDef_HTML_ClassTest extends HTMLPurifier_AttrDef_HTML_NmtokensTest
|
||||
{
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->def = new HTMLPurifier_AttrDef_HTML_Class();
|
||||
}
|
||||
function testAllowedClasses() {
|
||||
$this->config->set('Attr.AllowedClasses', array('foo'));
|
||||
$this->assertDef('foo');
|
||||
$this->assertDef('bar', false);
|
||||
$this->assertDef('foo bar', 'foo');
|
||||
}
|
||||
function testForbiddenClasses() {
|
||||
$this->config->set('Attr.ForbiddenClasses', array('bar'));
|
||||
$this->assertDef('foo');
|
||||
$this->assertDef('bar', false);
|
||||
$this->assertDef('foo bar', 'foo');
|
||||
}
|
||||
}
|
@ -3,9 +3,12 @@
|
||||
class HTMLPurifier_AttrDef_HTML_NmtokensTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function testDefault() {
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->def = new HTMLPurifier_AttrDef_HTML_Nmtokens();
|
||||
}
|
||||
|
||||
function testDefault() {
|
||||
|
||||
$this->assertDef('valid');
|
||||
$this->assertDef('a0-_');
|
||||
|
Loading…
Reference in New Issue
Block a user