0
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2024-12-22 08:21:52 +00:00

Optional support for IDNAs with PEAR Net_IDNA2

Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
This commit is contained in:
Edward Z. Yang 2012-01-06 05:28:00 -08:00
parent 94468f3c24
commit 974fe3f25e
9 changed files with 75 additions and 7 deletions

View File

@ -26,6 +26,10 @@ These optional extensions can enhance the capabilities of HTML Purifier:
* bcmath : Used for unit conversion and imagecrash protection * bcmath : Used for unit conversion and imagecrash protection
* tidy : Used for pretty-printing HTML * tidy : Used for pretty-printing HTML
These optional libraries can enhance the capabilities of HTML Purifier:
* CSSTidy : Clean CSS stylesheets using %Core.ExtractStyleBlocks
* Net_IDNA2 (PEAR) : IRI support using %Core.EnableIDNA
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
2. Reconnaissance 2. Reconnaissance

3
NEWS
View File

@ -25,6 +25,9 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
%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. ! The Forms module now works properly for transitional doctypes.
! Added support for internationalized domain names. You need the PEAR
Net_IDNA2 module to be in your path; if it is installed, ensure the
class can be loaded and then set %Core.EnableIDNA to true.
- 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

@ -347,6 +347,11 @@
<line>30</line> <line>30</line>
</file> </file>
</directive> </directive>
<directive id="Core.EnableIDNA">
<file name="HTMLPurifier/AttrDef/URI/Host.php">
<line>67</line>
</file>
</directive>
<directive id="Attr.DefaultTextDir"> <directive id="Attr.DefaultTextDir">
<file name="HTMLPurifier/AttrTransform/BdoDir.php"> <file name="HTMLPurifier/AttrTransform/BdoDir.php">
<line>13</line> <line>13</line>

View File

@ -44,9 +44,8 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
// A regular domain name. // A regular domain name.
// This breaks I18N domain names, but we don't have proper IRI support, // This doesn't match I18N domain names, but we don't have proper IRI support,
// so force users to insert Punycode. If there's complaining we'll // so force users to insert Punycode.
// try to fix things into an international friendly form.
// The productions describing this are: // The productions describing this are:
$a = '[a-z]'; // alpha $a = '[a-z]'; // alpha
@ -57,10 +56,44 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
// toplabel = alpha | alpha *( alphanum | "-" ) alphanum // toplabel = alpha | alpha *( alphanum | "-" ) alphanum
$toplabel = "$a($and*$an)?"; $toplabel = "$a($and*$an)?";
// hostname = *( domainlabel "." ) toplabel [ "." ] // hostname = *( domainlabel "." ) toplabel [ "." ]
$match = preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string); if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) {
if (!$match) return false; return $string;
}
return $string; // If we have Net_IDNA2 support, we can support IRIs by
// punycoding them. (This is the most portable thing to do,
// since otherwise we have to assume browsers support
if ($config->get('Core.EnableIDNA')) {
$idna = new Net_IDNA2(array('encoding' => 'utf8', 'overlong' => false, 'strict' => true));
// we need to encode each period separately
$parts = explode('.', $string);
try {
$new_parts = array();
foreach ($parts as $part) {
$encodable = false;
for ($i = 0, $c = strlen($part); $i < $c; $i++) {
if (ord($part[$i]) > 0x7a) {
$encodable = true;
break;
}
}
if (!$encodable) {
$new_parts[] = $part;
} else {
$new_parts[] = $idna->encode($part);
}
}
$string = implode('.', $new_parts);
if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) {
return $string;
}
} catch (Exception $e) {
// XXX error reporting
}
}
return false;
} }
} }

View File

@ -0,0 +1,9 @@
Core.EnableIDNA
TYPE: bool
DEFAULT: false
VERSION: 4.4.0
--DESCRIPTION--
Allows international domain names in URLs. This configuration option
requires the PEAR Net_IDNA2 module to be installed. It operates by
punycoding any internationalized host names for maximum portability.
--# vim: et sw=4 sts=4

View File

@ -145,7 +145,6 @@ make_dir_standalone('HTMLPurifier/Filter');
make_dir_standalone('HTMLPurifier/Printer'); make_dir_standalone('HTMLPurifier/Printer');
make_file_standalone('HTMLPurifier/Printer.php'); make_file_standalone('HTMLPurifier/Printer.php');
make_file_standalone('HTMLPurifier/Lexer/PH5P.php'); make_file_standalone('HTMLPurifier/Lexer/PH5P.php');
make_file_standalone('HTMLPurifier/Lexer/PEARSax3.php');
echo ' done!' . PHP_EOL; echo ' done!' . PHP_EOL;

View File

@ -69,4 +69,8 @@ $phpv = false;
// to true (or, if it's not in the include path, to its install directory). // to true (or, if it's not in the include path, to its install directory).
$GLOBALS['HTMLPurifierTest']['PEAR'] = false; $GLOBALS['HTMLPurifierTest']['PEAR'] = false;
// If PEAR is enabled, what PEAR tests should be run? (Note: you will
// need to ensure these libraries are installed)
$GLOBALS['HTMLPurifierTest']['Net_IDNA2'] = true;
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@ -35,6 +35,17 @@ class HTMLPurifier_AttrDef_URI_HostTest extends HTMLPurifier_AttrDefHarness
$this->assertDef('f1.top'); $this->assertDef('f1.top');
$this->assertDef('f-.top', false); $this->assertDef('f-.top', false);
$this->assertDef("\xE4\xB8\xAD\xE6\x96\x87.com.cn", false);
}
function testIDNA() {
if (!$GLOBALS['HTMLPurifierTest']['Net_IDNA2']) {
return false;
}
$this->config->set('Core.EnableIDNA', true);
$this->assertDef("\xE4\xB8\xAD\xE6\x96\x87.com.cn", "xn--fiq228c.com.cn");
$this->assertDef("\xe2\x80\x85.com", false); // rejected
} }
} }