Skip to content

Commit

Permalink
Add HTML5-compatible Legacy module
Browse files Browse the repository at this point in the history
  • Loading branch information
xemlock committed May 30, 2020
1 parent 6a38dca commit d963677
Show file tree
Hide file tree
Showing 8 changed files with 236 additions and 5 deletions.
28 changes: 28 additions & 0 deletions library/HTMLPurifier/AttrTransform/HTML5/FrameBorder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

/**
* Pre-transform that changes deprecated IFRAME frameborder attribute to CSS.
*/
class HTMLPurifier_AttrTransform_HTML5_FrameBorder extends HTMLPurifier_AttrTransform
{
/**
* @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (!isset($attr['frameborder'])) {
return $attr;
}

$frameBorder = (int) $this->confiscateAttr($attr, 'frameborder');

if ($frameBorder === 0) {
$this->prependCSS($attr, 'border:0;');
}

return $attr;
}
}
2 changes: 1 addition & 1 deletion library/HTMLPurifier/HTML5Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public function getDefinition($type, $raw = false, $optimized = false)
if ($needSetup) {
if ($def = parent::getDefinition($type, true, true)) {
/** @var HTMLPurifier_HTMLDefinition $def */
HTMLPurifier_HTML5Definition::setupDefinition($def);
HTMLPurifier_HTML5Definition::setupDefinition($def, $this);
}
}
return parent::getDefinition($type, $raw, $optimized);
Expand Down
10 changes: 6 additions & 4 deletions library/HTMLPurifier/HTML5Definition.php
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<?php

class HTMLPurifier_HTML5Definition
abstract class HTMLPurifier_HTML5Definition
{
/**
* Adds HTML5 element and attributes to a provided definition object.
*
* @param HTMLPurifier_HTMLDefinition $def
* @param HTMLPurifier_Config $config
* @return HTMLPurifier_HTMLDefinition
* @throws HTMLPurifier_Exception
*/
public static function setupDefinition(HTMLPurifier_HTMLDefinition $def)
public static function setupDefinition(HTMLPurifier_HTMLDefinition $def, HTMLPurifier_Config $config)
{
$def->manager->doctypes->register(
'HTML5',
Expand All @@ -24,8 +24,10 @@ public static function setupDefinition(HTMLPurifier_HTMLDefinition $def)
// Unsafe:
'HTML5_Scripting', 'HTML5_Interactive', 'Object', 'HTML5_Forms',
'HTML5_Iframe',
// Transitional:
'HTML5_Legacy',
),
array('Tidy_Transitional', 'Tidy_Proprietary'),
array('Tidy_HTML5'),
array()
);

Expand Down
137 changes: 137 additions & 0 deletions library/HTMLPurifier/HTMLModule/HTML5/Legacy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<?php

/**
* Legacy module defines elements that were obsoleted / deprecated in HTML5
* but are still supported by browsers.
*
* This module requires Tidy module to be enabled to avoid invalid HTML5 output.
* It provides definitions for obsolete attributes and elements that have fixes
* defined in Tidy_HTML5 module.
*/
class HTMLPurifier_HTMLModule_HTML5_Legacy extends HTMLPurifier_HTMLModule
{
/**
* @type string
*/
public $name = 'HTML5_Legacy';

/**
* @param HTMLPurifier_Config $config
*/
public function setup($config)
{
// Setup additional obsolete / deprecated elements

// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/basefont
$this->addElement(
'basefont',
'Inline',
'Empty',
null,
array(
'color' => 'Color',
'face' => 'Text', // extremely broad, we should
'size' => 'Text', // tighten it
'id' => 'ID'
)
);

// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/center
$this->addElement('center', 'Block', 'Flow', 'Common');

// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dir
$this->addElement('dir', 'Block', 'Required: li', 'Common');

// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/font
$this->addElement(
'font',
'Inline',
'Inline',
array('Core', 'I18N'),
array(
'color' => 'Color',
'face' => 'Text', // extremely broad, we should
'size' => 'Text', // tighten it
)
);

// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menu
$this->addElement('menu', 'Block', 'Required: li', 'Common');

$strike = $this->addElement('strike', 'Inline', 'Inline', 'Common');
$strike->formatting = true;

// Setup modifications to old elements

$align = 'Enum#left,right,center,justify';

$br = $this->addBlankElement('br');
$br->attr['clear'] = 'Enum#all,left,right,none';

$caption = $this->addBlankElement('caption');
$caption->attr['align'] = 'Enum#top,bottom,left,right';

$div = $this->addBlankElement('div');
$div->attr['align'] = $align;

for ($i = 1; $i <= 6; $i++) {
$h = $this->addBlankElement("h$i");
$h->attr['align'] = $align;
}

$hr = $this->addBlankElement('hr');
$hr->attr['align'] = $align;
$hr->attr['noshade'] = 'Bool#noshade';
$hr->attr['size'] = 'Pixels';
$hr->attr['width'] = 'Length';

$img = $this->addBlankElement('img');
$img->attr['align'] = 'IAlign';
$img->attr['border'] = 'Pixels';
$img->attr['hspace'] = 'Pixels';
$img->attr['vspace'] = 'Pixels';

$li = $this->addBlankElement('li');
$li->attr['value'] = new HTMLPurifier_AttrDef_Integer();
$li->attr['type'] = 'Enum#s:1,i,I,a,A,circle,disc,square';

$p = $this->addBlankElement('p');
$p->attr['align'] = $align;

$pre = $this->addBlankElement('pre');
$pre->attr['width'] = 'Number';

$table = $this->addBlankElement('table');
$table->attr['align'] = 'Enum#left,center,right';
$table->attr['bgcolor'] = 'Color';

$tr = $this->addBlankElement('tr');
$tr->attr['bgcolor'] = 'Color';

$th = $this->addBlankElement('th');
$th->attr['bgcolor'] = 'Color';
$th->attr['height'] = 'Length';
$th->attr['nowrap'] = 'Bool#nowrap';
$th->attr['width'] = 'Length';

$td = $this->addBlankElement('td');
$td->attr['bgcolor'] = 'Color';
$td->attr['height'] = 'Length';
$td->attr['nowrap'] = 'Bool#nowrap';
$td->attr['width'] = 'Length';

$ul = $this->addBlankElement('ul');
$ul->attr['type'] = 'Enum#circle,disc,square';

// Setup modifications to "unsafe" elements

$iframe = $this->addBlankElement('iframe');
$iframe->attr['frameborder'] = 'Enum#0,1';

$input = $this->addBlankElement('input');
$input->attr['align'] = 'IAlign';

$legend = $this->addBlankElement('legend');
$legend->attr['align'] = 'LAlign';
}
}
3 changes: 3 additions & 0 deletions library/HTMLPurifier/HTMLModule/HTML5/List.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,8 @@ public function setup($config)
// Attributes that were deprecated in HTML4, but reintroduced in HTML5
$ol->attr['start'] = new HTMLPurifier_AttrDef_Integer();
$ol->attr['type'] = 'Enum#s:1,a,A,i,I';

$li = $this->info['li'];
$li->attr['value'] = new HTMLPurifier_AttrDef_Integer();
}
}
35 changes: 35 additions & 0 deletions library/HTMLPurifier/HTMLModule/Tidy/HTML5.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

class HTMLPurifier_HTMLModule_Tidy_HTML5 extends HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4
{
public $name = 'Tidy_HTML5';

/**
* This is the lenient level. If a tag or attribute is about to be removed
* because it isn't supported by the doctype, Tidy will step in and change
* into an alternative that is supported.
* @var string
*/
public $defaultLevel = 'light';

/**
* @return array
*/
public function makeFixes()
{
$fixes = parent::makeFixes();

// Remove transforms for valid HTML5 elements
unset(
$fixes['u'],
$fixes['s'],
$fixes['ol@type']
);

$fixes['strike'] = new HTMLPurifier_TagTransform_Simple('del');

$fixes['iframe@frameborder'] = new HTMLPurifier_AttrTransform_HTML5_FrameBorder();

return $fixes;
}
}
5 changes: 5 additions & 0 deletions tests/HTMLPurifier/HTMLModule/HTML5/ListTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,9 @@ public function olInput()
),
);
}

public function testLi()
{
$this->assertPurification('<ul><li value="2">Foo</li></ul>');
}
}
21 changes: 21 additions & 0 deletions tests/HTMLPurifier/HTMLModule/Tidy/HTML5Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

class HTMLPurifier_HTMLModule_Tidy_HTML5Test extends BaseTestCase
{
public function testIframe()
{
$this->config->set('HTML.TidyLevel', 'light');
$this->config->set('HTML.SafeIframe', true);
$this->config->set('URI.SafeIframeRegexp', '/^foo$/');

$this->assertPurification(
'<iframe width="640" height="360" src="foo" frameborder="0"></iframe>',
'<iframe width="640" height="360" src="foo" style="border:0;"></iframe>'
);

$this->assertPurification(
'<iframe width="640" height="360" src="foo" frameborder="1"></iframe>',
'<iframe width="640" height="360" src="foo"></iframe>'
);
}
}

0 comments on commit d963677

Please sign in to comment.