PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/filter - logical_filters.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 344 359 95.8 %
Date: 2014-12-15 Functions: 12 12 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   +----------------------------------------------------------------------+
       3             :   | PHP Version 5                                                        |
       4             :   +----------------------------------------------------------------------+
       5             :   | Copyright (c) 1997-2014 The PHP Group                                |
       6             :   +----------------------------------------------------------------------+
       7             :   | This source file is subject to version 3.01 of the PHP license,      |
       8             :   | that is bundled with this package in the file LICENSE, and is        |
       9             :   | available through the world-wide-web at the following url:           |
      10             :   | http://www.php.net/license/3_01.txt                                  |
      11             :   | If you did not receive a copy of the PHP license and are unable to   |
      12             :   | obtain it through the world-wide-web, please send a note to          |
      13             :   | license@php.net so we can mail you a copy immediately.               |
      14             :   +----------------------------------------------------------------------+
      15             :   | Authors: Derick Rethans <derick@php.net>                             |
      16             :   |          Pierre-A. Joye <pierre@php.net>                             |
      17             :   +----------------------------------------------------------------------+
      18             : */
      19             : 
      20             : /* $Id$ */
      21             : 
      22             : #include "php_filter.h"
      23             : #include "filter_private.h"
      24             : #include "ext/standard/url.h"
      25             : #include "ext/pcre/php_pcre.h"
      26             : 
      27             : #include "zend_multiply.h"
      28             : 
      29             : #if HAVE_ARPA_INET_H
      30             : # include <arpa/inet.h>
      31             : #endif
      32             : 
      33             : #ifndef INADDR_NONE
      34             : # define INADDR_NONE ((unsigned long int) -1)
      35             : #endif
      36             : 
      37             : 
      38             : /* {{{ FETCH_LONG_OPTION(var_name, option_name) */
      39             : #define FETCH_LONG_OPTION(var_name, option_name)                                                                         \
      40             :         var_name = 0;                                                                                                        \
      41             :         var_name##_set = 0;                                                                                                  \
      42             :         if (option_array) {                                                                                                  \
      43             :                 if (zend_hash_find(HASH_OF(option_array), option_name, sizeof(option_name), (void **) &option_val) == SUCCESS) { \
      44             :                         PHP_FILTER_GET_LONG_OPT(option_val, var_name);                                                          \
      45             :                         var_name##_set = 1;                                                                                          \
      46             :                 }                                                                                                                \
      47             :         }
      48             : /* }}} */
      49             : 
      50             : /* {{{ FETCH_STRING_OPTION(var_name, option_name) */
      51             : #define FETCH_STRING_OPTION(var_name, option_name)                                                                       \
      52             :         var_name = NULL;                                                                                                     \
      53             :         var_name##_set = 0;                                                                                                  \
      54             :         var_name##_len = 0;                                                                                                  \
      55             :         if (option_array) {                                                                                                  \
      56             :                 if (zend_hash_find(HASH_OF(option_array), option_name, sizeof(option_name), (void **) &option_val) == SUCCESS) { \
      57             :                         if (Z_TYPE_PP(option_val) == IS_STRING) {                                                                    \
      58             :                                 var_name = Z_STRVAL_PP(option_val);                                                                      \
      59             :                                 var_name##_len = Z_STRLEN_PP(option_val);                                                                \
      60             :                                 var_name##_set = 1;                                                                                      \
      61             :                         }                                                                                                            \
      62             :                 }                                                                                                                \
      63             :         }
      64             : /* }}} */
      65             : 
      66             : #define FORMAT_IPV4    4
      67             : #define FORMAT_IPV6    6
      68             : 
      69          57 : static int php_filter_parse_int(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */
      70             :         long ctx_value;
      71          57 :         int sign = 0, digit = 0;
      72          57 :         const char *end = str + str_len;
      73             : 
      74          57 :         switch (*str) {
      75             :                 case '-':
      76          16 :                         sign = 1;
      77             :                 case '+':
      78          17 :                         str++;
      79             :                 default:
      80             :                         break;
      81             :         }
      82             : 
      83          57 :         if (*str == '0' && str + 1 == end) {
      84             :                 /* Special cases: +0 and -0 */
      85           2 :                 return 1;
      86             :         }
      87             : 
      88             :         /* must start with 1..9*/
      89          96 :         if (str < end && *str >= '1' && *str <= '9') {
      90          41 :                 ctx_value = ((sign)?-1:1) * ((*(str++)) - '0');
      91             :         } else {
      92          14 :                 return -1;
      93             :         }
      94             : 
      95          41 :         if ((end - str > MAX_LENGTH_OF_LONG - 1) /* number too long */
      96             :          || (SIZEOF_LONG == 4 && (end - str == MAX_LENGTH_OF_LONG - 1) && *str > '2')) {
      97             :                 /* overflow */
      98           0 :                 return -1;
      99             :         }
     100             : 
     101         213 :         while (str < end) {
     102         269 :                 if (*str >= '0' && *str <= '9') {
     103         133 :                         digit = (*(str++) - '0');
     104         203 :                         if ( (!sign) && ctx_value <= (LONG_MAX-digit)/10 ) {
     105          70 :                                 ctx_value = (ctx_value * 10) + digit;
     106         124 :                         } else if ( sign && ctx_value >= (LONG_MIN+digit)/10) {
     107          61 :                                 ctx_value = (ctx_value * 10) - digit;
     108             :                         } else {
     109           2 :                                 return -1;
     110             :                         }
     111             :                 } else {
     112           5 :                         return -1;
     113             :                 }
     114             :         }
     115             : 
     116          34 :         *ret = ctx_value;
     117          34 :         return 1;
     118             : }
     119             : /* }}} */
     120             : 
     121          11 : static int php_filter_parse_octal(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */
     122          11 :         unsigned long ctx_value = 0;
     123          11 :         const char *end = str + str_len;
     124             : 
     125         121 :         while (str < end) {
     126         200 :                 if (*str >= '0' && *str <= '7') {
     127         100 :                         unsigned long n = ((*(str++)) - '0');
     128             : 
     129         199 :                         if ((ctx_value > ((unsigned long)(~(long)0)) / 8) ||
     130          99 :                                 ((ctx_value = ctx_value * 8) > ((unsigned long)(~(long)0)) - n)) {
     131           1 :                                 return -1;
     132             :                         }
     133          99 :                         ctx_value += n;
     134             :                 } else {
     135           1 :                         return -1;
     136             :                 }
     137             :         }
     138             :         
     139           9 :         *ret = (long)ctx_value;
     140           9 :         return 1;
     141             : }
     142             : /* }}} */
     143             : 
     144          12 : static int php_filter_parse_hex(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */
     145          12 :         unsigned long ctx_value = 0;
     146          12 :         const char *end = str + str_len;
     147             :         unsigned long n;
     148             : 
     149         108 :         while (str < end) {
     150         123 :                 if (*str >= '0' && *str <= '9') {
     151          38 :                         n = ((*(str++)) - '0');
     152          90 :                 } else if (*str >= 'a' && *str <= 'f') {
     153          43 :                         n = ((*(str++)) - ('a' - 10));
     154           8 :                 } else if (*str >= 'A' && *str <= 'F') {
     155           4 :                         n = ((*(str++)) - ('A' - 10));
     156             :                 } else {
     157           0 :                         return -1;
     158             :                 }
     159         169 :                 if ((ctx_value > ((unsigned long)(~(long)0)) / 16) ||
     160          84 :                         ((ctx_value = ctx_value * 16) > ((unsigned long)(~(long)0)) - n)) {
     161           1 :                         return -1;
     162             :                 }
     163          84 :                 ctx_value += n;
     164             :         }
     165             : 
     166          11 :         *ret = (long)ctx_value;
     167          11 :         return 1;
     168             : }
     169             : /* }}} */
     170             : 
     171          93 : void php_filter_int(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
     172             : {
     173             :         zval **option_val;
     174             :         long   min_range, max_range, option_flags;
     175             :         int    min_range_set, max_range_set;
     176          93 :         int    allow_octal = 0, allow_hex = 0;
     177          93 :         int        len, error = 0;
     178             :         long   ctx_value;
     179             :         char *p;
     180             : 
     181             :         /* Parse options */
     182          94 :         FETCH_LONG_OPTION(min_range,    "min_range");
     183          94 :         FETCH_LONG_OPTION(max_range,    "max_range");
     184          93 :         option_flags = flags;
     185             : 
     186          93 :         len = Z_STRLEN_P(value);
     187             : 
     188          93 :         if (len == 0) {
     189           5 :                 RETURN_VALIDATION_FAILED
     190             :         }
     191             : 
     192          88 :         if (option_flags & FILTER_FLAG_ALLOW_OCTAL) {
     193          19 :                 allow_octal = 1;
     194             :         }
     195             : 
     196          88 :         if (option_flags & FILTER_FLAG_ALLOW_HEX) {
     197          17 :                 allow_hex = 1;
     198             :         }
     199             : 
     200             :         /* Start the validating loop */
     201          88 :         p = Z_STRVAL_P(value);
     202          88 :         ctx_value = 0;
     203             : 
     204          88 :         PHP_FILTER_TRIM_DEFAULT(p, len);
     205             : 
     206          88 :         if (*p == '0') {
     207          31 :                 p++; len--;
     208          43 :                 if (allow_hex && (*p == 'x' || *p == 'X')) {
     209          12 :                         p++; len--;
     210          12 :                         if (php_filter_parse_hex(p, len, &ctx_value TSRMLS_CC) < 0) {
     211           1 :                                 error = 1;
     212             :                         }
     213          19 :                 } else if (allow_octal) {
     214          11 :                         if (php_filter_parse_octal(p, len, &ctx_value TSRMLS_CC) < 0) {
     215           2 :                                 error = 1;
     216             :                         }
     217           8 :                 } else if (len != 0) {
     218           4 :                         error = 1;
     219             :                 }
     220             :         } else {
     221          57 :                 if (php_filter_parse_int(p, len, &ctx_value TSRMLS_CC) < 0) {
     222          21 :                         error = 1;
     223             :                 }
     224             :         }
     225             : 
     226          88 :         if (error > 0 || (min_range_set && (ctx_value < min_range)) || (max_range_set && (ctx_value > max_range))) {
     227          31 :                 RETURN_VALIDATION_FAILED
     228             :         } else {
     229             :                 zval_dtor(value);
     230          57 :                 Z_TYPE_P(value) = IS_LONG;
     231          57 :                 Z_LVAL_P(value) = ctx_value;
     232          57 :                 return;
     233             :         }
     234             : }
     235             : /* }}} */
     236             : 
     237          67 : void php_filter_boolean(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
     238             : {
     239          67 :         char *str = Z_STRVAL_P(value);
     240          67 :         int len = Z_STRLEN_P(value);
     241             :         int ret;
     242             : 
     243          67 :         PHP_FILTER_TRIM_DEFAULT_EX(str, len, 0);
     244             : 
     245             :         /* returns true for "1", "true", "on" and "yes"
     246             :          * returns false for "0", "false", "off", "no", and ""
     247             :          * null otherwise. */
     248          67 :         switch (len) {
     249             :                 case 0:
     250           8 :                         ret = 0;
     251           8 :                         break;
     252             :                 case 1:
     253          19 :                         if (*str == '1') {
     254          10 :                                 ret = 1;
     255           9 :                         } else if (*str == '0') {
     256           7 :                                 ret = 0;
     257             :                         } else {
     258           2 :                                 ret = -1;
     259             :                         }
     260          19 :                         break;
     261             :                 case 2:
     262           9 :                         if (strncasecmp(str, "on", 2) == 0) {
     263           5 :                                 ret = 1;
     264           4 :                         } else if (strncasecmp(str, "no", 2) == 0) {
     265           3 :                                 ret = 0;
     266             :                         } else {
     267           1 :                                 ret = -1;
     268             :                         }
     269           9 :                         break;
     270             :                 case 3:
     271          11 :                         if (strncasecmp(str, "yes", 3) == 0) {
     272           3 :                                 ret = 1;
     273           8 :                         } else if (strncasecmp(str, "off", 3) == 0) {
     274           5 :                                 ret = 0;
     275             :                         } else {
     276           3 :                                 ret = -1;
     277             :                         }
     278          11 :                         break;
     279             :                 case 4:
     280           6 :                         if (strncasecmp(str, "true", 4) == 0) {
     281           4 :                                 ret = 1;
     282             :                         } else {
     283           2 :                                 ret = -1;
     284             :                         }
     285           6 :                         break;
     286             :                 case 5:
     287           5 :                         if (strncasecmp(str, "false", 5) == 0) {
     288           5 :                                 ret = 0;
     289             :                         } else {
     290           0 :                                 ret = -1;
     291             :                         }
     292           5 :                         break;
     293             :                 default:
     294           9 :                         ret = -1;
     295             :         }
     296             : 
     297          67 :         if (ret == -1) {
     298          17 :                 RETURN_VALIDATION_FAILED
     299             :         } else {
     300             :                 zval_dtor(value);
     301          50 :                 ZVAL_BOOL(value, ret);
     302             :         }
     303             : }
     304             : /* }}} */
     305             : 
     306          68 : void php_filter_float(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
     307             : {
     308             :         int len;
     309             :         char *str, *end;
     310             :         char *num, *p;
     311             : 
     312             :         zval **option_val;
     313             :         char *decimal;
     314             :         int decimal_set, decimal_len;
     315          68 :         char dec_sep = '.';
     316          68 :         char tsd_sep[3] = "',.";
     317             : 
     318             :         long lval;
     319             :         double dval;
     320             : 
     321             :         int first, n;
     322             : 
     323          68 :         len = Z_STRLEN_P(value);
     324          68 :         str = Z_STRVAL_P(value);
     325             : 
     326          72 :         PHP_FILTER_TRIM_DEFAULT(str, len);
     327          64 :         end = str + len;
     328             : 
     329          64 :         FETCH_STRING_OPTION(decimal, "decimal");
     330             : 
     331          64 :         if (decimal_set) {
     332           5 :                 if (decimal_len != 1) {
     333           1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "decimal separator must be one char");
     334           1 :                         RETURN_VALIDATION_FAILED
     335             :                 } else {
     336           4 :                         dec_sep = *decimal;
     337             :                 }
     338             :         }
     339             : 
     340          63 :         num = p = emalloc(len+1);
     341          63 :         if (str < end && (*str == '+' || *str == '-')) {
     342           9 :                 *p++ = *str++;
     343             :         }
     344          63 :         first = 1;
     345             :         while (1) {
     346          78 :                 n = 0;
     347         308 :                 while (str < end && *str >= '0' && *str <= '9') {
     348         152 :                         ++n;
     349         152 :                         *p++ = *str++;
     350             :                 }
     351          78 :                 if (str == end || *str == dec_sep || *str == 'e' || *str == 'E') {
     352          50 :                         if (!first && n != 3) {
     353           3 :                                 goto error;
     354             :                         }
     355          47 :                         if (*str == dec_sep) {
     356          25 :                                 *p++ = '.';
     357          25 :                                 str++;
     358         126 :                                 while (str < end && *str >= '0' && *str <= '9') {
     359          76 :                                         *p++ = *str++;
     360             :                                 }
     361             :                         }
     362          47 :                         if (*str == 'e' || *str == 'E') {
     363          14 :                                 *p++ = *str++;
     364          14 :                                 if (str < end && (*str == '+' || *str == '-')) {
     365           7 :                                         *p++ = *str++;
     366             :                                 }
     367          48 :                                 while (str < end && *str >= '0' && *str <= '9') {
     368          20 :                                         *p++ = *str++;
     369             :                                 }
     370             :                         }
     371          47 :                         break;
     372             :                 }
     373          28 :                 if ((flags & FILTER_FLAG_ALLOW_THOUSAND) && (*str == tsd_sep[0] || *str == tsd_sep[1] || *str == tsd_sep[2])) {
     374          16 :                         if (first?(n < 1 || n > 3):(n != 3)) {
     375           1 :                                 goto error;
     376             :                         }
     377          15 :                         first = 0;
     378          15 :                         str++;
     379             :                 } else {
     380             :                         goto error;
     381             :                 }
     382          15 :         }
     383          47 :         if (str != end) {
     384           2 :                 goto error;
     385             :         }
     386          45 :         *p = 0;
     387             : 
     388          45 :         switch (is_numeric_string(num, p - num, &lval, &dval, 0)) {
     389             :                 case IS_LONG:
     390             :                         zval_dtor(value);
     391           9 :                         Z_TYPE_P(value) = IS_DOUBLE;
     392           9 :                         Z_DVAL_P(value) = lval;
     393           9 :                         break;
     394             :                 case IS_DOUBLE:
     395          31 :                         if ((!dval && p - num > 1 && strpbrk(num, "123456789")) || !zend_finite(dval)) {
     396             :                                 goto error;
     397             :                         }
     398             :                         zval_dtor(value);
     399          29 :                         Z_TYPE_P(value) = IS_DOUBLE;
     400          29 :                         Z_DVAL_P(value) = dval;
     401          29 :                         break;
     402             :                 default:
     403             : error:
     404          25 :                         efree(num);
     405          25 :                         RETURN_VALIDATION_FAILED
     406             :         }
     407          38 :         efree(num);     
     408             : }
     409             : /* }}} */
     410             : 
     411          15 : void php_filter_validate_regexp(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
     412             : {
     413             :         zval **option_val;
     414             :         char  *regexp;
     415             :         int regexp_len;
     416             :         long   option_flags;
     417             :         int    regexp_set, option_flags_set;
     418             : 
     419          15 :         pcre       *re = NULL;
     420          15 :         pcre_extra *pcre_extra = NULL;
     421          15 :         int preg_options = 0;
     422             : 
     423             :         int         ovector[3];
     424             :         int         matches;
     425             : 
     426             :         /* Parse options */
     427          15 :         FETCH_STRING_OPTION(regexp, "regexp");
     428          15 :         FETCH_LONG_OPTION(option_flags, "flags");
     429             : 
     430          15 :         if (!regexp_set) {
     431           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "'regexp' option missing");
     432           1 :                 RETURN_VALIDATION_FAILED
     433             :         }
     434             : 
     435          14 :         re = pcre_get_compiled_regex(regexp, &pcre_extra, &preg_options TSRMLS_CC);
     436          14 :         if (!re) {
     437           0 :                 RETURN_VALIDATION_FAILED
     438             :         }
     439          14 :         matches = pcre_exec(re, NULL, Z_STRVAL_P(value), Z_STRLEN_P(value), 0, 0, ovector, 3);
     440             : 
     441             :         /* 0 means that the vector is too small to hold all the captured substring offsets */
     442          14 :         if (matches < 0) {
     443          11 :                 RETURN_VALIDATION_FAILED
     444             :         }
     445             : }
     446             : /* }}} */
     447             : 
     448          48 : void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
     449             : {
     450             :         php_url *url;
     451          48 :         int old_len = Z_STRLEN_P(value);
     452             :         
     453          48 :         php_filter_url(value, flags, option_array, charset TSRMLS_CC);
     454             : 
     455          48 :         if (Z_TYPE_P(value) != IS_STRING || old_len != Z_STRLEN_P(value)) {
     456           2 :                 RETURN_VALIDATION_FAILED
     457             :         }
     458             : 
     459             :         /* Use parse_url - if it returns false, we return NULL */
     460          46 :         url = php_url_parse_ex(Z_STRVAL_P(value), Z_STRLEN_P(value));
     461             : 
     462          46 :         if (url == NULL) {
     463           6 :                 RETURN_VALIDATION_FAILED
     464             :         }
     465             : 
     466          40 :         if (url->scheme != NULL && (!strcasecmp(url->scheme, "http") || !strcasecmp(url->scheme, "https"))) {
     467             :                 char *e, *s;
     468             : 
     469          20 :                 if (url->host == NULL) {
     470           3 :                         goto bad_url;
     471             :                 }
     472             : 
     473          17 :                 e = url->host + strlen(url->host);
     474          17 :                 s = url->host;
     475             : 
     476             :                 /* First char of hostname must be alphanumeric */
     477          17 :                 if(!isalnum((int)*(unsigned char *)s)) { 
     478           0 :                         goto bad_url;
     479             :                 }
     480             : 
     481         225 :                 while (s < e) {
     482         192 :                         if (!isalnum((int)*(unsigned char *)s) && *s != '-' && *s != '.') {
     483           1 :                                 goto bad_url;
     484             :                         }
     485         191 :                         s++;
     486             :                 }
     487             :         }
     488             : 
     489         108 :         if (
     490          36 :                 url->scheme == NULL || 
     491             :                 /* some schemas allow the host to be empty */
     492          27 :                 (url->host == NULL && (strcmp(url->scheme, "mailto") && strcmp(url->scheme, "news") && strcmp(url->scheme, "file"))) ||
     493          45 :                 ((flags & FILTER_FLAG_PATH_REQUIRED) && url->path == NULL) || ((flags & FILTER_FLAG_QUERY_REQUIRED) && url->query == NULL)
     494             :         ) {
     495             : bad_url:
     496          21 :                 php_url_free(url);
     497          21 :                 RETURN_VALIDATION_FAILED
     498             :         }
     499          19 :         php_url_free(url);
     500             : }
     501             : /* }}} */
     502             : 
     503          35 : void php_filter_validate_email(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
     504             : {
     505             :         /*
     506             :          * The regex below is based on a regex by Michael Rushton.
     507             :          * However, it is not identical.  I changed it to only consider routeable
     508             :          * addresses as valid.  Michael's regex considers a@b a valid address
     509             :          * which conflicts with section 2.3.5 of RFC 5321 which states that:
     510             :          *
     511             :          *   Only resolvable, fully-qualified domain names (FQDNs) are permitted
     512             :          *   when domain names are used in SMTP.  In other words, names that can
     513             :          *   be resolved to MX RRs or address (i.e., A or AAAA) RRs (as discussed
     514             :          *   in Section 5) are permitted, as are CNAME RRs whose targets can be
     515             :          *   resolved, in turn, to MX or address RRs.  Local nicknames or
     516             :          *   unqualified names MUST NOT be used.
     517             :          *
     518             :          * This regex does not handle comments and folding whitespace.  While
     519             :          * this is technically valid in an email address, these parts aren't
     520             :          * actually part of the address itself.
     521             :          *
     522             :          * Michael's regex carries this copyright:
     523             :          *
     524             :          * Copyright © Michael Rushton 2009-10
     525             :          * http://squiloople.com/
     526             :          * Feel free to use and redistribute this code. But please keep this copyright notice.
     527             :          *
     528             :          */
     529          35 :         const char regexp[] = "/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD";
     530             : 
     531          35 :         pcre       *re = NULL;
     532          35 :         pcre_extra *pcre_extra = NULL;
     533          35 :         int preg_options = 0;
     534             :         int         ovector[150]; /* Needs to be a multiple of 3 */
     535             :         int         matches;
     536             : 
     537             : 
     538             :         /* The maximum length of an e-mail address is 320 octets, per RFC 2821. */
     539          35 :         if (Z_STRLEN_P(value) > 320) {
     540           2 :                 RETURN_VALIDATION_FAILED
     541             :         }
     542             : 
     543          33 :         re = pcre_get_compiled_regex((char *)regexp, &pcre_extra, &preg_options TSRMLS_CC);
     544          33 :         if (!re) {
     545           0 :                 RETURN_VALIDATION_FAILED
     546             :         }
     547          33 :         matches = pcre_exec(re, NULL, Z_STRVAL_P(value), Z_STRLEN_P(value), 0, 0, ovector, 3);
     548             : 
     549             :         /* 0 means that the vector is too small to hold all the captured substring offsets */
     550          33 :         if (matches < 0) {
     551          21 :                 RETURN_VALIDATION_FAILED
     552             :         }
     553             : 
     554             : }
     555             : /* }}} */
     556             : 
     557          55 : static int _php_filter_validate_ipv4(char *str, int str_len, int *ip) /* {{{ */
     558             : {
     559          55 :         const char *end = str + str_len;
     560             :         int num, m;
     561          55 :         int n = 0;
     562             : 
     563         248 :         while (str < end) {
     564             :                 int leading_zero;
     565         193 :                 if (*str < '0' || *str > '9') {
     566           6 :                         return 0;
     567             :                 }
     568         187 :                 leading_zero = (*str == '0');
     569         187 :                 m = 1;
     570         187 :                 num = ((*(str++)) - '0');
     571         546 :                 while (str < end && (*str >= '0' && *str <= '9')) {
     572         173 :                         num = num * 10 + ((*(str++)) - '0');
     573         173 :                         if (num > 255 || ++m > 3) {
     574           1 :                                 return 0;
     575             :                         }
     576             :                 }
     577             :                 /* don't allow a leading 0; that introduces octal numbers,
     578             :                  * which we don't support */
     579         186 :                 if (leading_zero && (num != 0 || m > 1))
     580           2 :                         return 0;
     581         184 :                 ip[n++] = num;
     582         184 :                 if (n == 4) {
     583          45 :                         return str == end;
     584         139 :                 } else if (str >= end || *(str++) != '.') {
     585           1 :                         return 0;
     586             :                 }
     587             :         }
     588           0 :         return 0;               
     589             : }
     590             : /* }}} */
     591             : 
     592          67 : static int _php_filter_validate_ipv6(char *str, int str_len TSRMLS_DC) /* {{{ */
     593             : {
     594          67 :         int compressed = 0;
     595          67 :         int blocks = 0;
     596             :         int n;
     597             :         char *ipv4;
     598             :         char *end;
     599             :         int ip4elm[4];
     600          67 :         char *s = str;
     601             : 
     602          67 :         if (!memchr(str, ':', str_len)) {
     603           0 :                 return 0;
     604             :         }
     605             : 
     606             :         /* check for bundled IPv4 */
     607          67 :         ipv4 = memchr(str, '.', str_len);
     608          67 :         if (ipv4) {
     609         114 :                 while (ipv4 > str && *(ipv4-1) != ':') {
     610          62 :                         ipv4--;
     611             :                 }
     612             : 
     613          26 :                 if (!_php_filter_validate_ipv4(ipv4, (str_len - (ipv4 - str)), ip4elm)) {
     614           4 :                         return 0;
     615             :                 }
     616             : 
     617          22 :                 str_len = ipv4 - str; /* length excluding ipv4 */
     618          22 :                 if (str_len < 2) {
     619           0 :                         return 0;
     620             :                 }
     621             : 
     622          22 :                 if (ipv4[-2] != ':') {
     623             :                         /* don't include : before ipv4 unless it's a :: */
     624          13 :                         str_len--;
     625             :                 }
     626             : 
     627          22 :                 blocks = 2;
     628             :         }
     629             : 
     630          63 :         end = str + str_len;
     631             : 
     632         346 :         while (str < end) {
     633         248 :                 if (*str == ':') {
     634         204 :                         if (++str >= end) {
     635             :                                 /* cannot end in : without previous : */
     636           0 :                                 return 0;
     637             :                         }
     638         204 :                         if (*str == ':') {
     639          54 :                                 if (compressed) {
     640           4 :                                         return 0;
     641             :                                 }
     642          50 :                                 blocks++; /* :: means 1 or more 16-bit 0 blocks */
     643          50 :                                 compressed = 1;
     644             : 
     645          50 :                                 if (++str == end) {
     646          10 :                                         return (blocks <= 8);
     647             :                                 }
     648         150 :                         } else if ((str - 1) == s) {
     649             :                                 /* dont allow leading : without another : following */
     650           0 :                                 return 0;
     651             :                         }                               
     652             :                 }
     653         234 :                 n = 0;
     654        2612 :                 while ((str < end) &&
     655        1152 :                        ((*str >= '0' && *str <= '9') ||
     656         352 :                         (*str >= 'a' && *str <= 'f') ||
     657         256 :                         (*str >= 'A' && *str <= 'F'))) {
     658         384 :                         n++;
     659         384 :                         str++;
     660             :                 }
     661         234 :                 if (n < 1 || n > 4) {
     662           8 :                         return 0;
     663             :                 }
     664         226 :                 if (++blocks > 8)
     665           6 :                         return 0;
     666             :         }
     667          35 :         return ((compressed && blocks <= 8) || blocks == 8);
     668             : }
     669             : /* }}} */
     670             : 
     671         106 : void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
     672             : {
     673             :         /* validates an ipv4 or ipv6 IP, based on the flag (4, 6, or both) add a
     674             :          * flag to throw out reserved ranges; multicast ranges... etc. If both
     675             :          * allow_ipv4 and allow_ipv6 flags flag are used, then the first dot or
     676             :          * colon determine the format */
     677             : 
     678             :         int            ip[4];
     679             :         int            mode;
     680             : 
     681         106 :         if (memchr(Z_STRVAL_P(value), ':', Z_STRLEN_P(value))) {
     682          68 :                 mode = FORMAT_IPV6;
     683          38 :         } else if (memchr(Z_STRVAL_P(value), '.', Z_STRLEN_P(value))) {
     684          30 :                 mode = FORMAT_IPV4;
     685             :         } else {
     686           8 :                 RETURN_VALIDATION_FAILED
     687             :         }
     688             : 
     689          98 :         if ((flags & FILTER_FLAG_IPV4) && (flags & FILTER_FLAG_IPV6)) {
     690             :                 /* Both formats are cool */
     691          98 :         } else if ((flags & FILTER_FLAG_IPV4) && mode == FORMAT_IPV6) {
     692           1 :                 RETURN_VALIDATION_FAILED
     693          97 :         } else if ((flags & FILTER_FLAG_IPV6) && mode == FORMAT_IPV4) {
     694           1 :                 RETURN_VALIDATION_FAILED
     695             :         }
     696             : 
     697          96 :         switch (mode) {
     698             :                 case FORMAT_IPV4:
     699          29 :                         if (!_php_filter_validate_ipv4(Z_STRVAL_P(value), Z_STRLEN_P(value), ip)) {
     700           9 :                                 RETURN_VALIDATION_FAILED
     701             :                         }
     702             : 
     703             :                         /* Check flags */
     704          20 :                         if (flags & FILTER_FLAG_NO_PRIV_RANGE) {
     705           8 :                                 if (
     706           2 :                                         (ip[0] == 10) ||
     707           2 :                                         (ip[0] == 172 && (ip[1] >= 16 && ip[1] <= 31)) ||
     708           4 :                                         (ip[0] == 192 && ip[1] == 168)
     709             :                                 ) {
     710           1 :                                         RETURN_VALIDATION_FAILED
     711             :                                 }
     712             :                         }
     713             : 
     714          19 :                         if (flags & FILTER_FLAG_NO_RES_RANGE) {
     715          51 :                                 if (
     716           8 :                                         (ip[0] == 0) ||
     717          12 :                                         (ip[0] == 100 && (ip[1] >= 64 && ip[1] <= 127)) ||
     718           6 :                                         (ip[0] == 169 && ip[1] == 254) ||
     719           8 :                                         (ip[0] == 192 && ip[1] == 0 && ip[2] == 2) ||
     720          12 :                                         (ip[0] == 127 && ip[1] == 0 && ip[2] == 0 && ip[3] == 1) ||
     721           5 :                                         (ip[0] >= 224 && ip[0] <= 255)
     722             :                                 ) {
     723           5 :                                         RETURN_VALIDATION_FAILED
     724             :                                 }
     725             :                         }
     726          14 :                         break;
     727             : 
     728             :                 case FORMAT_IPV6:
     729             :                         {
     730          67 :                                 int res = 0;
     731          67 :                                 res = _php_filter_validate_ipv6(Z_STRVAL_P(value), Z_STRLEN_P(value) TSRMLS_CC);
     732          67 :                                 if (res < 1) {
     733          26 :                                         RETURN_VALIDATION_FAILED
     734             :                                 }
     735             :                                 /* Check flags */
     736          41 :                                 if (flags & FILTER_FLAG_NO_PRIV_RANGE) {
     737           1 :                                         if (Z_STRLEN_P(value) >=2 && (!strncasecmp("FC", Z_STRVAL_P(value), 2) || !strncasecmp("FD", Z_STRVAL_P(value), 2))) {
     738           1 :                                                 RETURN_VALIDATION_FAILED
     739             :                                         }
     740             :                                 }
     741          40 :                                 if (flags & FILTER_FLAG_NO_RES_RANGE) {
     742           8 :                                         switch (Z_STRLEN_P(value)) {
     743             :                                                 case 1: case 0:
     744           0 :                                                         break;
     745             :                                                 case 2:
     746           1 :                                                         if (!strcmp("::", Z_STRVAL_P(value))) {
     747           1 :                                                                 RETURN_VALIDATION_FAILED
     748             :                                                         }
     749           0 :                                                         break;
     750             :                                                 case 3:
     751           3 :                                                         if (!strcmp("::1", Z_STRVAL_P(value)) || !strcmp("5f:", Z_STRVAL_P(value))) {
     752           3 :                                                                 RETURN_VALIDATION_FAILED
     753             :                                                         }
     754           0 :                                                         break;
     755             :                                                 default:
     756           4 :                                                         if (Z_STRLEN_P(value) >= 5) {
     757          13 :                                                                 if (
     758           4 :                                                                         !strncasecmp("fe8", Z_STRVAL_P(value), 3) ||
     759           3 :                                                                         !strncasecmp("fe9", Z_STRVAL_P(value), 3) ||
     760           3 :                                                                         !strncasecmp("fea", Z_STRVAL_P(value), 3) ||
     761           3 :                                                                         !strncasecmp("feb", Z_STRVAL_P(value), 3)
     762             :                                                                 ) {
     763           1 :                                                                         RETURN_VALIDATION_FAILED
     764             :                                                                 }
     765             :                                                         }
     766          10 :                                                         if (
     767           4 :                                                                 (Z_STRLEN_P(value) >= 9 &&  !strncasecmp("2001:0db8", Z_STRVAL_P(value), 9)) ||
     768           4 :                                                                 (Z_STRLEN_P(value) >= 2 &&  !strncasecmp("5f", Z_STRVAL_P(value), 2)) ||
     769           2 :                                                                 (Z_STRLEN_P(value) >= 4 &&  !strncasecmp("3ff3", Z_STRVAL_P(value), 4)) ||
     770           0 :                                                                 (Z_STRLEN_P(value) >= 8 &&  !strncasecmp("2001:001", Z_STRVAL_P(value), 8))
     771             :                                                         ) {
     772           3 :                                                                 RETURN_VALIDATION_FAILED
     773             :                                                         }
     774             :                                         }
     775             :                                 }
     776             :                         }
     777             :                         break;
     778             :         }
     779             : }
     780             : /* }}} */
     781             : 
     782             : /*
     783             :  * Local variables:
     784             :  * tab-width: 4
     785             :  * c-basic-offset: 4
     786             :  * End:
     787             :  * vim600: noet sw=4 ts=4 fdm=marker
     788             :  * vim<600: noet sw=4 ts=4
     789             :  */

Generated by: LCOV version 1.10

Generated at Mon, 15 Dec 2014 17:02:41 +0000 (5 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.