Index: php5-5.2.0/ext/filter/logical_filters.c
===================================================================
--- php5-5.2.0.orig/ext/filter/logical_filters.c	2007-04-23 20:22:47.000000000 +0200
+++ php5-5.2.0/ext/filter/logical_filters.c	2007-04-23 20:22:47.000000000 +0200
@@ -17,21 +17,33 @@
   +----------------------------------------------------------------------+
 */
 
-/* $Id: logical_filters.c,v 1.1.2.11 2006/10/17 15:26:14 iliaa Exp $ */
+/* $Id: logical_filters.c,v 1.1.2.18 2006/12/26 09:16:24 dmitry Exp $ */
 
 #include "php_filter.h"
 #include "filter_private.h"
 #include "ext/standard/url.h"
 #include "ext/pcre/php_pcre.h"
 
+#include "zend_multiply.h"
+
+#if HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#define LONG_SIGN_MASK (1L << (8*sizeof(long)-1))
+
+#ifndef INADDR_NONE
+# define INADDR_NONE ((unsigned long int) -1)
+#endif
+
+
 /* {{{ 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);                                                                            \
+			PHP_FILTER_GET_LONG_OPT(option_val, var_name);								\
 			var_name##_set = 1;                                                                                          \
 		}                                                                                                                \
 	}
@@ -44,10 +56,11 @@
 	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);                                                                    \
+			if (Z_TYPE_PP(option_val) == IS_STRING) {                                                                    \
+				var_name = Z_STRVAL_PP(option_val);                                                                      \
+				var_name##_len = Z_STRLEN_PP(option_val);                                                                \
+				var_name##_set = 1;                                                                                      \
+			}                                                                                                            \
 		}                                                                                                                \
 	}
 /* }}} */
@@ -55,24 +68,14 @@
 #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 ctx_value;
 	long sign = 1;
-	int error = 0;
-	const char *end;
+	const char *end = str + str_len;
+	double dval;
+	long overflow;
 
-	end = str + str_len;
-
-	switch(*str) {
+	switch (*str) {
 		case '-':
 			sign = -1;
 		case '+':
@@ -82,88 +85,79 @@
 	}
 
 	/* must start with 1..9*/
-	if (*str >= '1' && *str <= '9') {
-		ctx_value += ((*str) - '0');
-		str++;
+	if (str < end && *str >= '1' && *str <= '9') {
+		ctx_value = ((*(str++)) - '0');
 	} else {
 		return -1;
 	}
 
-	if (str_len == 1 ) {
-		*ret = ctx_value;
-		return 1;
-	}
-
-	while (*str) {
+	while (str < end) {
 		if (*str >= '0' && *str <= '9') {
-			ctx_value *= 10;
-		   	ctx_value += ((*str) - '0');
-		   	str++;
+			ZEND_SIGNED_MULTIPLY_LONG(ctx_value, 10, ctx_value, dval, overflow);
+			if (overflow) {
+				return -1;
+			}
+			ctx_value += ((*(str++)) - '0');
+			if (ctx_value & LONG_SIGN_MASK) {
+				return -1;
+			}
 		} else {
-			error = 1;
-			break;
+			return -1;
 		}
 	}
 
-	/* state "tail" */
-	if (!error && *str == '\0' && str == end) {
-		*ret = ctx_value * sign;
-		return 1;
-	} else {
-		return -1;
-	}
+	*ret = ctx_value * sign;
+	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;
+	unsigned long ctx_value = 0;
+	const char *end = str + str_len;
 
-	while (*str) {
+	while (str < end) {
 		if (*str >= '0' && *str <= '7') {
-			ctx_value *= 8;
-			ctx_value += ((*str) - '0');
-			str++;
+			unsigned long n = ((*(str++)) - '0');
+
+			if ((ctx_value > ((unsigned long)(~(long)0)) / 8) ||
+				((ctx_value = ctx_value * 8) > ((unsigned long)(~(long)0)) - n)) {
+				return -1;
+			}
+			ctx_value += n;
 		} else {
-			error = 1;
-			break;
+			return -1;
 		}
 	}
-	if (!error && *str == '\0') {
-		*ret = ctx_value;
-		return 1;
-	} else {
-		return -1;
-	}
+	
+	*ret = (long)ctx_value;
+	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;
+	unsigned long ctx_value = 0;
+	const char *end = str + str_len;
+	unsigned long n;
 
-	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++;
+	while (str < end) {
+		if (*str >= '0' && *str <= '9') {
+			n = ((*(str++)) - '0');
+		} else if (*str >= 'a' && *str <= 'f') {
+			n = ((*(str++)) - ('a' - 10));
+		} else if (*str >= 'A' && *str <= 'F') {
+			n = ((*(str++)) - ('A' - 10));
 		} else {
-			error = 1;
-			break;
+			return -1;
 		}
+		if ((ctx_value > ((unsigned long)(~(long)0)) / 16) ||
+			((ctx_value = ctx_value * 16) > ((unsigned long)(~(long)0)) - n)) {
+			return -1;
+		}
+		ctx_value += n;
 	}
-	if (!error && *str == '\0') {
-		*ret = ctx_value;
-		return 1;
-	} else {
-		return -1;
-	}
+
+	*ret = (long)ctx_value;
+	return 1;
 }
 /* }}} */
 
@@ -175,7 +169,7 @@
 	int    allow_octal = 0, allow_hex = 0;
 	int	   len, error = 0;
 	long   ctx_value;
-	char *p, *start, *end;
+	char *p;
 
 	/* Parse options */
 	FETCH_LONG_OPTION(min_range,    "min_range");
@@ -200,12 +194,12 @@
 	p = Z_STRVAL_P(value);
 	ctx_value = 0;
 
-	PHP_FILTER_TRIM_DEFAULT(p, len, end);
+	PHP_FILTER_TRIM_DEFAULT(p, len);
 
 	if (*p == '0') {
-		p++;
+		p++; len--;
 		if (allow_hex && (*p == 'x' || *p == 'X')) {
-			p++;
+			p++; len--;
 			if (php_filter_parse_hex(p, len, &ctx_value TSRMLS_CC) < 0) {
 				error = 1;
 			}
@@ -213,7 +207,7 @@
 			if (php_filter_parse_octal(p, len, &ctx_value TSRMLS_CC) < 0) {
 				error = 1;
 			}
-		} else if (len != 1) {
+		} else if (len != 0) {
 			error = 1;
 		}
 	} else {
@@ -236,34 +230,65 @@
 void php_filter_boolean(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
 {
 	char *str = Z_STRVAL_P(value);
-	char *start, *end;
 	int len = Z_STRLEN_P(value);
+	int ret;
 
-	if (len>0) {
-		PHP_FILTER_TRIM_DEFAULT(str, len, end);
-	} else {
-		RETURN_VALIDATION_FAILED
-	}
+	PHP_FILTER_TRIM_DEFAULT(str, len);
 
 	/* 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 {
+	switch (len) {
+		case 1:
+			if (*str == '1') {
+				ret = 1;
+			} else if (*str == '0') {
+				ret = 0;
+			} else {
+				ret = -1;
+			}
+			break;
+		case 2:
+			if (strncasecmp(str, "on", 2) == 0) {
+				ret = 1;
+			} else if (strncasecmp(str, "no", 2) == 0) {
+				ret = 0;
+			} else {
+				ret = -1;
+			}
+			break;
+		case 3:
+			if (strncasecmp(str, "yes", 3) == 0) {
+				ret = 1;
+			} else if (strncasecmp(str, "off", 3) == 0) {
+				ret = 0;
+			} else {
+				ret = -1;
+			}
+			break;
+		case 4:
+			if (strncasecmp(str, "true", 4) == 0) {
+				ret = 1;
+			} else {
+				ret = -1;
+			}
+			break;
+		case 5:
+			if (strncasecmp(str, "false", 5) == 0) {
+				ret = 0;
+			} else {
+				ret = -1;
+			}
+			break;
+		default:
+			ret = -1;
+	}
+
+	if (ret == -1) {	
 		RETURN_VALIDATION_FAILED
+	} else {
+		zval_dtor(value);
+		ZVAL_BOOL(value, ret);
 	}
 }
 /* }}} */
@@ -271,168 +296,102 @@
 void php_filter_float(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
 {
 	int len;
-	char *str, *start, *end;
+	char *str, *end;
+	char *num, *p;
 
 	zval **option_val;
 	char *decimal;
-	char dec_sep = '\0';
-
-	const char default_decimal[] = ".";
 	int decimal_set, decimal_len;
-
+	char dec_sep = '.';
 	char tsd_sep[3] = "',.";
 
-	long options_flag;
-	int options_flag_set;
-
-	int sign = 1;
+	long lval;
+	double dval;
 
-	double ret_val = 0;
-	double factor;
-
-	int exp_value = 0, exp_multiply = 1;
+	int first, n;
 
 	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;
-	}
+	PHP_FILTER_TRIM_DEFAULT(str, len);
+	end = str + len;
 
 	FETCH_STRING_OPTION(decimal, "decimal");
-	FETCH_LONG_OPTION(options_flag, "flags");
 
 	if (decimal_set) {
-		if (decimal_len > 1) {
+		if (decimal_len != 1) {
 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "decimal separator must be one char");
+			RETURN_VALIDATION_FAILED
 		} 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;
+	num = p = emalloc(len+1);
+	if (str < end && (*str == '+' || *str == '-')) {
+		*p++ = *str++;
+	}
+	first = 1;
+	while (1) {
+		n = 0;
+		while (str < end && *str >= '0' && *str <= '9') {
+			++n;
+			*p++ = *str++;
+		}
+		if (str == end || *str == dec_sep || *str == 'e' || *str == 'E') {
+			if (!first && n != 3) {
+				goto error;
+			}
+			if (*str == dec_sep) {
+				*p++ = '.';
+				str++;
+				while (str < end && *str >= '0' && *str <= '9') {
+					*p++ = *str++;
+				}
+			}
+			if (*str == 'e' || *str == 'E') {
+				*p++ = *str++;
+				if (str < end && (*str == '+' || *str == '-')) {
+					*p++ = *str++;
+				}
+				while (str < end && *str >= '0' && *str <= '9') {
+					*p++ = *str++;
+				}
+			}
+			break;
 		}
-
-		if (*str < '0' || *str > '9') {
-			goto stateError;
+		if ((flags & FILTER_FLAG_ALLOW_THOUSAND) && (*str == tsd_sep[0] || *str == tsd_sep[1] || *str == tsd_sep[2])) {
+			if (first?(n < 1 || n > 3):(n != 3)) {
+				goto error;
+			}
+			first = 0;
+			str++;
+		} else {
+			goto error;
 		}
-
-		ret_val += factor * (*str - '0');
-		factor /= 10;
-		str++;
 	}
-	if (!(*str)) {
-		goto stateT;
+	if (str != end) {
+		goto error;
 	}
+	*p = 0;
 
-stateExp:
-	str++;
-	switch (*str) {
-		case '-':
-			exp_multiply = -1;
-			str++;
+	switch (is_numeric_string(num, p - num, &lval, &dval, 0)) {
+		case IS_LONG:
+			zval_dtor(value);
+			Z_TYPE_P(value) = IS_DOUBLE;
+			Z_DVAL_P(value) = lval;
 			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);
+		case IS_DOUBLE:
+			zval_dtor(value);
+			Z_TYPE_P(value) = IS_DOUBLE;
+			Z_DVAL_P(value) = dval;
+			break;
+		default:
+error:
+			efree(num);
+			RETURN_VALIDATION_FAILED
 	}
-
-	zval_dtor(value);
-	Z_TYPE_P(value) = IS_DOUBLE;
-	Z_DVAL_P(value) = sign * ret_val;
-	return;
-
-stateError:
-	RETURN_VALIDATION_FAILED
+	efree(num);	
 }
 /* }}} */
 
@@ -476,6 +435,13 @@
 void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
 {
 	php_url *url;
+	int old_len = Z_STRLEN_P(value);
+	
+	php_filter_url(value, flags, option_array, charset TSRMLS_CC);
+
+	if (Z_TYPE_P(value) != IS_STRING || old_len != Z_STRLEN_P(value)) {
+		RETURN_VALIDATION_FAILED
+	}
 
 	/* Use parse_url - if it returns false, we return NULL */
 	url = php_url_parse_ex(Z_STRVAL_P(value), Z_STRLEN_P(value));
@@ -485,10 +451,10 @@
 	}
 
 	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)
+		url->scheme == NULL || 
+		/* some schemas allow the host to be empty */
+		(url->host == NULL && (strcmp(url->scheme, "mailto") && strcmp(url->scheme, "news") && strcmp(url->scheme, "file"))) ||
+		((flags & FILTER_FLAG_PATH_REQUIRED) && url->path == NULL) || ((flags & FILTER_FLAG_QUERY_REQUIRED) && url->query == NULL)
 	) {
 		php_url_free(url);
 		RETURN_VALIDATION_FAILED
@@ -500,7 +466,7 @@
 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\\-]+))$/D";
+	const char regexp[] = "/^((\\\"[^\\\"\\f\\n\\r\\t\\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\\-]+))$/D";
 
 	pcre       *re = NULL;
 	pcre_extra *pcre_extra = NULL;
@@ -523,220 +489,97 @@
 }
 /* }}} */
 
-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) /* {{{ */
+static int _php_filter_validate_ipv4(char *str, int str_len, int *ip) /* {{{ */
 {
-	char *p;
-	int x;
+	const char *end = str + str_len;
+	int num, m;
+	int n = 0;
 
-	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) {
+	while (str < end) {
+		if (*str < '0' || *str > '9') {
+			return 0;
+		}
+		m = 1;
+		num = ((*(str++)) - '0');
+		while (str < end && (*str >= '0' && *str <= '9')) {
+			num = num * 10 + ((*(str++)) - '0');
+			if (num > 255 || ++m > 3) {
+				return 0;
+			}
+		}
+		ip[n++] = num;
+		if (n == 4) {
+			return str == end;
+		} else if (str >= end || *(str++) != '.') {
 			return 0;
 		}
 	}
-	return 1;
+	return 0;		
 }
 /* }}} */
 
-#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) /* {{{ */
+static int _php_filter_validate_ipv6(char *str, int str_len 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 compressed = 0;
+	int blocks = 8;
+	int n;
+	char *ipv4;
+	char *end;
 	int ip4elm[4];
 
-	if (!strchr(str, ':')) {
+	if (!memchr(str, ':', str_len)) {
 		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, '.');
-
+	ipv4 = memchr(str, '.', str_len);
 	if (ipv4) {
-		while (*ipv4 != ':' && ipv4 >= start) {
+ 		while (ipv4 > str && *(ipv4-1) != ':') {
 			ipv4--;
 		}
 
-		/* ::w.x.y.z */
-		if (compressed && ipv4 == (compressed + 1)) {
-			compressed_2end = 1;
-		}
-		ipv4++;
-
-		if (!_php_filter_validate_ipv4(ipv4, ip4elm TSRMLS_CC)) {
+		if (!_php_filter_validate_ipv4(ipv4, (str_len - (ipv4 - str)), ip4elm)) {
 			return 0;
 		}
-
-		if (compressed_2end) {
-			return 1;
+		str_len = (ipv4 - str) - 1;
+		if (str_len == 1) {
+			return *str == ':';
 		}
+		blocks = 6;
 	}
 
-	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) {
+	end = str + str_len;
+	while (str < end) {
+		if (*str == ':') {
+			if (--blocks == 0) {
 				return 0;
-			}
-
-			hexcode_found = 0;
-			t = compressed - 1;
-			while (t >= start) {
-				IPV6_LOOP_IN(t);
-				t--;
-			}
-			if (hexcode_found > 4) {
+			}			
+			if (++str >= end) {
 				return 0;
 			}
-
-			if (col_fnd > 6) {
-				return 0;
-			} else {
-				return 1;
-			}
+			if (*str == ':') {
+				if (compressed || --blocks == 0) {
+					return 0;
+				}			
+				if (++str == end) {
+					return 1;
+				}
+				compressed = 1;
+			}				
+		}
+		n = 0;
+		while ((str < end) &&
+		       ((*str >= '0' && *str <= '9') ||
+		        (*str >= 'a' && *str <= 'f') ||
+		        (*str >= 'A' && *str <= 'F'))) {
+			n++;
+			str++;
+		}
+		if (n < 1 || n > 4) {
+			return 0;
 		}
 	}
-	return 0;
+	return (compressed || blocks == 1);
 }
 /* }}} */
 
@@ -771,7 +614,7 @@
 
 	switch (mode) {
 		case FORMAT_IPV4:
-			if (!_php_filter_validate_ipv4(str, ip TSRMLS_CC)) {
+			if (!_php_filter_validate_ipv4(str, Z_STRLEN_P(value), ip)) {
 				RETURN_VALIDATION_FAILED
 			}
 
@@ -801,7 +644,7 @@
 		case FORMAT_IPV6:
 			{
 				int res = 0;
-				res = _php_filter_validate_ipv6_(str TSRMLS_CC);
+				res = _php_filter_validate_ipv6(str, Z_STRLEN_P(value) TSRMLS_CC);
 				if (res < 1) {
 					RETURN_VALIDATION_FAILED
 				}
Index: php5-5.2.0/ext/filter/filter_private.h
===================================================================
--- php5-5.2.0.orig/ext/filter/filter_private.h	2006-10-17 17:26:14.000000000 +0200
+++ php5-5.2.0/ext/filter/filter_private.h	2007-04-23 20:22:47.000000000 +0200
@@ -81,27 +81,38 @@
 
 #define FILTER_CALLBACK               0x0400
 
-#define PHP_FILTER_TRIM_DEFAULT(p, len, end) { \
-	while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\v') { \
+#define RETURN_VALIDATION_FAILED	\
+	zval_dtor(value);	\
+	if (flags & FILTER_NULL_ON_FAILURE) {	\
+		ZVAL_NULL(value);	\
+	} else {	\
+		ZVAL_FALSE(value);	\
+	}	\
+	return;	\
+
+#define PHP_FILTER_TRIM_DEFAULT(p, len) { \
+	while ((len > 0)  && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\v' || *p == '\n')) { \
 		p++; \
 		len--; \
 	} \
-	start = p; \
-	end = p + len - 1; \
-	if (*end == ' ' || *end == '\t' || *end == '\r' || *end == '\v') { \
-		unsigned int i; \
-		for (i = len - 1; i >= 0; i--) { \
-			if (!(p[i] == ' ' || p[i] == '\t' || p[i] == '\r' || p[i] == '\v')) { \
-				break; \
-			} \
-		} \
-		i++; \
-		p[i] = '\0'; \
-		end = p + i - 1; \
-		len = (int) (end - p) + 1; \
+	if (len < 1) { \
+		RETURN_VALIDATION_FAILED \
+	} \
+	while (p[len-1] == ' ' || p[len-1] == '\t' || p[len-1] == '\r' || p[len-1] == '\v' || p[len-1] == '\n') { \
+		len--; \
 	} \
 }
 
+#define PHP_FILTER_GET_LONG_OPT(zv, opt) { \
+	if (Z_TYPE_PP(zv) != IS_LONG) {                                                                      \
+		zval tmp = **zv;                                                                                 \
+		zval_copy_ctor(&tmp);                                                                                    \
+		convert_to_long(&tmp);                                                                                   \
+		opt = Z_LVAL(tmp);                                                                                  \
+	} else {                                                                                                     \
+		opt = Z_LVAL_PP(zv);                                                                        \
+	}                                                                                                            \
+}
 
 #endif /* FILTER_PRIVATE_H */
 
Index: php5-5.2.0/ext/standard/php_string.h
===================================================================
--- php5-5.2.0.orig/ext/standard/php_string.h	2007-04-23 20:46:25.000000000 +0200
+++ php5-5.2.0/ext/standard/php_string.h	2007-04-23 20:49:04.000000000 +0200
@@ -132,6 +132,7 @@
 		int needle_len, char *str, int str_len, int *_new_length);
 PHPAPI char *php_trim(char *c, int len, char *what, int what_len, zval *return_value, int mode TSRMLS_DC);
 PHPAPI size_t php_strip_tags(char *rbuf, int len, int *state, char *allow, int allow_len);
+PHPAPI size_t php_strip_tags_ex(char *rbuf, int len, int *stateptr, char *allow, int allow_len, zend_bool allow_tag_spaces);
 PHPAPI int php_char_to_str_ex(char *str, uint len, char from, char *to, int to_len, zval *result, int case_sensitivity, int *replace_count);
 PHPAPI int php_char_to_str(char *str, uint len, char from, char *to, int to_len, zval *result);
 PHPAPI void php_implode(zval *delim, zval *arr, zval *return_value TSRMLS_DC);
Index: php5-5.2.0/ext/standard/string.c
===================================================================
--- php5-5.2.0.orig/ext/standard/string.c	2007-04-23 20:25:58.000000000 +0200
+++ php5-5.2.0/ext/standard/string.c	2007-04-23 20:45:31.000000000 +0200
@@ -1230,11 +1230,11 @@
 	}
 
 	len = cend - comp;
-	ret = emalloc(len + 1);
-	memcpy(ret, comp, len);
-	ret[len] = '\0';
 
 	if (p_ret) {
+		ret = emalloc(len + 1);
+		memcpy(ret, comp, len);
+		ret[len] = '\0';
 		*p_ret = ret;
 	}
 	if (p_len) {
@@ -1876,6 +1876,8 @@
 
 	if (offset >= 0) {
 		if (offset > haystack_len) {
+			efree(needle_dup);
+			efree(haystack_dup);
 			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Offset is greater than the length of haystack string");
 			RETURN_FALSE;
 		}
@@ -1883,6 +1885,8 @@
 		e = haystack_dup + haystack_len - needle_len;
 	} else {
 		if (-offset > haystack_len) {
+			efree(needle_dup);
+			efree(haystack_dup);
 			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Offset is greater than the length of haystack string");
 			RETURN_FALSE;
 		}
@@ -3872,7 +3876,7 @@
 	}
 	convert_to_string_ex(str);
 	buf = estrndup(Z_STRVAL_PP(str), Z_STRLEN_PP(str));
-	retval_len = php_strip_tags(buf, Z_STRLEN_PP(str), NULL, allowed_tags, allowed_tags_len);
+	retval_len = php_strip_tags_ex(buf, Z_STRLEN_PP(str), NULL, allowed_tags, allowed_tags_len, 0);
 	RETURN_STRINGL(buf, retval_len, 0);
 }
 /* }}} */
@@ -4026,7 +4030,13 @@
 int php_tag_find(char *tag, int len, char *set) {
 	char c, *n, *t;
 	int state=0, done=0;
-	char *norm = emalloc(len+1);
+	char *norm;
+
+	if (len <= 0) {
+		return 0;
+	}
+	
+	norm = emalloc(len+1);
 
 	n = norm;
 	t = tag;
@@ -4036,9 +4046,6 @@
 	   and turn any <a whatever...> into just <a> and any </tag>
 	   into <tag>
 	*/
-	if (!len) {
-		return 0;
-	}
 	while (!done) {
 		switch (c) {
 			case '<':
@@ -4076,6 +4083,11 @@
 }
 /* }}} */
 
+PHPAPI size_t php_strip_tags(char *rbuf, int len, int *stateptr, char *allow, int allow_len)
+{
+	return php_strip_tags_ex(rbuf, len, stateptr, allow, allow_len, 0);
+}
+
 /* {{{ php_strip_tags
  
 	A simple little state-machine to strip out html and php tags 
@@ -4096,10 +4108,10 @@
 	swm: Added ability to strip <?xml tags without assuming it PHP
 	code.
 */
-PHPAPI size_t php_strip_tags(char *rbuf, int len, int *stateptr, char *allow, int allow_len)
+PHPAPI size_t php_strip_tags_ex(char *rbuf, int len, int *stateptr, char *allow, int allow_len, zend_bool allow_tag_spaces)
 {
 	char *tbuf, *buf, *p, *tp, *rp, c, lc;
-	int br, i=0, depth=0;
+	int br, i=0, depth=0, in_q = 0;
 	int state = 0;
 
 	if (stateptr)
@@ -4124,7 +4136,7 @@
 			case '\0':
 				break;
 			case '<':
-				if (isspace(*(p + 1))) {
+				if (isspace(*(p + 1)) && !allow_tag_spaces) {
 					goto reg_char;
 				}
 				if (state == 0) {
@@ -4133,7 +4145,7 @@
 					if (allow) {
 						tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
 						*(tp++) = '<';
-					}
+				 	}
 				} else if (state == 1) {
 					depth++;
 				}
@@ -4172,7 +4184,11 @@
 					depth--;
 					break;
 				}
-			
+
+				if (in_q) {
+					break;
+				}
+
 				switch (state) {
 					case 1: /* HTML/XML */
 						lc = '>';
@@ -4228,6 +4244,9 @@
 					tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
 					*(tp++) = c;
 				}
+				if (p != buf && *(p-1) != '\\') {
+					in_q = !in_q;
+				}
 				break;
 			
 			case '!': 
