aboutsummaryrefslogtreecommitdiffstats
path: root/library/HTMLPurifier/AttrDef/URI
diff options
context:
space:
mode:
Diffstat (limited to 'library/HTMLPurifier/AttrDef/URI')
-rw-r--r--library/HTMLPurifier/AttrDef/URI/Email.php5
-rw-r--r--library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php14
-rw-r--r--library/HTMLPurifier/AttrDef/URI/Host.php104
-rw-r--r--library/HTMLPurifier/AttrDef/URI/IPv4.php28
-rw-r--r--library/HTMLPurifier/AttrDef/URI/IPv6.php106
5 files changed, 165 insertions, 92 deletions
diff --git a/library/HTMLPurifier/AttrDef/URI/Email.php b/library/HTMLPurifier/AttrDef/URI/Email.php
index bfee9d166..daf32b764 100644
--- a/library/HTMLPurifier/AttrDef/URI/Email.php
+++ b/library/HTMLPurifier/AttrDef/URI/Email.php
@@ -5,8 +5,11 @@ abstract class HTMLPurifier_AttrDef_URI_Email extends HTMLPurifier_AttrDef
/**
* Unpacks a mailbox into its display-name and address
+ * @param string $string
+ * @return mixed
*/
- function unpack($string) {
+ public function unpack($string)
+ {
// needs to be implemented
}
diff --git a/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php b/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php
index 94c715ab4..52c0d5968 100644
--- a/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php
+++ b/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php
@@ -7,15 +7,23 @@
class HTMLPurifier_AttrDef_URI_Email_SimpleCheck extends HTMLPurifier_AttrDef_URI_Email
{
- public function validate($string, $config, $context) {
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
// no support for named mailboxes i.e. "Bob <bob@example.com>"
// that needs more percent encoding to be done
- if ($string == '') return false;
+ if ($string == '') {
+ return false;
+ }
$string = trim($string);
$result = preg_match('/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i', $string);
return $result ? $string : false;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/URI/Host.php b/library/HTMLPurifier/AttrDef/URI/Host.php
index 2156c10c6..e7df800b1 100644
--- a/library/HTMLPurifier/AttrDef/URI/Host.php
+++ b/library/HTMLPurifier/AttrDef/URI/Host.php
@@ -7,56 +7,122 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
{
/**
- * Instance of HTMLPurifier_AttrDef_URI_IPv4 sub-validator
+ * IPv4 sub-validator.
+ * @type HTMLPurifier_AttrDef_URI_IPv4
*/
protected $ipv4;
/**
- * Instance of HTMLPurifier_AttrDef_URI_IPv6 sub-validator
+ * IPv6 sub-validator.
+ * @type HTMLPurifier_AttrDef_URI_IPv6
*/
protected $ipv6;
- public function __construct() {
+ public function __construct()
+ {
$this->ipv4 = new HTMLPurifier_AttrDef_URI_IPv4();
$this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6();
}
- public function validate($string, $config, $context) {
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
$length = strlen($string);
- if ($string === '') return '';
- if ($length > 1 && $string[0] === '[' && $string[$length-1] === ']') {
+ // empty hostname is OK; it's usually semantically equivalent:
+ // the default host as defined by a URI scheme is used:
+ //
+ // If the URI scheme defines a default for host, then that
+ // default applies when the host subcomponent is undefined
+ // or when the registered name is empty (zero length).
+ if ($string === '') {
+ return '';
+ }
+ if ($length > 1 && $string[0] === '[' && $string[$length - 1] === ']') {
//IPv6
$ip = substr($string, 1, $length - 2);
$valid = $this->ipv6->validate($ip, $config, $context);
- if ($valid === false) return false;
- return '['. $valid . ']';
+ if ($valid === false) {
+ return false;
+ }
+ return '[' . $valid . ']';
}
// need to do checks on unusual encodings too
$ipv4 = $this->ipv4->validate($string, $config, $context);
- if ($ipv4 !== false) return $ipv4;
+ if ($ipv4 !== false) {
+ return $ipv4;
+ }
// A regular domain name.
- // This breaks I18N domain names, but we don't have proper IRI support,
- // so force users to insert Punycode. If there's complaining we'll
- // try to fix things into an international friendly form.
+ // This doesn't match I18N domain names, but we don't have proper IRI support,
+ // so force users to insert Punycode.
+
+ // There is not a good sense in which underscores should be
+ // allowed, since it's technically not! (And if you go as
+ // far to allow everything as specified by the DNS spec...
+ // well, that's literally everything, modulo some space limits
+ // for the components and the overall name (which, by the way,
+ // we are NOT checking!). So we (arbitrarily) decide this:
+ // let's allow underscores wherever we would have allowed
+ // hyphens, if they are enabled. This is a pretty good match
+ // for browser behavior, for example, a large number of browsers
+ // cannot handle foo_.example.com, but foo_bar.example.com is
+ // fairly well supported.
+ $underscore = $config->get('Core.AllowHostnameUnderscore') ? '_' : '';
// The productions describing this are:
$a = '[a-z]'; // alpha
$an = '[a-z0-9]'; // alphanum
- $and = '[a-z0-9-]'; // alphanum | "-"
+ $and = "[a-z0-9-$underscore]"; // alphanum | "-"
// domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
- $domainlabel = "$an($and*$an)?";
+ $domainlabel = "$an($and*$an)?";
// toplabel = alpha | alpha *( alphanum | "-" ) alphanum
- $toplabel = "$a($and*$an)?";
+ $toplabel = "$a($and*$an)?";
// hostname = *( domainlabel "." ) toplabel [ "." ]
- $match = preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string);
- if (!$match) return false;
+ if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) {
+ 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;
+ }
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/URI/IPv4.php b/library/HTMLPurifier/AttrDef/URI/IPv4.php
index ec4cf591b..30ac16c9e 100644
--- a/library/HTMLPurifier/AttrDef/URI/IPv4.php
+++ b/library/HTMLPurifier/AttrDef/URI/IPv4.php
@@ -8,32 +8,38 @@ class HTMLPurifier_AttrDef_URI_IPv4 extends HTMLPurifier_AttrDef
{
/**
- * IPv4 regex, protected so that IPv6 can reuse it
+ * IPv4 regex, protected so that IPv6 can reuse it.
+ * @type string
*/
protected $ip4;
- public function validate($aIP, $config, $context) {
-
- if (!$this->ip4) $this->_loadRegex();
-
- if (preg_match('#^' . $this->ip4 . '$#s', $aIP))
- {
- return $aIP;
+ /**
+ * @param string $aIP
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($aIP, $config, $context)
+ {
+ if (!$this->ip4) {
+ $this->_loadRegex();
}
+ if (preg_match('#^' . $this->ip4 . '$#s', $aIP)) {
+ return $aIP;
+ }
return false;
-
}
/**
* Lazy load function to prevent regex from being stuffed in
* cache.
*/
- protected function _loadRegex() {
+ protected function _loadRegex()
+ {
$oct = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])'; // 0-255
$this->ip4 = "(?:{$oct}\\.{$oct}\\.{$oct}\\.{$oct})";
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/URI/IPv6.php b/library/HTMLPurifier/AttrDef/URI/IPv6.php
index 9454e9be5..f243793ee 100644
--- a/library/HTMLPurifier/AttrDef/URI/IPv6.php
+++ b/library/HTMLPurifier/AttrDef/URI/IPv6.php
@@ -9,91 +9,81 @@
class HTMLPurifier_AttrDef_URI_IPv6 extends HTMLPurifier_AttrDef_URI_IPv4
{
- public function validate($aIP, $config, $context) {
-
- if (!$this->ip4) $this->_loadRegex();
+ /**
+ * @param string $aIP
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($aIP, $config, $context)
+ {
+ if (!$this->ip4) {
+ $this->_loadRegex();
+ }
$original = $aIP;
$hex = '[0-9a-fA-F]';
$blk = '(?:' . $hex . '{1,4})';
- $pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128
+ $pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128
// prefix check
- if (strpos($aIP, '/') !== false)
- {
- if (preg_match('#' . $pre . '$#s', $aIP, $find))
- {
- $aIP = substr($aIP, 0, 0-strlen($find[0]));
- unset($find);
- }
- else
- {
- return false;
- }
+ if (strpos($aIP, '/') !== false) {
+ if (preg_match('#' . $pre . '$#s', $aIP, $find)) {
+ $aIP = substr($aIP, 0, 0 - strlen($find[0]));
+ unset($find);
+ } else {
+ return false;
+ }
}
// IPv4-compatiblity check
- if (preg_match('#(?<=:'.')' . $this->ip4 . '$#s', $aIP, $find))
- {
- $aIP = substr($aIP, 0, 0-strlen($find[0]));
- $ip = explode('.', $find[0]);
- $ip = array_map('dechex', $ip);
- $aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3];
- unset($find, $ip);
+ if (preg_match('#(?<=:' . ')' . $this->ip4 . '$#s', $aIP, $find)) {
+ $aIP = substr($aIP, 0, 0 - strlen($find[0]));
+ $ip = explode('.', $find[0]);
+ $ip = array_map('dechex', $ip);
+ $aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3];
+ unset($find, $ip);
}
// compression check
$aIP = explode('::', $aIP);
$c = count($aIP);
- if ($c > 2)
- {
+ if ($c > 2) {
+ return false;
+ } elseif ($c == 2) {
+ list($first, $second) = $aIP;
+ $first = explode(':', $first);
+ $second = explode(':', $second);
+
+ if (count($first) + count($second) > 8) {
return false;
- }
- elseif ($c == 2)
- {
- list($first, $second) = $aIP;
- $first = explode(':', $first);
- $second = explode(':', $second);
-
- if (count($first) + count($second) > 8)
- {
- return false;
- }
+ }
- while(count($first) < 8)
- {
- array_push($first, '0');
- }
+ while (count($first) < 8) {
+ array_push($first, '0');
+ }
- array_splice($first, 8 - count($second), 8, $second);
- $aIP = $first;
- unset($first,$second);
- }
- else
- {
- $aIP = explode(':', $aIP[0]);
+ array_splice($first, 8 - count($second), 8, $second);
+ $aIP = $first;
+ unset($first, $second);
+ } else {
+ $aIP = explode(':', $aIP[0]);
}
$c = count($aIP);
- if ($c != 8)
- {
- return false;
+ if ($c != 8) {
+ return false;
}
// All the pieces should be 16-bit hex strings. Are they?
- foreach ($aIP as $piece)
- {
- if (!preg_match('#^[0-9a-fA-F]{4}$#s', sprintf('%04s', $piece)))
- {
- return false;
- }
+ foreach ($aIP as $piece) {
+ if (!preg_match('#^[0-9a-fA-F]{4}$#s', sprintf('%04s', $piece))) {
+ return false;
+ }
}
-
return $original;
-
}
-
}
// vim: et sw=4 sts=4