summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/filter/filter.c4
-rw-r--r--ext/filter/filter_private.h5
-rw-r--r--ext/filter/logical_filters.c87
-rw-r--r--ext/filter/php_filter.h1
-rw-r--r--ext/filter/tests/015.phpt30
-rw-r--r--ext/filter/tests/056.phpt68
6 files changed, 183 insertions, 12 deletions
diff --git a/ext/filter/filter.c b/ext/filter/filter.c
index 530dce6f53..66bcaa94d6 100644
--- a/ext/filter/filter.c
+++ b/ext/filter/filter.c
@@ -44,6 +44,7 @@ static const filter_list_entry filter_list[] = {
{ "float", FILTER_VALIDATE_FLOAT, php_filter_float },
{ "validate_regexp", FILTER_VALIDATE_REGEXP, php_filter_validate_regexp },
+ { "validate_domain", FILTER_VALIDATE_DOMAIN, php_filter_validate_domain },
{ "validate_url", FILTER_VALIDATE_URL, php_filter_validate_url },
{ "validate_email", FILTER_VALIDATE_EMAIL, php_filter_validate_email },
{ "validate_ip", FILTER_VALIDATE_IP, php_filter_validate_ip },
@@ -231,6 +232,7 @@ PHP_MINIT_FUNCTION(filter)
REGISTER_LONG_CONSTANT("FILTER_VALIDATE_FLOAT", FILTER_VALIDATE_FLOAT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("FILTER_VALIDATE_REGEXP", FILTER_VALIDATE_REGEXP, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("FILTER_VALIDATE_DOMAIN", FILTER_VALIDATE_DOMAIN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("FILTER_VALIDATE_URL", FILTER_VALIDATE_URL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("FILTER_VALIDATE_EMAIL", FILTER_VALIDATE_EMAIL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("FILTER_VALIDATE_IP", FILTER_VALIDATE_IP, CONST_CS | CONST_PERSISTENT);
@@ -278,6 +280,8 @@ PHP_MINIT_FUNCTION(filter)
REGISTER_LONG_CONSTANT("FILTER_FLAG_NO_RES_RANGE", FILTER_FLAG_NO_RES_RANGE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("FILTER_FLAG_NO_PRIV_RANGE", FILTER_FLAG_NO_PRIV_RANGE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("FILTER_FLAG_HOSTNAME", FILTER_FLAG_HOSTNAME, CONST_CS | CONST_PERSISTENT);
+
sapi_register_input_filter(php_sapi_filter, php_sapi_filter_init TSRMLS_CC);
return SUCCESS;
diff --git a/ext/filter/filter_private.h b/ext/filter/filter_private.h
index b07b6ca534..8bfbb2df8b 100644
--- a/ext/filter/filter_private.h
+++ b/ext/filter/filter_private.h
@@ -55,6 +55,8 @@
#define FILTER_FLAG_NO_RES_RANGE 0x400000
#define FILTER_FLAG_NO_PRIV_RANGE 0x800000
+#define FILTER_FLAG_HOSTNAME 0x100000
+
#define FILTER_VALIDATE_INT 0x0101
#define FILTER_VALIDATE_BOOLEAN 0x0102
#define FILTER_VALIDATE_FLOAT 0x0103
@@ -64,7 +66,8 @@
#define FILTER_VALIDATE_EMAIL 0x0112
#define FILTER_VALIDATE_IP 0x0113
#define FILTER_VALIDATE_MAC 0x0114
-#define FILTER_VALIDATE_LAST 0x0114
+#define FILTER_VALIDATE_DOMAIN 0x0115
+#define FILTER_VALIDATE_LAST 0x0115
#define FILTER_VALIDATE_ALL 0x0100
diff --git a/ext/filter/logical_filters.c b/ext/filter/logical_filters.c
index be1c2f0d40..01497192f0 100644
--- a/ext/filter/logical_filters.c
+++ b/ext/filter/logical_filters.c
@@ -14,6 +14,7 @@
+----------------------------------------------------------------------+
| Authors: Derick Rethans <derick@php.net> |
| Pierre-A. Joye <pierre@php.net> |
+ | Kévin Dunglas <dunglas@gmail.com> |
+----------------------------------------------------------------------+
*/
@@ -80,6 +81,8 @@
#define FORMAT_IPV4 4
#define FORMAT_IPV6 6
+static int _php_filter_validate_ipv6(char *str, size_t str_len TSRMLS_DC);
+
static int php_filter_parse_int(const char *str, size_t str_len, zend_long *ret TSRMLS_DC) { /* {{{ */
zend_long ctx_value;
int sign = 0, digit = 0;
@@ -452,6 +455,65 @@ void php_filter_validate_regexp(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
RETURN_VALIDATION_FAILED
}
}
+
+static int _php_filter_validate_domain(char * domain, int len, zend_long flags) /* {{{ */
+{
+ char *e, *s, *t;
+ size_t l;
+ int hostname = flags & FILTER_FLAG_HOSTNAME;
+ unsigned char i = 1;
+
+ s = domain;
+ l = len;
+ e = domain + l;
+ t = e - 1;
+
+ /* Ignore trailing dot */
+ if (*t == '.') {
+ e = t;
+ l--;
+ }
+
+ /* The total length cannot exceed 253 characters (final dot not included) */
+ if (l > 253) {
+ return 0;
+ }
+
+ /* First char must be alphanumeric */
+ if(*s == '.' || (hostname && !isalnum((int)*(unsigned char *)s))) {
+ return 0;
+ }
+
+ while (s < e) {
+ if (*s == '.') {
+ /* The first and the last character of a label must be alphanumeric */
+ if (*(s + 1) == '.' || (hostname && (!isalnum((int)*(unsigned char *)(s - 1)) || !isalnum((int)*(unsigned char *)(s + 1))))) {
+ return 0;
+ }
+
+ /* Reset label length counter */
+ i = 1;
+ } else {
+ if (i > 63 || (hostname && *s != '-' && !isalnum((int)*(unsigned char *)s))) {
+ return 0;
+ }
+
+ i++;
+ }
+
+ s++;
+ }
+
+ return 1;
+}
+/* }}} */
+
+void php_filter_validate_domain(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
+{
+ if (!_php_filter_validate_domain(Z_STRVAL_P(value), Z_STRLEN_P(value), flags)) {
+ RETURN_VALIDATION_FAILED
+ }
+}
/* }}} */
void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
@@ -473,25 +535,28 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
}
if (url->scheme != NULL && (!strcasecmp(url->scheme, "http") || !strcasecmp(url->scheme, "https"))) {
- char *e, *s;
+ char *e, *s, *t;
+ size_t l;
if (url->host == NULL) {
goto bad_url;
}
- e = url->host + strlen(url->host);
s = url->host;
-
- /* First char of hostname must be alphanumeric */
- if(!isalnum((int)*(unsigned char *)s)) {
- goto bad_url;
+ l = strlen(s);
+ e = url->host + l;
+ t = e - 1;
+
+ /* An IPv6 enclosed by square brackets is a valid hostname */
+ if (*s == '[' && *t == ']' && _php_filter_validate_ipv6((s + 1), l - 2 TSRMLS_CC)) {
+ php_url_free(url);
+ return;
}
- while (s < e) {
- if (!isalnum((int)*(unsigned char *)s) && *s != '-' && *s != '.') {
- goto bad_url;
- }
- s++;
+ // Validate domain
+ if (!_php_filter_validate_domain(url->host, l, FILTER_FLAG_HOSTNAME)) {
+ php_url_free(url);
+ RETURN_VALIDATION_FAILED
}
}
diff --git a/ext/filter/php_filter.h b/ext/filter/php_filter.h
index 126a0c6c8b..a82b2e6159 100644
--- a/ext/filter/php_filter.h
+++ b/ext/filter/php_filter.h
@@ -75,6 +75,7 @@ void php_filter_int(PHP_INPUT_FILTER_PARAM_DECL);
void php_filter_boolean(PHP_INPUT_FILTER_PARAM_DECL);
void php_filter_float(PHP_INPUT_FILTER_PARAM_DECL);
void php_filter_validate_regexp(PHP_INPUT_FILTER_PARAM_DECL);
+void php_filter_validate_domain(PHP_INPUT_FILTER_PARAM_DECL);
void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL);
void php_filter_validate_email(PHP_INPUT_FILTER_PARAM_DECL);
void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL);
diff --git a/ext/filter/tests/015.phpt b/ext/filter/tests/015.phpt
index 476615ae37..a5d764934a 100644
--- a/ext/filter/tests/015.phpt
+++ b/ext/filter/tests/015.phpt
@@ -11,6 +11,21 @@ $values = Array(
'http://www.example/img/test.png',
'http://www.example/img/dir/',
'http://www.example/img/dir',
+'http://www.thelongestdomainnameintheworldandthensomeandthensomemoreandmore.com/',
+'http://toolongtoolongtoolongtoolongtoolongtoolongtoolongtoolongtoolongtoolong.com',
+'http://eauBcFReEmjLcoZwI0RuONNnwU4H9r151juCaqTI5VeIP5jcYIqhx1lh5vV00l2rTs6y7hOp7rYw42QZiq6VIzjcYrRm8gFRMk9U9Wi1grL8Mr5kLVloYLthHgyA94QK3SaXCATklxgo6XvcbXIqAGG7U0KxTr8hJJU1p2ZQ2mXHmp4DhYP8N9SRuEKzaCPcSIcW7uj21jZqBigsLsNAXEzU8SPXZjmVQVtwQATPWeWyGW4GuJhjP4Q8o0.com',
+'http://kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.CQ1oT5Uq3jJt6Uhy3VH9u3Gi5YhfZCvZVKgLlaXNFhVKB1zJxvunR7SJa.com.',
+'http://[2001:0db8:0000:85a3:0000:0000:ac1f:8001]',
+'http://[2001:db8:0:85a3:0:0:ac1f:8001]:123/me.html',
+'http://[2001:db8:0:85a3::ac1f:8001]/',
+'http://[::1]',
+'http://cont-ains.h-yph-en-s.com',
+'http://..com',
+'http://a.-bc.com',
+'http://ab.cd-.com',
+'http://-.abc.com',
+'http://abc.-.abc.com',
+'http://underscore_.example.com',
'http//www.example/wrong/url/',
'http:/www.example',
'file:///tmp/test.c',
@@ -56,6 +71,21 @@ string(32) "http://www.example.com/index.php"
string(31) "http://www.example/img/test.png"
string(27) "http://www.example/img/dir/"
string(26) "http://www.example/img/dir"
+string(79) "http://www.thelongestdomainnameintheworldandthensomeandthensomemoreandmore.com/"
+bool(false)
+bool(false)
+string(261) "http://kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.CQ1oT5Uq3jJt6Uhy3VH9u3Gi5YhfZCvZVKgLlaXNFhVKB1zJxvunR7SJa.com."
+string(48) "http://[2001:0db8:0000:85a3:0000:0000:ac1f:8001]"
+string(50) "http://[2001:db8:0:85a3:0:0:ac1f:8001]:123/me.html"
+string(36) "http://[2001:db8:0:85a3::ac1f:8001]/"
+string(12) "http://[::1]"
+string(31) "http://cont-ains.h-yph-en-s.com"
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
bool(false)
bool(false)
string(18) "file:///tmp/test.c"
diff --git a/ext/filter/tests/056.phpt b/ext/filter/tests/056.phpt
new file mode 100644
index 0000000000..4a27a9fa10
--- /dev/null
+++ b/ext/filter/tests/056.phpt
@@ -0,0 +1,68 @@
+--TEST--
+filter_var() and FILTER_VALIDATE_DOMAIN
+--SKIPIF--
+<?php if (!extension_loaded("filter")) die("skip"); ?>
+--FILE--
+<?php
+
+$values = Array(
+'example.com',
+'www.thelongestdomainnameintheworldandthensomeandthensomemoreandmore.com',
+'toolongtoolongtoolongtoolongtoolongtoolongtoolongtoolongtoolongtoolong.com',
+'eauBcFReEmjLcoZwI0RuONNnwU4H9r151juCaqTI5VeIP5jcYIqhx1lh5vV00l2rTs6y7hOp7rYw42QZiq6VIzjcYrRm8gFRMk9U9Wi1grL8Mr5kLVloYLthHgyA94QK3SaXCATklxgo6XvcbXIqAGG7U0KxTr8hJJU1p2ZQ2mXHmp4DhYP8N9SRuEKzaCPcSIcW7uj21jZqBigsLsNAXEzU8SPXZjmVQVtwQATPWeWyGW4GuJhjP4Q8o0.com',
+'kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.CQ1oT5Uq3jJt6Uhy3VH9u3Gi5YhfZCvZVKgLlaXNFhVKB1zJxvunR7SJa.com.',
+'cont-ains.h-yph-en-s.com',
+'..com',
+'ab..cc.dd',
+'a.-bc.com',
+'ab.cd-.com',
+'-.abc.com',
+'abc.-.abc.com',
+'underscore_.example.com',
+'',
+-1,
+array(),
+'\r\n',
+);
+foreach ($values as $value) {
+ var_dump(filter_var($value, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME));
+}
+
+var_dump(filter_var('_example.com', FILTER_VALIDATE_DOMAIN));
+var_dump(filter_var('_example.com', FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME));
+var_dump(filter_var('test_.example.com', FILTER_VALIDATE_DOMAIN));
+var_dump(filter_var('test_.example.com', FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME));
+var_dump(filter_var('te_st.example.com', FILTER_VALIDATE_DOMAIN));
+var_dump(filter_var('te_st.example.com', FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME));
+var_dump(filter_var('test._example.com', FILTER_VALIDATE_DOMAIN));
+var_dump(filter_var('test._example.com', FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME));
+
+echo "Done\n";
+?>
+--EXPECT--
+string(11) "example.com"
+string(71) "www.thelongestdomainnameintheworldandthensomeandthensomemoreandmore.com"
+bool(false)
+bool(false)
+string(254) "kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.CQ1oT5Uq3jJt6Uhy3VH9u3Gi5YhfZCvZVKgLlaXNFhVKB1zJxvunR7SJa.com."
+string(24) "cont-ains.h-yph-en-s.com"
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+string(12) "_example.com"
+bool(false)
+string(17) "test_.example.com"
+bool(false)
+string(17) "te_st.example.com"
+bool(false)
+string(17) "test._example.com"
+bool(false)
+Done