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: 375 389 96.4 %
Date: 2014-11-22 Functions: 13 13 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 22 Nov 2014 23:01:15 +0000 (45 hours ago)

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