mirror of
https://github.com/php/php-src.git
synced 2024-10-21 00:12:34 +00:00
822 lines
18 KiB
C
822 lines
18 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| PHP Version 5 |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 1997-2006 The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Authors: Derick Rethans <derick@php.net> |
|
|
| Pierre-A. Joye <pierre@php.net> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
/* $Id$ */
|
|
|
|
#include "php_filter.h"
|
|
#include "filter_private.h"
|
|
#include "ext/standard/url.h"
|
|
#include "ext/pcre/php_pcre.h"
|
|
|
|
/* {{{ FETCH_LONG_OPTION(var_name, option_name) */
|
|
#define FETCH_LONG_OPTION(var_name, option_name) \
|
|
var_name = 0; \
|
|
var_name##_set = 0; \
|
|
if (option_array) { \
|
|
if (zend_hash_find(HASH_OF(option_array), option_name, sizeof(option_name), (void **) &option_val) == SUCCESS) { \
|
|
convert_to_long(*option_val); \
|
|
var_name = Z_LVAL_PP(option_val); \
|
|
var_name##_set = 1; \
|
|
} \
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ FETCH_STRING_OPTION(var_name, option_name) */
|
|
#define FETCH_STRING_OPTION(var_name, option_name) \
|
|
var_name = NULL; \
|
|
var_name##_set = 0; \
|
|
var_name##_len = 0; \
|
|
if (option_array) { \
|
|
if (zend_hash_find(HASH_OF(option_array), option_name, sizeof(option_name), (void **) &option_val) == SUCCESS) { \
|
|
convert_to_string(*option_val); \
|
|
var_name = Z_STRVAL_PP(option_val); \
|
|
var_name##_set = 1; \
|
|
var_name##_len = Z_STRLEN_PP(option_val); \
|
|
} \
|
|
}
|
|
/* }}} */
|
|
|
|
#define FORMAT_IPV4 4
|
|
#define FORMAT_IPV6 6
|
|
|
|
#define RETURN_VALIDATION_FAILED \
|
|
zval_dtor(value); \
|
|
if (flags & FILTER_NULL_ON_FAILURE) { \
|
|
ZVAL_NULL(value); \
|
|
} else { \
|
|
ZVAL_FALSE(value); \
|
|
} \
|
|
return; \
|
|
|
|
static int php_filter_parse_int(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */
|
|
long ctx_value = 0;
|
|
long sign = 1;
|
|
int error = 0;
|
|
const char *end;
|
|
|
|
end = str + str_len;
|
|
|
|
switch(*str) {
|
|
case '-':
|
|
sign = -1;
|
|
case '+':
|
|
str++;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* must start with 1..9*/
|
|
if (*str >= '1' && *str <= '9') {
|
|
ctx_value += ((*str) - '0');
|
|
str++;
|
|
} else {
|
|
return -1;
|
|
}
|
|
|
|
if (str_len == 1 ) {
|
|
*ret = ctx_value;
|
|
return 1;
|
|
}
|
|
|
|
while (*str) {
|
|
if (*str >= '0' && *str <= '9') {
|
|
ctx_value *= 10;
|
|
ctx_value += ((*str) - '0');
|
|
str++;
|
|
} else {
|
|
error = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* state "tail" */
|
|
if (!error && *str == '\0' && str == end) {
|
|
*ret = ctx_value * sign;
|
|
return 1;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
static int php_filter_parse_octal(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */
|
|
long ctx_value = 0;
|
|
int error = 0;
|
|
|
|
while (*str) {
|
|
if (*str >= '0' && *str <= '7') {
|
|
ctx_value *= 8;
|
|
ctx_value += ((*str) - '0');
|
|
str++;
|
|
} else {
|
|
error = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!error && *str == '\0') {
|
|
*ret = ctx_value;
|
|
return 1;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
static int php_filter_parse_hex(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */
|
|
long ctx_value = 0;
|
|
int error = 0;
|
|
|
|
while (*str) {
|
|
if ((*str >= '0' && *str <= '9') || (*str >= 'a' && *str <= 'f') || (*str >= 'A' && *str <= 'F')) {
|
|
ctx_value *= 16;
|
|
if (*str >= '0' && *str <= '9') {
|
|
ctx_value += ((*str) - '0');
|
|
} else if (*str >= 'a' && *str <= 'f') {
|
|
ctx_value += 10 + ((*str) - 'a');
|
|
} else if (*str >= 'A' && *str <= 'F') {
|
|
ctx_value += 10 + ((*str) - 'A');
|
|
}
|
|
str++;
|
|
} else {
|
|
error = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!error && *str == '\0') {
|
|
*ret = ctx_value;
|
|
return 1;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
void php_filter_int(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
|
|
{
|
|
zval **option_val;
|
|
long min_range, max_range, option_flags;
|
|
int min_range_set, max_range_set;
|
|
int allow_octal = 0, allow_hex = 0;
|
|
int len, error = 0;
|
|
long ctx_value;
|
|
char *p, *start, *end;
|
|
|
|
/* Parse options */
|
|
FETCH_LONG_OPTION(min_range, "min_range");
|
|
FETCH_LONG_OPTION(max_range, "max_range");
|
|
option_flags = flags;
|
|
|
|
len = Z_STRLEN_P(value);
|
|
|
|
if (len == 0) {
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
|
|
if (option_flags & FILTER_FLAG_ALLOW_OCTAL) {
|
|
allow_octal = 1;
|
|
}
|
|
|
|
if (option_flags & FILTER_FLAG_ALLOW_HEX) {
|
|
allow_hex = 1;
|
|
}
|
|
|
|
/* Start the validating loop */
|
|
p = Z_STRVAL_P(value);
|
|
ctx_value = 0;
|
|
|
|
PHP_FILTER_TRIM_DEFAULT(p, len, end);
|
|
|
|
if (*p == '0') {
|
|
p++;
|
|
if (allow_hex && (*p == 'x' || *p == 'X')) {
|
|
p++;
|
|
if (php_filter_parse_hex(p, len, &ctx_value TSRMLS_CC) < 0) {
|
|
error = 1;
|
|
}
|
|
} else if (allow_octal) {
|
|
if (php_filter_parse_octal(p, len, &ctx_value TSRMLS_CC) < 0) {
|
|
error = 1;
|
|
}
|
|
} else if (len != 1) {
|
|
error = 1;
|
|
}
|
|
} else {
|
|
if (php_filter_parse_int(p, len, &ctx_value TSRMLS_CC) < 0) {
|
|
error = 1;
|
|
}
|
|
}
|
|
|
|
if (error > 0 || (min_range_set && (ctx_value < min_range)) || (max_range_set && (ctx_value > max_range))) {
|
|
RETURN_VALIDATION_FAILED
|
|
} else {
|
|
zval_dtor(value);
|
|
Z_TYPE_P(value) = IS_LONG;
|
|
Z_LVAL_P(value) = ctx_value;
|
|
return;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
void php_filter_boolean(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
|
|
{
|
|
char *str = Z_STRVAL_P(value);
|
|
char *start, *end;
|
|
int len = Z_STRLEN_P(value);
|
|
|
|
if (len>0) {
|
|
PHP_FILTER_TRIM_DEFAULT(str, len, end);
|
|
} else {
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
|
|
/* returns true for "1", "true", "on" and "yes"
|
|
* returns false for "0", "false", "off", "no", and ""
|
|
* null otherwise. */
|
|
if ((strncasecmp(str, "true", sizeof("true")) == 0) ||
|
|
(strncasecmp(str, "yes", sizeof("yes")) == 0) ||
|
|
(strncasecmp(str, "on", sizeof("on")) == 0) ||
|
|
(strncmp(str, "1", sizeof("1")) == 0))
|
|
{
|
|
zval_dtor(value);
|
|
ZVAL_BOOL(value, 1);
|
|
} else if ((strncasecmp(str, "false", sizeof("false")) == 0) ||
|
|
(strncasecmp(str, "no", sizeof("no")) == 0) ||
|
|
(strncasecmp(str, "off", sizeof("off")) == 0) ||
|
|
(strncmp(str, "0", sizeof("0")) == 0))
|
|
{
|
|
zval_dtor(value);
|
|
ZVAL_BOOL(value, 0);
|
|
} else {
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
void php_filter_float(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
|
|
{
|
|
int len;
|
|
char *str, *start, *end;
|
|
|
|
zval **option_val;
|
|
char *decimal;
|
|
char dec_sep = '\0';
|
|
|
|
const char default_decimal[] = ".";
|
|
int decimal_set, decimal_len;
|
|
|
|
char tsd_sep[3] = "',.";
|
|
|
|
long options_flag;
|
|
int options_flag_set;
|
|
|
|
int sign = 1;
|
|
|
|
double ret_val = 0;
|
|
double factor;
|
|
|
|
int exp_value = 0, exp_multiply = 1;
|
|
|
|
len = Z_STRLEN_P(value);
|
|
|
|
if (len < 1) {
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
|
|
str = Z_STRVAL_P(value);
|
|
start = str;
|
|
|
|
if (len == 1) {
|
|
if (*str >= '0' && *str <= '9') {
|
|
ret_val = (double)*str - '0';
|
|
} else if (*str == 'E' || *str == 'e') {
|
|
ret_val = 0;
|
|
}
|
|
zval_dtor(value);
|
|
Z_TYPE_P(value) = IS_DOUBLE;
|
|
Z_DVAL_P(value) = ret_val;
|
|
return;
|
|
}
|
|
|
|
FETCH_STRING_OPTION(decimal, "decimal");
|
|
FETCH_LONG_OPTION(options_flag, "flags");
|
|
|
|
if (decimal_set) {
|
|
if (decimal_len > 1) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "decimal separator must be one char");
|
|
} else {
|
|
dec_sep = *decimal;
|
|
}
|
|
} else {
|
|
dec_sep = *default_decimal;
|
|
}
|
|
|
|
PHP_FILTER_TRIM_DEFAULT(str, len, end);
|
|
|
|
if (*str == '-') {
|
|
sign = -1;
|
|
str++;
|
|
start = str;
|
|
} else if (*str == '+') {
|
|
sign = 1;
|
|
str++;
|
|
start = str;
|
|
}
|
|
|
|
ret_val = 0.0;
|
|
|
|
while (*str == '0') {
|
|
str++;
|
|
}
|
|
|
|
if (*str == dec_sep) {
|
|
str++;
|
|
goto stateDot;
|
|
}
|
|
|
|
ret_val = 0;
|
|
|
|
if (str != start) {
|
|
str--;
|
|
}
|
|
|
|
while (*str && *str != dec_sep) {
|
|
if ((options_flag & FILTER_FLAG_ALLOW_THOUSAND) && (*str == tsd_sep[0] || *str == tsd_sep[1] || *str == tsd_sep[2])) {
|
|
str++;
|
|
continue;
|
|
}
|
|
|
|
if (*str == 'e' || *str == 'E') {
|
|
goto stateExp;
|
|
}
|
|
|
|
if (*str < '0' || *str > '9') {
|
|
goto stateError;
|
|
}
|
|
|
|
ret_val *=10; ret_val += (*str - '0');
|
|
str++;
|
|
}
|
|
if (!(*str)) {
|
|
goto stateT;
|
|
}
|
|
str++;
|
|
|
|
stateDot:
|
|
factor = 0.1;
|
|
while (*str) {
|
|
if (*str == 'e' || *str == 'E') {
|
|
goto stateExp;
|
|
}
|
|
|
|
if (*str < '0' || *str > '9') {
|
|
goto stateError;
|
|
}
|
|
|
|
ret_val += factor * (*str - '0');
|
|
factor /= 10;
|
|
str++;
|
|
}
|
|
if (!(*str)) {
|
|
goto stateT;
|
|
}
|
|
|
|
stateExp:
|
|
str++;
|
|
switch (*str) {
|
|
case '-':
|
|
exp_multiply = -1;
|
|
str++;
|
|
break;
|
|
case '+':
|
|
exp_multiply = 1;
|
|
str++;
|
|
}
|
|
|
|
while (*str) {
|
|
if (*str < '0' || *str > '9') {
|
|
goto stateError;
|
|
}
|
|
exp_value *= 10;
|
|
exp_value += ((*str) - '0');
|
|
str++;
|
|
}
|
|
|
|
stateT:
|
|
if ((str -1) != end) {
|
|
goto stateError;
|
|
}
|
|
if (exp_value) {
|
|
exp_value *= exp_multiply;
|
|
ret_val *= pow(10, exp_value);
|
|
}
|
|
|
|
zval_dtor(value);
|
|
Z_TYPE_P(value) = IS_DOUBLE;
|
|
Z_DVAL_P(value) = sign * ret_val;
|
|
return;
|
|
|
|
stateError:
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
/* }}} */
|
|
|
|
void php_filter_validate_regexp(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
|
|
{
|
|
zval **option_val;
|
|
char *regexp;
|
|
int regexp_len;
|
|
long option_flags;
|
|
int regexp_set, option_flags_set;
|
|
|
|
pcre *re = NULL;
|
|
pcre_extra *pcre_extra = NULL;
|
|
int preg_options = 0;
|
|
|
|
int ovector[3];
|
|
int matches;
|
|
|
|
/* Parse options */
|
|
FETCH_STRING_OPTION(regexp, "regexp");
|
|
FETCH_LONG_OPTION(option_flags, "flags");
|
|
|
|
if (!regexp_set) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "'regexp' option missing");
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
|
|
re = pcre_get_compiled_regex(regexp, &pcre_extra, &preg_options TSRMLS_CC);
|
|
if (!re) {
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
matches = pcre_exec(re, NULL, Z_STRVAL_P(value), Z_STRLEN_P(value), 0, 0, ovector, 3);
|
|
|
|
/* 0 means that the vector is too small to hold all the captured substring offsets */
|
|
if (matches < 0) {
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
|
|
{
|
|
php_url *url;
|
|
|
|
/* Use parse_url - if it returns false, we return NULL */
|
|
url = php_url_parse_ex(Z_STRVAL_P(value), Z_STRLEN_P(value));
|
|
|
|
if (url == NULL) {
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
|
|
if (
|
|
((flags & FILTER_FLAG_SCHEME_REQUIRED) && url->scheme == NULL) ||
|
|
((flags & FILTER_FLAG_HOST_REQUIRED) && url->host == NULL) ||
|
|
((flags & FILTER_FLAG_PATH_REQUIRED) && url->path == NULL) ||
|
|
((flags & FILTER_FLAG_QUERY_REQUIRED) && url->query == NULL)
|
|
) {
|
|
php_url_free(url);
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
php_url_free(url);
|
|
}
|
|
/* }}} */
|
|
|
|
void php_filter_validate_email(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
|
|
{
|
|
/* From http://cvs.php.net/co.php/pear/HTML_QuickForm/QuickForm/Rule/Email.php?r=1.4 */
|
|
const char regexp[] = "/^((\\\"[^\\\"\\f\\n\\r\\t\\v\\b]+\\\")|([\\w\\!\\#\\$\\%\\&\\'\\*\\+\\-\\~\\/\\^\\`\\|\\{\\}]+(\\.[\\w\\!\\#\\$\\%\\&\\'\\*\\+\\-\\~\\/\\^\\`\\|\\{\\}]+)*))@((\\[(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))\\])|(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))|((([A-Za-z0-9\\-])+\\.)+[A-Za-z\\-]+))$/";
|
|
|
|
pcre *re = NULL;
|
|
pcre_extra *pcre_extra = NULL;
|
|
int preg_options = 0;
|
|
int ovector[150]; /* Needs to be a multiple of 3 */
|
|
int matches;
|
|
|
|
|
|
re = pcre_get_compiled_regex((char *)regexp, &pcre_extra, &preg_options TSRMLS_CC);
|
|
if (!re) {
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
matches = pcre_exec(re, NULL, Z_STRVAL_P(value), Z_STRLEN_P(value), 0, 0, ovector, 3);
|
|
|
|
/* 0 means that the vector is too small to hold all the captured substring offsets */
|
|
if (matches < 0) {
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
|
|
}
|
|
/* }}} */
|
|
|
|
static int _php_filter_validate_ipv4_count_dots(char *str) /* {{{ */
|
|
{
|
|
char *s1, *s2, *s3, *s4;
|
|
|
|
s1 = strchr(str, '.');
|
|
if (!s1)
|
|
return 0;
|
|
s2 = strchr(s1 + 1, '.');
|
|
if (!s2)
|
|
return 1;
|
|
s3 = strchr(s2 + 1, '.');
|
|
if (!s3)
|
|
return 2;
|
|
s4 = strchr(s3 + 1, '.');
|
|
if (!s4)
|
|
return 3;
|
|
return 4; /* too many */
|
|
}
|
|
/* }}} */
|
|
|
|
static int _php_filter_validate_ipv4_get_nr(char **str) /* {{{ */
|
|
{
|
|
char *begin, *end, *ptr, *tmp_str;
|
|
int tmp_nr = -1;
|
|
|
|
begin = ptr = *str;
|
|
while ((*ptr >= '0') && (*ptr <= '9')) {
|
|
++ptr;
|
|
}
|
|
end = ptr;
|
|
*str = end + 1;
|
|
|
|
if (end == begin) {
|
|
return -1;
|
|
}
|
|
|
|
tmp_str = calloc(1, end - begin + 1);
|
|
memcpy(tmp_str, begin, end - begin);
|
|
tmp_nr = strtol(tmp_str, NULL, 10);
|
|
free(tmp_str);
|
|
|
|
if (tmp_nr < 0 || tmp_nr > 255) {
|
|
tmp_nr = -1;
|
|
}
|
|
return tmp_nr;
|
|
}
|
|
/* }}} */
|
|
|
|
static int _php_filter_validate_ipv4(char *str, int *ip TSRMLS_DC) /* {{{ */
|
|
{
|
|
char *p;
|
|
int x;
|
|
|
|
if (_php_filter_validate_ipv4_count_dots(str) != 3) {
|
|
return 0;
|
|
}
|
|
|
|
p = str;
|
|
for (x = 0; x < 4; ++x) {
|
|
ip[x] = _php_filter_validate_ipv4_get_nr(&p);
|
|
if (ip[x] == -1) {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
/* }}} */
|
|
|
|
#define IS_HEX(s) if (!((s >= '0' && s <= '9') || (s >= 'a' && s <= 'f') ||(s >= 'A' && s <= 'F'))) { \
|
|
return 0; \
|
|
}
|
|
|
|
#define IPV6_LOOP_IN(str) \
|
|
if (*str == ':') { \
|
|
if (hexcode_found > 4) { \
|
|
return -134; \
|
|
} \
|
|
hexcode_found = 0; \
|
|
col_fnd++; \
|
|
} else { \
|
|
IS_HEX(*str); \
|
|
hexcode_found++; \
|
|
}
|
|
|
|
static int _php_filter_validate_ipv6_(char *str TSRMLS_DC) /* {{{ */
|
|
{
|
|
int hexcode_found = 0;
|
|
int compressed_2end = 0;
|
|
int col_fnd = 0;
|
|
char *start = str;
|
|
char *compressed = NULL, *t = str;
|
|
char *s2 = NULL, *ipv4=NULL;
|
|
int ip4elm[4];
|
|
|
|
if (!strchr(str, ':')) {
|
|
return 0;
|
|
}
|
|
|
|
/* Check for compressed expression. only one is allowed */
|
|
compressed = strstr(str, "::");
|
|
if (compressed) {
|
|
s2 = strstr(compressed+1, "::");
|
|
if (s2) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* check for bundled IPv4 */
|
|
ipv4 = strchr(str, '.');
|
|
|
|
if (ipv4) {
|
|
while (*ipv4 != ':' && ipv4 >= start) {
|
|
ipv4--;
|
|
}
|
|
|
|
/* ::w.x.y.z */
|
|
if (compressed && ipv4 == (compressed + 1)) {
|
|
compressed_2end = 1;
|
|
}
|
|
ipv4++;
|
|
|
|
if (!_php_filter_validate_ipv4(ipv4, ip4elm TSRMLS_CC)) {
|
|
return 0;
|
|
}
|
|
|
|
if (compressed_2end) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (!compressed) {
|
|
char *end;
|
|
if (ipv4) {
|
|
end = ipv4 - 1;
|
|
} else {
|
|
end = str + strlen(start);
|
|
}
|
|
|
|
while (*str && str <= end) {
|
|
IPV6_LOOP_IN(str);
|
|
str++;
|
|
}
|
|
|
|
if (!ipv4) {
|
|
if (col_fnd != 7) {
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
} else {
|
|
if (col_fnd != 6) {
|
|
return -1230;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
} else {
|
|
if (!ipv4) {
|
|
t = compressed - 1;
|
|
while (t >= start) {
|
|
IPV6_LOOP_IN(t);
|
|
t--;
|
|
}
|
|
|
|
if (hexcode_found > 4) {
|
|
return 0;
|
|
}
|
|
|
|
t = compressed + 2;
|
|
hexcode_found = 0;
|
|
while (*t) {
|
|
IPV6_LOOP_IN(t);
|
|
t++;
|
|
}
|
|
|
|
if (hexcode_found > 4) {
|
|
return 0;
|
|
}
|
|
|
|
if (col_fnd > 6) {
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
} else {
|
|
/* ipv4 part always at the end */
|
|
t = ipv4 - 1;
|
|
while (t >= (compressed + 2)) {
|
|
IPV6_LOOP_IN(t);
|
|
t--;
|
|
}
|
|
|
|
if (hexcode_found > 4) {
|
|
return 0;
|
|
}
|
|
|
|
hexcode_found = 0;
|
|
t = compressed - 1;
|
|
while (t >= start) {
|
|
IPV6_LOOP_IN(t);
|
|
t--;
|
|
}
|
|
if (hexcode_found > 4) {
|
|
return 0;
|
|
}
|
|
|
|
if (col_fnd > 6) {
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
/* }}} */
|
|
|
|
void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
|
|
{
|
|
/* validates an ipv4 or ipv6 IP, based on the flag (4, 6, or both) add a
|
|
* flag to throw out reserved ranges; multicast ranges... etc. If both
|
|
* allow_ipv4 and allow_ipv6 flags flag are used, then the first dot or
|
|
* colon determine the format */
|
|
|
|
char *str = NULL;
|
|
int ip[4];
|
|
int mode;
|
|
|
|
str = Z_STRVAL_P(value);
|
|
|
|
if (strchr(str, ':')) {
|
|
mode = FORMAT_IPV6;
|
|
} else if (strchr(str, '.')) {
|
|
mode = FORMAT_IPV4;
|
|
} else {
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
|
|
if (flags & (FILTER_FLAG_IPV4 || FILTER_FLAG_IPV6)) {
|
|
/* Both formats are cool */
|
|
} else if ((flags & FILTER_FLAG_IPV4) && mode == FORMAT_IPV6) {
|
|
RETURN_VALIDATION_FAILED
|
|
} else if ((flags & FILTER_FLAG_IPV6) && mode == FORMAT_IPV4) {
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
|
|
switch (mode) {
|
|
case FORMAT_IPV4:
|
|
if (!_php_filter_validate_ipv4(str, ip TSRMLS_CC)) {
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
|
|
/* Check flags */
|
|
if (flags & FILTER_FLAG_NO_PRIV_RANGE) {
|
|
if (
|
|
(ip[0] == 10) ||
|
|
(ip[0] == 172 && (ip[1] >= 16 && ip[1] <= 31)) ||
|
|
(ip[0] == 192 && ip[1] == 168)
|
|
) {
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
}
|
|
|
|
if (flags & FILTER_FLAG_NO_RES_RANGE) {
|
|
if (
|
|
(ip[0] == 0) ||
|
|
(ip[0] == 169 && ip[1] == 254) ||
|
|
(ip[0] == 192 && ip[1] == 0 && ip[2] == 2) ||
|
|
(ip[0] >= 224 && ip[0] <= 255)
|
|
) {
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
}
|
|
break;
|
|
|
|
case FORMAT_IPV6:
|
|
{
|
|
int res = 0;
|
|
res = _php_filter_validate_ipv6_(str TSRMLS_CC);
|
|
if (res < 1) {
|
|
RETURN_VALIDATION_FAILED
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/*
|
|
* Local variables:
|
|
* tab-width: 4
|
|
* c-basic-offset: 4
|
|
* End:
|
|
* vim600: noet sw=4 ts=4 fdm=marker
|
|
* vim<600: noet sw=4 ts=4
|
|
*/
|