0
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2024-12-23 00:41:52 +00:00

Make forms work for transitional doctypes.

Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
This commit is contained in:
Edward Z. Yang 2011-12-30 22:56:44 +08:00
parent 1bbbc624dd
commit e0354fecd9
9 changed files with 89 additions and 3 deletions

1
NEWS
View File

@ -23,6 +23,7 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
! Implement iframes, and allow them to be used in untrusted mode with ! Implement iframes, and allow them to be used in untrusted mode with
%HTML.SafeIframe and %URI.SafeIframeRegexp. Thanks Bradley M. Froehle %HTML.SafeIframe and %URI.SafeIframeRegexp. Thanks Bradley M. Froehle
<brad.froehle@gmail.com> for submitting an initial version of the patch. <brad.froehle@gmail.com> for submitting an initial version of the patch.
! The Forms module now works properly for transitional doctypes.
- Color keywords are now case insensitive. Thanks Yzmir Ramirez - Color keywords are now case insensitive. Thanks Yzmir Ramirez
<yramirez-htmlpurifier@adicio.com> for reporting. <yramirez-htmlpurifier@adicio.com> for reporting.
- Explicitly initialize anonModule variable to null. - Explicitly initialize anonModule variable to null.

View File

@ -73,6 +73,7 @@ require 'HTMLPurifier/UnitConverter.php';
require 'HTMLPurifier/VarParser.php'; require 'HTMLPurifier/VarParser.php';
require 'HTMLPurifier/VarParserException.php'; require 'HTMLPurifier/VarParserException.php';
require 'HTMLPurifier/AttrDef/CSS.php'; require 'HTMLPurifier/AttrDef/CSS.php';
require 'HTMLPurifier/AttrDef/Clone.php';
require 'HTMLPurifier/AttrDef/Enum.php'; require 'HTMLPurifier/AttrDef/Enum.php';
require 'HTMLPurifier/AttrDef/Integer.php'; require 'HTMLPurifier/AttrDef/Integer.php';
require 'HTMLPurifier/AttrDef/Lang.php'; require 'HTMLPurifier/AttrDef/Lang.php';

View File

@ -67,6 +67,7 @@ require_once $__dir . '/HTMLPurifier/UnitConverter.php';
require_once $__dir . '/HTMLPurifier/VarParser.php'; require_once $__dir . '/HTMLPurifier/VarParser.php';
require_once $__dir . '/HTMLPurifier/VarParserException.php'; require_once $__dir . '/HTMLPurifier/VarParserException.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS.php'; require_once $__dir . '/HTMLPurifier/AttrDef/CSS.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Clone.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Enum.php'; require_once $__dir . '/HTMLPurifier/AttrDef/Enum.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Integer.php'; require_once $__dir . '/HTMLPurifier/AttrDef/Integer.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Lang.php'; require_once $__dir . '/HTMLPurifier/AttrDef/Lang.php';

View File

@ -0,0 +1,28 @@
<?php
/**
* Dummy AttrDef that mimics another AttrDef, BUT it generates clones
* with make.
*/
class HTMLPurifier_AttrDef_Clone extends HTMLPurifier_AttrDef
{
/**
* What we're cloning
*/
protected $clone;
public function __construct($clone) {
$this->clone = $clone;
}
public function validate($v, $config, $context) {
return $this->clone->validate($v, $config, $context);
}
public function make($string) {
return clone $this->clone;
}
}
// vim: et sw=4 sts=4

View File

@ -15,6 +15,13 @@ class HTMLPurifier_AttrTypes
* types. * types.
*/ */
public function __construct() { public function __construct() {
// XXX This is kind of poor, since we don't actually /clone/
// instances; instead, we use the supplied make() attribute. So,
// the underlying class must know how to deal with arguments.
// With the old implementation of Enum, that ignored its
// arguments when handling a make dispatch, the IAlign
// definition wouldn't work.
// pseudo-types, must be instantiated via shorthand // pseudo-types, must be instantiated via shorthand
$this->info['Enum'] = new HTMLPurifier_AttrDef_Enum(); $this->info['Enum'] = new HTMLPurifier_AttrDef_Enum();
$this->info['Bool'] = new HTMLPurifier_AttrDef_HTML_Bool(); $this->info['Bool'] = new HTMLPurifier_AttrDef_HTML_Bool();
@ -29,6 +36,9 @@ class HTMLPurifier_AttrTypes
$this->info['URI'] = new HTMLPurifier_AttrDef_URI(); $this->info['URI'] = new HTMLPurifier_AttrDef_URI();
$this->info['LanguageCode'] = new HTMLPurifier_AttrDef_Lang(); $this->info['LanguageCode'] = new HTMLPurifier_AttrDef_Lang();
$this->info['Color'] = new HTMLPurifier_AttrDef_HTML_Color(); $this->info['Color'] = new HTMLPurifier_AttrDef_HTML_Color();
$this->info['IAlign'] = self::makeEnum('top,middle,bottom,left,right');
$this->info['LAlign'] = self::makeEnum('top,bottom,left,right');
$this->info['FrameTarget'] = new HTMLPurifier_AttrDef_HTML_FrameTarget();
// unimplemented aliases // unimplemented aliases
$this->info['ContentType'] = new HTMLPurifier_AttrDef_Text(); $this->info['ContentType'] = new HTMLPurifier_AttrDef_Text();
@ -44,6 +54,10 @@ class HTMLPurifier_AttrTypes
$this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true); $this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true);
} }
private static function makeEnum($in) {
return new HTMLPurifier_AttrDef_Clone(new HTMLPurifier_AttrDef_Enum(explode(',', $in)));
}
/** /**
* Retrieves a type * Retrieves a type
* @param $type String type name * @param $type String type name

View File

@ -84,7 +84,8 @@ class HTMLPurifier_HTMLModule_Forms extends HTMLPurifier_HTMLModule
$button->excludes = $this->makeLookup( $button->excludes = $this->makeLookup(
'form', 'fieldset', // Form 'form', 'fieldset', // Form
'input', 'select', 'textarea', 'label', 'button', // Formctrl 'input', 'select', 'textarea', 'label', 'button', // Formctrl
'a' // as per HTML 4.01 spec, this is omitted by modularization 'a', // as per HTML 4.01 spec, this is omitted by modularization
'isindex', 'iframe' // legacy items
); );
// Extra exclusion: img usemap="" is not permitted within this element. // Extra exclusion: img usemap="" is not permitted within this element.

View File

@ -89,7 +89,7 @@ class HTMLPurifier_HTMLModule_Legacy extends HTMLPurifier_HTMLModule
$hr->attr['width'] = 'Length'; $hr->attr['width'] = 'Length';
$img = $this->addBlankElement('img'); $img = $this->addBlankElement('img');
$img->attr['align'] = 'Enum#top,middle,bottom,left,right'; $img->attr['align'] = 'IAlign';
$img->attr['border'] = 'Pixels'; $img->attr['border'] = 'Pixels';
$img->attr['hspace'] = 'Pixels'; $img->attr['hspace'] = 'Pixels';
$img->attr['vspace'] = 'Pixels'; $img->attr['vspace'] = 'Pixels';
@ -136,6 +136,22 @@ class HTMLPurifier_HTMLModule_Legacy extends HTMLPurifier_HTMLModule
$ul->attr['compact'] = 'Bool#compact'; $ul->attr['compact'] = 'Bool#compact';
$ul->attr['type'] = 'Enum#square,disc,circle'; $ul->attr['type'] = 'Enum#square,disc,circle';
// "safe" modifications to "unsafe" elements
// WARNING: If you want to add support for an unsafe, legacy
// attribute, make a new TrustedLegacy module with the trusted
// bit set appropriately
$form = $this->addBlankElement('form');
$form->content_model = 'Flow | #PCDATA';
$form->content_model_type = 'optional';
$form->attr['target'] = 'FrameTarget';
$input = $this->addBlankElement('input');
$input->attr['align'] = 'IAlign';
$legend = $this->addBlankElement('legend');
$legend->attr['align'] = 'LAlign';
} }
} }

View File

@ -369,6 +369,13 @@ class HTMLPurifier_HTMLModuleManager
// :TODO: // :TODO:
// non-standalone definitions that don't have a standalone // non-standalone definitions that don't have a standalone
// to merge into could be deferred to the end // to merge into could be deferred to the end
// HOWEVER, it is perfectly valid for a non-standalone
// definition to lack a standalone definition, even
// after all processing: this allows us to safely
// specify extra attributes for elements that may not be
// enabled all in one place. In particular, this might
// be the case for trusted elements. WARNING: care must
// be taken that the /extra/ definitions are all safe.
continue; continue;
} }

View File

@ -7,10 +7,10 @@ class HTMLPurifier_HTMLModule_FormsTest extends HTMLPurifier_HTMLModuleHarness
parent::setUp(); parent::setUp();
$this->config->set('HTML.Trusted', true); $this->config->set('HTML.Trusted', true);
$this->config->set('Attr.EnableID', true); $this->config->set('Attr.EnableID', true);
$this->config->set('Cache.DefinitionImpl', null);
} }
function testBasicUse() { function testBasicUse() {
$this->config->set('HTML.Doctype', 'HTML 4.01 Strict');
$this->assertResult( // need support for label for later $this->assertResult( // need support for label for later
' '
<form action="http://somesite.com/prog/adduser" method="post"> <form action="http://somesite.com/prog/adduser" method="post">
@ -30,6 +30,7 @@ class HTMLPurifier_HTMLModule_FormsTest extends HTMLPurifier_HTMLModuleHarness
} }
function testSelectOption() { function testSelectOption() {
$this->config->set('HTML.Doctype', 'HTML 4.01 Strict');
$this->assertResult(' $this->assertResult('
<form action="http://somesite.com/prog/component-select" method="post"> <form action="http://somesite.com/prog/component-select" method="post">
<p> <p>
@ -49,6 +50,7 @@ class HTMLPurifier_HTMLModule_FormsTest extends HTMLPurifier_HTMLModuleHarness
} }
function testSelectOptgroup() { function testSelectOptgroup() {
$this->config->set('HTML.Doctype', 'HTML 4.01 Strict');
$this->assertResult(' $this->assertResult('
<form action="http://somesite.com/prog/someprog" method="post"> <form action="http://somesite.com/prog/someprog" method="post">
<p> <p>
@ -74,6 +76,7 @@ class HTMLPurifier_HTMLModule_FormsTest extends HTMLPurifier_HTMLModuleHarness
} }
function testTextarea() { function testTextarea() {
$this->config->set('HTML.Doctype', 'HTML 4.01 Strict');
$this->assertResult(' $this->assertResult('
<form action="http://somesite.com/prog/text-read" method="post"> <form action="http://somesite.com/prog/text-read" method="post">
<p> <p>
@ -90,6 +93,7 @@ class HTMLPurifier_HTMLModule_FormsTest extends HTMLPurifier_HTMLModuleHarness
// label tests omitted // label tests omitted
function testFieldset() { function testFieldset() {
$this->config->set('HTML.Doctype', 'HTML 4.01 Strict');
$this->assertResult(' $this->assertResult('
<form action="..." method="post"> <form action="..." method="post">
<fieldset> <fieldset>
@ -122,17 +126,30 @@ class HTMLPurifier_HTMLModule_FormsTest extends HTMLPurifier_HTMLModuleHarness
} }
function testInputTransform() { function testInputTransform() {
$this->config->set('HTML.Doctype', 'XHTML 1.0 Strict');
$this->assertResult('<input type="checkbox" />', '<input type="checkbox" value="" />'); $this->assertResult('<input type="checkbox" />', '<input type="checkbox" value="" />');
} }
function testTextareaTransform() { function testTextareaTransform() {
$this->config->set('HTML.Doctype', 'HTML 4.01 Strict');
$this->assertResult('<textarea></textarea>', '<textarea cols="22" rows="3"></textarea>'); $this->assertResult('<textarea></textarea>', '<textarea cols="22" rows="3"></textarea>');
} }
function testTextInFieldset() { function testTextInFieldset() {
$this->config->set('HTML.Doctype', 'HTML 4.01 Strict');
$this->assertResult('<fieldset> <legend></legend>foo</fieldset>'); $this->assertResult('<fieldset> <legend></legend>foo</fieldset>');
} }
function testStrict() {
$this->config->set('HTML.Doctype', 'HTML 4.01 Strict');
$this->assertResult('<form action=""></form>', '');
}
function testLegacy() {
$this->assertResult('<form action=""></form>');
$this->assertResult('<form action=""><input align="left" /></form>');
}
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4