Back to index

php5  5.3.10
filter.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 1997-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt                                  |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Authors: Rasmus Lerdorf <rasmus@php.net>                             |
00016   |          Derick Rethans <derick@php.net>                             |
00017   |          Pierre-A. Joye <pierre@php.net>                             |
00018   |          Ilia Alshanetsky <iliaa@php.net>                            |
00019   +----------------------------------------------------------------------+
00020 */
00021 
00022 /* $Id: filter.c 321634 2012-01-01 13:15:04Z felipe $ */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include "config.h"
00026 #endif
00027 
00028 #include "php_filter.h"
00029 
00030 ZEND_DECLARE_MODULE_GLOBALS(filter)
00031 
00032 #include "filter_private.h"
00033 
00034 typedef struct filter_list_entry {
00035        const char *name;
00036        int    id;
00037        void (*function)(PHP_INPUT_FILTER_PARAM_DECL);
00038 } filter_list_entry;
00039 
00040 /* {{{ filter_list */
00041 static const filter_list_entry filter_list[] = {
00042        { "int",             FILTER_VALIDATE_INT,           php_filter_int             },
00043        { "boolean",         FILTER_VALIDATE_BOOLEAN,       php_filter_boolean         },
00044        { "float",           FILTER_VALIDATE_FLOAT,         php_filter_float           },
00045 
00046        { "validate_regexp", FILTER_VALIDATE_REGEXP,        php_filter_validate_regexp },
00047        { "validate_url",    FILTER_VALIDATE_URL,           php_filter_validate_url    },
00048        { "validate_email",  FILTER_VALIDATE_EMAIL,         php_filter_validate_email  },
00049        { "validate_ip",     FILTER_VALIDATE_IP,            php_filter_validate_ip     },
00050 
00051        { "string",          FILTER_SANITIZE_STRING,        php_filter_string          },
00052        { "stripped",        FILTER_SANITIZE_STRING,        php_filter_string          },
00053        { "encoded",         FILTER_SANITIZE_ENCODED,       php_filter_encoded         },
00054        { "special_chars",   FILTER_SANITIZE_SPECIAL_CHARS, php_filter_special_chars   },
00055        { "full_special_chars",   FILTER_SANITIZE_FULL_SPECIAL_CHARS, php_filter_full_special_chars   },
00056        { "unsafe_raw",      FILTER_UNSAFE_RAW,             php_filter_unsafe_raw      },
00057        { "email",           FILTER_SANITIZE_EMAIL,         php_filter_email           },
00058        { "url",             FILTER_SANITIZE_URL,           php_filter_url             },
00059        { "number_int",      FILTER_SANITIZE_NUMBER_INT,    php_filter_number_int      },
00060        { "number_float",    FILTER_SANITIZE_NUMBER_FLOAT,  php_filter_number_float    },
00061        { "magic_quotes",    FILTER_SANITIZE_MAGIC_QUOTES,  php_filter_magic_quotes    },
00062 
00063        { "callback",        FILTER_CALLBACK,               php_filter_callback        },
00064 };
00065 /* }}} */
00066 
00067 #ifndef PARSE_ENV
00068 #define PARSE_ENV 4
00069 #endif
00070 
00071 #ifndef PARSE_SERVER
00072 #define PARSE_SERVER 5
00073 #endif
00074 
00075 #ifndef PARSE_SESSION
00076 #define PARSE_SESSION 6
00077 #endif
00078 
00079 static unsigned int php_sapi_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC);
00080 static unsigned int php_sapi_filter_init(TSRMLS_D);
00081 
00082 /* {{{ arginfo */
00083 ZEND_BEGIN_ARG_INFO_EX(arginfo_filter_input, 0, 0, 2)
00084        ZEND_ARG_INFO(0, type)
00085        ZEND_ARG_INFO(0, variable_name)
00086        ZEND_ARG_INFO(0, filter)
00087        ZEND_ARG_INFO(0, options)
00088 ZEND_END_ARG_INFO()
00089 
00090 ZEND_BEGIN_ARG_INFO_EX(arginfo_filter_var, 0, 0, 1)
00091        ZEND_ARG_INFO(0, variable)
00092        ZEND_ARG_INFO(0, filter)
00093        ZEND_ARG_INFO(0, options)
00094 ZEND_END_ARG_INFO()
00095 
00096 ZEND_BEGIN_ARG_INFO_EX(arginfo_filter_input_array, 0, 0, 1)
00097        ZEND_ARG_INFO(0, type)
00098        ZEND_ARG_INFO(0, definition)
00099        ZEND_ARG_INFO(0, add_empty)
00100 ZEND_END_ARG_INFO()
00101 
00102 ZEND_BEGIN_ARG_INFO_EX(arginfo_filter_var_array, 0, 0, 1)
00103        ZEND_ARG_INFO(0, data)
00104        ZEND_ARG_INFO(0, definition)
00105        ZEND_ARG_INFO(0, add_empty)
00106 ZEND_END_ARG_INFO()
00107 
00108 ZEND_BEGIN_ARG_INFO(arginfo_filter_list, 0)
00109 ZEND_END_ARG_INFO()
00110 
00111 ZEND_BEGIN_ARG_INFO_EX(arginfo_filter_has_var, 0, 0, 2)
00112        ZEND_ARG_INFO(0, type)
00113        ZEND_ARG_INFO(0, variable_name)
00114 ZEND_END_ARG_INFO()
00115 
00116 ZEND_BEGIN_ARG_INFO_EX(arginfo_filter_id, 0, 0, 1)
00117        ZEND_ARG_INFO(0, filtername)
00118 ZEND_END_ARG_INFO()
00119 /* }}} */
00120 
00121 /* {{{ filter_functions[]
00122  */
00123 static const zend_function_entry filter_functions[] = {
00124        PHP_FE(filter_input,        arginfo_filter_input)
00125        PHP_FE(filter_var,          arginfo_filter_var)
00126        PHP_FE(filter_input_array,  arginfo_filter_input_array)
00127        PHP_FE(filter_var_array,    arginfo_filter_var_array)
00128        PHP_FE(filter_list,         arginfo_filter_list)
00129        PHP_FE(filter_has_var,             arginfo_filter_has_var)
00130        PHP_FE(filter_id,           arginfo_filter_id)
00131        PHP_FE_END
00132 };
00133 /* }}} */
00134 
00135 /* {{{ filter_module_entry
00136  */
00137 zend_module_entry filter_module_entry = {
00138 #if ZEND_MODULE_API_NO >= 20010901
00139        STANDARD_MODULE_HEADER,
00140 #endif
00141        "filter",
00142        filter_functions,
00143        PHP_MINIT(filter),
00144        PHP_MSHUTDOWN(filter),
00145        NULL,
00146        PHP_RSHUTDOWN(filter),
00147        PHP_MINFO(filter),
00148        "0.11.0",
00149        STANDARD_MODULE_PROPERTIES
00150 };
00151 /* }}} */
00152 
00153 #ifdef COMPILE_DL_FILTER
00154 ZEND_GET_MODULE(filter)
00155 #endif
00156 
00157 static PHP_INI_MH(UpdateDefaultFilter) /* {{{ */
00158 {
00159        int i, size = sizeof(filter_list) / sizeof(filter_list_entry);
00160 
00161        for (i = 0; i < size; ++i) {
00162               if ((strcasecmp(new_value, filter_list[i].name) == 0)) {
00163                      IF_G(default_filter) = filter_list[i].id;
00164                      return SUCCESS;
00165               }
00166        }
00167        /* Fallback to the default filter */
00168        IF_G(default_filter) = FILTER_DEFAULT;
00169        return SUCCESS;
00170 }
00171 /* }}} */
00172 
00173 /* {{{ PHP_INI
00174  */
00175 static PHP_INI_MH(OnUpdateFlags)
00176 {
00177        if (!new_value) {
00178               IF_G(default_filter_flags) = FILTER_FLAG_NO_ENCODE_QUOTES;
00179        } else {
00180               IF_G(default_filter_flags) = atoi(new_value);
00181        }
00182        return SUCCESS;
00183 }
00184 
00185 PHP_INI_BEGIN()
00186        STD_PHP_INI_ENTRY("filter.default",   "unsafe_raw", PHP_INI_SYSTEM|PHP_INI_PERDIR, UpdateDefaultFilter, default_filter, zend_filter_globals, filter_globals)
00187        PHP_INI_ENTRY("filter.default_flags", NULL,     PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateFlags)
00188 PHP_INI_END()
00189 /* }}} */
00190 
00191 static void php_filter_init_globals(zend_filter_globals *filter_globals) /* {{{ */
00192 {
00193        filter_globals->post_array = NULL;
00194        filter_globals->get_array = NULL;
00195        filter_globals->cookie_array = NULL;
00196        filter_globals->env_array = NULL;
00197        filter_globals->server_array = NULL;
00198        filter_globals->session_array = NULL;
00199        filter_globals->default_filter = FILTER_DEFAULT;
00200 }
00201 /* }}} */
00202 
00203 #define PARSE_REQUEST 99
00204 
00205 /* {{{ PHP_MINIT_FUNCTION
00206  */
00207 PHP_MINIT_FUNCTION(filter)
00208 {
00209        ZEND_INIT_MODULE_GLOBALS(filter, php_filter_init_globals, NULL);
00210 
00211        REGISTER_INI_ENTRIES();
00212 
00213        REGISTER_LONG_CONSTANT("INPUT_POST",      PARSE_POST,   CONST_CS | CONST_PERSISTENT);
00214        REGISTER_LONG_CONSTANT("INPUT_GET",              PARSE_GET,           CONST_CS | CONST_PERSISTENT);
00215        REGISTER_LONG_CONSTANT("INPUT_COOKIE",    PARSE_COOKIE,        CONST_CS | CONST_PERSISTENT);
00216        REGISTER_LONG_CONSTANT("INPUT_ENV",              PARSE_ENV,           CONST_CS | CONST_PERSISTENT);
00217        REGISTER_LONG_CONSTANT("INPUT_SERVER",    PARSE_SERVER,        CONST_CS | CONST_PERSISTENT);
00218        REGISTER_LONG_CONSTANT("INPUT_SESSION", PARSE_SESSION,  CONST_CS | CONST_PERSISTENT);
00219        REGISTER_LONG_CONSTANT("INPUT_REQUEST", PARSE_REQUEST,  CONST_CS | CONST_PERSISTENT);
00220 
00221        REGISTER_LONG_CONSTANT("FILTER_FLAG_NONE", FILTER_FLAG_NONE, CONST_CS | CONST_PERSISTENT);
00222 
00223        REGISTER_LONG_CONSTANT("FILTER_REQUIRE_SCALAR", FILTER_REQUIRE_SCALAR, CONST_CS | CONST_PERSISTENT);
00224        REGISTER_LONG_CONSTANT("FILTER_REQUIRE_ARRAY", FILTER_REQUIRE_ARRAY, CONST_CS | CONST_PERSISTENT);
00225        REGISTER_LONG_CONSTANT("FILTER_FORCE_ARRAY", FILTER_FORCE_ARRAY, CONST_CS | CONST_PERSISTENT);
00226        REGISTER_LONG_CONSTANT("FILTER_NULL_ON_FAILURE", FILTER_NULL_ON_FAILURE, CONST_CS | CONST_PERSISTENT);
00227 
00228        REGISTER_LONG_CONSTANT("FILTER_VALIDATE_INT", FILTER_VALIDATE_INT, CONST_CS | CONST_PERSISTENT);
00229        REGISTER_LONG_CONSTANT("FILTER_VALIDATE_BOOLEAN", FILTER_VALIDATE_BOOLEAN, CONST_CS | CONST_PERSISTENT);
00230        REGISTER_LONG_CONSTANT("FILTER_VALIDATE_FLOAT", FILTER_VALIDATE_FLOAT, CONST_CS | CONST_PERSISTENT);
00231 
00232        REGISTER_LONG_CONSTANT("FILTER_VALIDATE_REGEXP", FILTER_VALIDATE_REGEXP, CONST_CS | CONST_PERSISTENT);
00233        REGISTER_LONG_CONSTANT("FILTER_VALIDATE_URL", FILTER_VALIDATE_URL, CONST_CS | CONST_PERSISTENT);
00234        REGISTER_LONG_CONSTANT("FILTER_VALIDATE_EMAIL", FILTER_VALIDATE_EMAIL, CONST_CS | CONST_PERSISTENT);
00235        REGISTER_LONG_CONSTANT("FILTER_VALIDATE_IP", FILTER_VALIDATE_IP, CONST_CS | CONST_PERSISTENT);
00236 
00237        REGISTER_LONG_CONSTANT("FILTER_DEFAULT", FILTER_DEFAULT, CONST_CS | CONST_PERSISTENT);
00238        REGISTER_LONG_CONSTANT("FILTER_UNSAFE_RAW", FILTER_UNSAFE_RAW, CONST_CS | CONST_PERSISTENT);
00239 
00240        REGISTER_LONG_CONSTANT("FILTER_SANITIZE_STRING", FILTER_SANITIZE_STRING, CONST_CS | CONST_PERSISTENT);
00241        REGISTER_LONG_CONSTANT("FILTER_SANITIZE_STRIPPED", FILTER_SANITIZE_STRING, CONST_CS | CONST_PERSISTENT);
00242        REGISTER_LONG_CONSTANT("FILTER_SANITIZE_ENCODED", FILTER_SANITIZE_ENCODED, CONST_CS | CONST_PERSISTENT);
00243        REGISTER_LONG_CONSTANT("FILTER_SANITIZE_SPECIAL_CHARS", FILTER_SANITIZE_SPECIAL_CHARS, CONST_CS | CONST_PERSISTENT);
00244        REGISTER_LONG_CONSTANT("FILTER_SANITIZE_FULL_SPECIAL_CHARS", FILTER_SANITIZE_SPECIAL_CHARS, CONST_CS | CONST_PERSISTENT);
00245        REGISTER_LONG_CONSTANT("FILTER_SANITIZE_EMAIL", FILTER_SANITIZE_EMAIL, CONST_CS | CONST_PERSISTENT);
00246        REGISTER_LONG_CONSTANT("FILTER_SANITIZE_URL", FILTER_SANITIZE_URL, CONST_CS | CONST_PERSISTENT);
00247        REGISTER_LONG_CONSTANT("FILTER_SANITIZE_NUMBER_INT", FILTER_SANITIZE_NUMBER_INT, CONST_CS | CONST_PERSISTENT);
00248        REGISTER_LONG_CONSTANT("FILTER_SANITIZE_NUMBER_FLOAT", FILTER_SANITIZE_NUMBER_FLOAT, CONST_CS | CONST_PERSISTENT);
00249        REGISTER_LONG_CONSTANT("FILTER_SANITIZE_MAGIC_QUOTES", FILTER_SANITIZE_MAGIC_QUOTES, CONST_CS | CONST_PERSISTENT);
00250 
00251        REGISTER_LONG_CONSTANT("FILTER_CALLBACK", FILTER_CALLBACK, CONST_CS | CONST_PERSISTENT);
00252 
00253        REGISTER_LONG_CONSTANT("FILTER_FLAG_ALLOW_OCTAL", FILTER_FLAG_ALLOW_OCTAL, CONST_CS | CONST_PERSISTENT);
00254        REGISTER_LONG_CONSTANT("FILTER_FLAG_ALLOW_HEX", FILTER_FLAG_ALLOW_HEX, CONST_CS | CONST_PERSISTENT);
00255 
00256        REGISTER_LONG_CONSTANT("FILTER_FLAG_STRIP_LOW", FILTER_FLAG_STRIP_LOW, CONST_CS | CONST_PERSISTENT);
00257        REGISTER_LONG_CONSTANT("FILTER_FLAG_STRIP_HIGH", FILTER_FLAG_STRIP_HIGH, CONST_CS | CONST_PERSISTENT);
00258        REGISTER_LONG_CONSTANT("FILTER_FLAG_STRIP_BACKTICK", FILTER_FLAG_STRIP_BACKTICK, CONST_CS | CONST_PERSISTENT);
00259        REGISTER_LONG_CONSTANT("FILTER_FLAG_ENCODE_LOW", FILTER_FLAG_ENCODE_LOW, CONST_CS | CONST_PERSISTENT);
00260        REGISTER_LONG_CONSTANT("FILTER_FLAG_ENCODE_HIGH", FILTER_FLAG_ENCODE_HIGH, CONST_CS | CONST_PERSISTENT);
00261        REGISTER_LONG_CONSTANT("FILTER_FLAG_ENCODE_AMP", FILTER_FLAG_ENCODE_AMP, CONST_CS | CONST_PERSISTENT);
00262        REGISTER_LONG_CONSTANT("FILTER_FLAG_NO_ENCODE_QUOTES", FILTER_FLAG_NO_ENCODE_QUOTES, CONST_CS | CONST_PERSISTENT);
00263        REGISTER_LONG_CONSTANT("FILTER_FLAG_EMPTY_STRING_NULL", FILTER_FLAG_EMPTY_STRING_NULL, CONST_CS | CONST_PERSISTENT);
00264 
00265        REGISTER_LONG_CONSTANT("FILTER_FLAG_ALLOW_FRACTION", FILTER_FLAG_ALLOW_FRACTION, CONST_CS | CONST_PERSISTENT);
00266        REGISTER_LONG_CONSTANT("FILTER_FLAG_ALLOW_THOUSAND", FILTER_FLAG_ALLOW_THOUSAND, CONST_CS | CONST_PERSISTENT);
00267        REGISTER_LONG_CONSTANT("FILTER_FLAG_ALLOW_SCIENTIFIC", FILTER_FLAG_ALLOW_SCIENTIFIC, CONST_CS | CONST_PERSISTENT);
00268 
00269        REGISTER_LONG_CONSTANT("FILTER_FLAG_SCHEME_REQUIRED", FILTER_FLAG_SCHEME_REQUIRED, CONST_CS | CONST_PERSISTENT);
00270        REGISTER_LONG_CONSTANT("FILTER_FLAG_HOST_REQUIRED", FILTER_FLAG_HOST_REQUIRED, CONST_CS | CONST_PERSISTENT);
00271        REGISTER_LONG_CONSTANT("FILTER_FLAG_PATH_REQUIRED", FILTER_FLAG_PATH_REQUIRED, CONST_CS | CONST_PERSISTENT);
00272        REGISTER_LONG_CONSTANT("FILTER_FLAG_QUERY_REQUIRED", FILTER_FLAG_QUERY_REQUIRED, CONST_CS | CONST_PERSISTENT);
00273 
00274        REGISTER_LONG_CONSTANT("FILTER_FLAG_IPV4", FILTER_FLAG_IPV4, CONST_CS | CONST_PERSISTENT);
00275        REGISTER_LONG_CONSTANT("FILTER_FLAG_IPV6", FILTER_FLAG_IPV6, CONST_CS | CONST_PERSISTENT);
00276        REGISTER_LONG_CONSTANT("FILTER_FLAG_NO_RES_RANGE", FILTER_FLAG_NO_RES_RANGE, CONST_CS | CONST_PERSISTENT);
00277        REGISTER_LONG_CONSTANT("FILTER_FLAG_NO_PRIV_RANGE", FILTER_FLAG_NO_PRIV_RANGE, CONST_CS | CONST_PERSISTENT);
00278 
00279        sapi_register_input_filter(php_sapi_filter, php_sapi_filter_init);
00280 
00281        return SUCCESS;
00282 }
00283 /* }}} */
00284 
00285 /* {{{ PHP_MSHUTDOWN_FUNCTION
00286  */
00287 PHP_MSHUTDOWN_FUNCTION(filter)
00288 {
00289        UNREGISTER_INI_ENTRIES();
00290 
00291        return SUCCESS;
00292 }
00293 /* }}} */
00294 
00295 /* {{{ PHP_RSHUTDOWN_FUNCTION
00296  */
00297 #define VAR_ARRAY_COPY_DTOR(a)   \
00298        if (IF_G(a)) {               \
00299               zval_ptr_dtor(&IF_G(a)); \
00300               IF_G(a) = NULL;          \
00301        }
00302 
00303 PHP_RSHUTDOWN_FUNCTION(filter)
00304 {
00305        VAR_ARRAY_COPY_DTOR(get_array)
00306        VAR_ARRAY_COPY_DTOR(post_array)
00307        VAR_ARRAY_COPY_DTOR(cookie_array)
00308        VAR_ARRAY_COPY_DTOR(server_array)
00309        VAR_ARRAY_COPY_DTOR(env_array)
00310        VAR_ARRAY_COPY_DTOR(session_array)
00311        return SUCCESS;
00312 }
00313 /* }}} */
00314 
00315 /* {{{ PHP_MINFO_FUNCTION
00316  */
00317 PHP_MINFO_FUNCTION(filter)
00318 {
00319        php_info_print_table_start();
00320        php_info_print_table_row( 2, "Input Validation and Filtering", "enabled" );
00321        php_info_print_table_row( 2, "Revision", "$Revision: 321634 $");
00322        php_info_print_table_end();
00323 
00324        DISPLAY_INI_ENTRIES();
00325 }
00326 /* }}} */
00327 
00328 static filter_list_entry php_find_filter(long id) /* {{{ */
00329 {
00330        int i, size = sizeof(filter_list) / sizeof(filter_list_entry);
00331 
00332        for (i = 0; i < size; ++i) {
00333               if (filter_list[i].id == id) {
00334                      return filter_list[i];
00335               }
00336        }
00337        /* Fallback to "string" filter */
00338        for (i = 0; i < size; ++i) {
00339               if (filter_list[i].id == FILTER_DEFAULT) {
00340                      return filter_list[i];
00341               }
00342        }
00343        /* To shut up GCC */
00344        return filter_list[0];
00345 }
00346 /* }}} */
00347 
00348 static unsigned int php_sapi_filter_init(TSRMLS_D)
00349 {
00350        IF_G(get_array) = NULL;
00351        IF_G(post_array) = NULL;
00352        IF_G(cookie_array) = NULL;
00353        IF_G(server_array) = NULL;
00354        IF_G(env_array) = NULL;
00355        IF_G(session_array) = NULL;
00356        return SUCCESS;
00357 }
00358 
00359 static void php_zval_filter(zval **value, long filter, long flags, zval *options, char* charset, zend_bool copy TSRMLS_DC) /* {{{ */
00360 {
00361        filter_list_entry  filter_func;
00362 
00363        filter_func = php_find_filter(filter);
00364 
00365        if (!filter_func.id) {
00366               /* Find default filter */
00367               filter_func = php_find_filter(FILTER_DEFAULT);
00368        }
00369 
00370        if (copy) {
00371               SEPARATE_ZVAL(value);
00372        }
00373 
00374        /* #49274, fatal error with object without a toString method
00375          Fails nicely instead of getting a recovarable fatal error. */
00376        if (Z_TYPE_PP(value) == IS_OBJECT) {
00377               zend_class_entry *ce;
00378 
00379               ce = Z_OBJCE_PP(value);
00380               if (!ce->__tostring) {
00381                      ZVAL_FALSE(*value);
00382                      return;
00383               }
00384        }
00385 
00386        /* Here be strings */
00387        convert_to_string(*value);
00388 
00389        filter_func.function(*value, flags, options, charset TSRMLS_CC);
00390 
00391        if (
00392               options && (Z_TYPE_P(options) == IS_ARRAY || Z_TYPE_P(options) == IS_OBJECT) &&
00393               ((flags & FILTER_NULL_ON_FAILURE && Z_TYPE_PP(value) == IS_NULL) || 
00394               (!(flags & FILTER_NULL_ON_FAILURE) && Z_TYPE_PP(value) == IS_BOOL && Z_LVAL_PP(value) == 0)) &&
00395               zend_hash_exists(HASH_OF(options), "default", sizeof("default"))
00396        ) {
00397               zval **tmp; 
00398               if (zend_hash_find(HASH_OF(options), "default", sizeof("default"), (void **)&tmp) == SUCCESS) {
00399                      MAKE_COPY_ZVAL(tmp, *value);
00400               }
00401        }
00402 }
00403 /* }}} */
00404 
00405 static unsigned int php_sapi_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) /* {{{ */
00406 {
00407        zval  new_var, raw_var;
00408        zval *array_ptr = NULL, *orig_array_ptr = NULL;
00409        char *orig_var = NULL;
00410        int retval = 0;
00411 
00412        assert(*val != NULL);
00413 
00414 #define PARSE_CASE(s,a,t)                    \
00415               case s:                              \
00416                      if (!IF_G(a)) {                  \
00417                             ALLOC_ZVAL(array_ptr);       \
00418                             array_init(array_ptr);       \
00419                             INIT_PZVAL(array_ptr);       \
00420                             IF_G(a) = array_ptr;         \
00421                      } else {                         \
00422                             array_ptr = IF_G(a);         \
00423                      }                                \
00424                      orig_array_ptr = PG(http_globals)[t]; \
00425                      break;
00426 
00427        switch (arg) {
00428               PARSE_CASE(PARSE_POST,    post_array,    TRACK_VARS_POST)
00429               PARSE_CASE(PARSE_GET,     get_array,     TRACK_VARS_GET)
00430               PARSE_CASE(PARSE_COOKIE,  cookie_array,  TRACK_VARS_COOKIE)
00431               PARSE_CASE(PARSE_SERVER,  server_array,  TRACK_VARS_SERVER)
00432               PARSE_CASE(PARSE_ENV,     env_array,     TRACK_VARS_ENV)
00433 
00434               case PARSE_STRING: /* PARSE_STRING is used by parse_str() function */
00435                      retval = 1;
00436                      break;
00437        }
00438 
00439        /* 
00440         * According to rfc2965, more specific paths are listed above the less specific ones.
00441         * If we encounter a duplicate cookie name, we should skip it, since it is not possible
00442         * to have the same (plain text) cookie name for the same path and we should not overwrite
00443         * more specific cookies with the less specific ones.
00444        */
00445        if (arg == PARSE_COOKIE && orig_array_ptr && zend_symtable_exists(Z_ARRVAL_P(orig_array_ptr), var, strlen(var)+1)) {
00446               return 0;
00447        }
00448 
00449        if (array_ptr) {
00450               /* Make a copy of the variable name, as php_register_variable_ex seems to
00451                * modify it */
00452               orig_var = estrdup(var);
00453 
00454               /* Store the RAW variable internally */
00455               /* FIXME: Should not use php_register_variable_ex as that also registers
00456                * globals when register_globals is turned on */
00457               Z_STRLEN(raw_var) = val_len;
00458               Z_STRVAL(raw_var) = estrndup(*val, val_len);
00459               Z_TYPE(raw_var) = IS_STRING;
00460 
00461               php_register_variable_ex(var, &raw_var, array_ptr TSRMLS_CC);
00462        }
00463 
00464        if (val_len) {
00465               /* Register mangled variable */
00466               /* FIXME: Should not use php_register_variable_ex as that also registers
00467                * globals when register_globals is turned on */
00468               Z_STRLEN(new_var) = val_len;
00469               Z_TYPE(new_var) = IS_STRING;
00470 
00471               if (IF_G(default_filter) != FILTER_UNSAFE_RAW) {
00472                      zval *tmp_new_var = &new_var;
00473                      Z_STRVAL(new_var) = estrndup(*val, val_len);
00474                      INIT_PZVAL(tmp_new_var);
00475                      php_zval_filter(&tmp_new_var, IF_G(default_filter), IF_G(default_filter_flags), NULL, NULL/*charset*/, 0 TSRMLS_CC);
00476               } else if (PG(magic_quotes_gpc) && !retval) { /* for PARSE_STRING php_register_variable_safe() will do the addslashes() */
00477                      Z_STRVAL(new_var) = php_addslashes(*val, Z_STRLEN(new_var), &Z_STRLEN(new_var), 0 TSRMLS_CC);
00478               } else {
00479                      Z_STRVAL(new_var) = estrndup(*val, val_len);
00480               }
00481        } else { /* empty string */
00482               ZVAL_EMPTY_STRING(&new_var);
00483        }
00484 
00485        if (orig_array_ptr) {
00486               php_register_variable_ex(orig_var, &new_var, orig_array_ptr TSRMLS_CC);
00487        }
00488        if (array_ptr) {
00489               efree(orig_var);
00490        }
00491 
00492        if (retval) {
00493               if (new_val_len) {
00494                      *new_val_len = Z_STRLEN(new_var);
00495               }
00496               efree(*val);
00497               if (Z_STRLEN(new_var)) {
00498                      *val = estrndup(Z_STRVAL(new_var), Z_STRLEN(new_var));
00499               } else {
00500                      *val = estrdup("");
00501               }
00502               zval_dtor(&new_var);
00503        }
00504 
00505        return retval;
00506 }
00507 /* }}} */
00508 
00509 static void php_zval_filter_recursive(zval **value, long filter, long flags, zval *options, char *charset, zend_bool copy TSRMLS_DC) /* {{{ */
00510 {
00511        if (Z_TYPE_PP(value) == IS_ARRAY) {
00512               zval **element;
00513               HashPosition pos;
00514 
00515               if (Z_ARRVAL_PP(value)->nApplyCount > 1) {
00516                      return;
00517               }
00518 
00519               for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(value), &pos);
00520                       zend_hash_get_current_data_ex(Z_ARRVAL_PP(value), (void **) &element, &pos) == SUCCESS;
00521                       zend_hash_move_forward_ex(Z_ARRVAL_PP(value), &pos)
00522               ) {
00523                      SEPARATE_ZVAL_IF_NOT_REF(element);
00524                      if (Z_TYPE_PP(element) == IS_ARRAY) {
00525                             Z_ARRVAL_PP(element)->nApplyCount++;
00526                             php_zval_filter_recursive(element, filter, flags, options, charset, copy TSRMLS_CC);
00527                             Z_ARRVAL_PP(element)->nApplyCount--;
00528                      } else {
00529                             php_zval_filter(element, filter, flags, options, charset, copy TSRMLS_CC);
00530                      }
00531               }
00532        } else {
00533               php_zval_filter(value, filter, flags, options, charset, copy TSRMLS_CC);
00534        }
00535 }
00536 /* }}} */
00537 
00538 static zval *php_filter_get_storage(long arg TSRMLS_DC)/* {{{ */
00539 
00540 {
00541        zval *array_ptr = NULL;
00542        zend_bool jit_initialization = (PG(auto_globals_jit) && !PG(register_globals) && !PG(register_long_arrays));
00543 
00544        switch (arg) {
00545               case PARSE_GET:
00546                      array_ptr = IF_G(get_array);
00547                      break;
00548               case PARSE_POST:
00549                      array_ptr = IF_G(post_array);
00550                      break;
00551               case PARSE_COOKIE:
00552                      array_ptr = IF_G(cookie_array);
00553                      break;
00554               case PARSE_SERVER:
00555                      if (jit_initialization) {
00556                             zend_is_auto_global("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC);
00557                      }
00558                      array_ptr = IF_G(server_array);
00559                      break;
00560               case PARSE_ENV:
00561                      if (jit_initialization) {
00562                             zend_is_auto_global("_ENV", sizeof("_ENV")-1 TSRMLS_CC);
00563                      }
00564                      array_ptr = IF_G(env_array) ? IF_G(env_array) : PG(http_globals)[TRACK_VARS_ENV];
00565                      break;
00566               case PARSE_SESSION:
00567                      /* FIXME: Implement session source */
00568                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "INPUT_SESSION is not yet implemented");
00569                      break;
00570               case PARSE_REQUEST:
00571                      /* FIXME: Implement request source */
00572                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "INPUT_REQUEST is not yet implemented");
00573                      break;
00574        }
00575 
00576        return array_ptr;
00577 }
00578 /* }}} */
00579 
00580 /* {{{ proto mixed filter_has_var(constant type, string variable_name)
00581  * Returns true if the variable with the name 'name' exists in source.
00582  */
00583 PHP_FUNCTION(filter_has_var)
00584 {
00585        long        arg;
00586        char       *var;
00587        int         var_len;
00588        zval       *array_ptr = NULL;
00589 
00590        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &arg, &var, &var_len) == FAILURE) {
00591               RETURN_FALSE;
00592        }
00593 
00594        array_ptr = php_filter_get_storage(arg TSRMLS_CC);
00595 
00596        if (array_ptr && HASH_OF(array_ptr) && zend_hash_exists(HASH_OF(array_ptr), var, var_len + 1)) {
00597               RETURN_TRUE;
00598        }
00599 
00600        RETURN_FALSE;
00601 }
00602 /* }}} */
00603 
00604 static void php_filter_call(zval **filtered, long filter, zval **filter_args, const int copy, long filter_flags TSRMLS_DC) /* {{{ */
00605 {
00606        zval  *options = NULL;
00607        zval **option;
00608        char  *charset = NULL;
00609 
00610        if (filter_args && Z_TYPE_PP(filter_args) != IS_ARRAY) {
00611               long lval;
00612 
00613               PHP_FILTER_GET_LONG_OPT(filter_args, lval);
00614 
00615               if (filter != -1) { /* handler for array apply */
00616                      /* filter_args is the filter_flags */
00617                      filter_flags = lval;
00618 
00619                      if (!(filter_flags & FILTER_REQUIRE_ARRAY ||  filter_flags & FILTER_FORCE_ARRAY)) {
00620                             filter_flags |= FILTER_REQUIRE_SCALAR;
00621                      }
00622               } else {
00623                      filter = lval;
00624               }
00625        } else if (filter_args) {
00626               if (zend_hash_find(HASH_OF(*filter_args), "filter", sizeof("filter"), (void **)&option) == SUCCESS) {
00627                      PHP_FILTER_GET_LONG_OPT(option, filter);
00628               }
00629 
00630               if (zend_hash_find(HASH_OF(*filter_args), "flags", sizeof("flags"), (void **)&option) == SUCCESS) {
00631                      PHP_FILTER_GET_LONG_OPT(option, filter_flags);
00632 
00633                      if (!(filter_flags & FILTER_REQUIRE_ARRAY ||  filter_flags & FILTER_FORCE_ARRAY)) {
00634                             filter_flags |= FILTER_REQUIRE_SCALAR;
00635                      }
00636               }
00637 
00638               if (zend_hash_find(HASH_OF(*filter_args), "options", sizeof("options"), (void **)&option) == SUCCESS) {
00639                      if (filter != FILTER_CALLBACK) {
00640                             if (Z_TYPE_PP(option) == IS_ARRAY) {
00641                                    options = *option;
00642                             }
00643                      } else {
00644                             options = *option;
00645                             filter_flags = 0;
00646                      }
00647               }
00648        }
00649 
00650        if (Z_TYPE_PP(filtered) == IS_ARRAY) {
00651               if (filter_flags & FILTER_REQUIRE_SCALAR) {
00652                      if (copy) {
00653                             SEPARATE_ZVAL(filtered);
00654                      }
00655                      zval_dtor(*filtered);
00656                      if (filter_flags & FILTER_NULL_ON_FAILURE) {
00657                             ZVAL_NULL(*filtered);
00658                      } else {
00659                             ZVAL_FALSE(*filtered);
00660                      }
00661                      return;
00662               }
00663               php_zval_filter_recursive(filtered, filter, filter_flags, options, charset, copy TSRMLS_CC);
00664               return;
00665        }
00666        if (filter_flags & FILTER_REQUIRE_ARRAY) {
00667               if (copy) {
00668                      SEPARATE_ZVAL(filtered);
00669               }
00670               zval_dtor(*filtered);
00671               if (filter_flags & FILTER_NULL_ON_FAILURE) {
00672                      ZVAL_NULL(*filtered);
00673               } else {
00674                      ZVAL_FALSE(*filtered);
00675               }
00676               return;
00677        }
00678 
00679        php_zval_filter(filtered, filter, filter_flags, options, charset, copy TSRMLS_CC);
00680        if (filter_flags & FILTER_FORCE_ARRAY) {
00681               zval *tmp;
00682 
00683               ALLOC_ZVAL(tmp);
00684               MAKE_COPY_ZVAL(filtered, tmp);
00685 
00686               zval_dtor(*filtered);
00687 
00688               array_init(*filtered);
00689               add_next_index_zval(*filtered, tmp);
00690        }
00691 }
00692 /* }}} */
00693 
00694 static void php_filter_array_handler(zval *input, zval **op, zval *return_value, zend_bool add_empty TSRMLS_DC) /* {{{ */
00695 {
00696        char *arg_key;
00697        uint arg_key_len;
00698        ulong index;
00699        HashPosition pos;
00700        zval **tmp, **arg_elm;
00701 
00702        if (!op) {
00703               zval_dtor(return_value);
00704               MAKE_COPY_ZVAL(&input, return_value);
00705               php_filter_call(&return_value, FILTER_DEFAULT, NULL, 0, FILTER_REQUIRE_ARRAY TSRMLS_CC);
00706        } else if (Z_TYPE_PP(op) == IS_LONG) {
00707               zval_dtor(return_value);
00708               MAKE_COPY_ZVAL(&input, return_value);
00709               php_filter_call(&return_value, Z_LVAL_PP(op), NULL, 0, FILTER_REQUIRE_ARRAY TSRMLS_CC);
00710        } else if (Z_TYPE_PP(op) == IS_ARRAY) {
00711               array_init(return_value);
00712 
00713               zend_hash_internal_pointer_reset(Z_ARRVAL_PP(op));
00714               for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(op), &pos);
00715                      zend_hash_get_current_data_ex(Z_ARRVAL_PP(op), (void **) &arg_elm, &pos) == SUCCESS;
00716                      zend_hash_move_forward_ex(Z_ARRVAL_PP(op), &pos))
00717               {
00718                      if (zend_hash_get_current_key_ex(Z_ARRVAL_PP(op), &arg_key, &arg_key_len, &index, 0, &pos) != HASH_KEY_IS_STRING) {
00719                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Numeric keys are not allowed in the definition array");
00720                             zval_dtor(return_value);
00721                             RETURN_FALSE;
00722                      }
00723                      if (arg_key_len < 2) {
00724                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty keys are not allowed in the definition array");
00725                             zval_dtor(return_value);
00726                             RETURN_FALSE;
00727                      }
00728                      if (zend_hash_find(Z_ARRVAL_P(input), arg_key, arg_key_len, (void **)&tmp) != SUCCESS) {
00729                             if (add_empty) {
00730                                    add_assoc_null_ex(return_value, arg_key, arg_key_len);
00731                             }
00732                      } else {
00733                             zval *nval;
00734 
00735                             ALLOC_ZVAL(nval);
00736                             MAKE_COPY_ZVAL(tmp, nval);
00737 
00738                             php_filter_call(&nval, -1, arg_elm, 0, FILTER_REQUIRE_SCALAR TSRMLS_CC);
00739                             add_assoc_zval_ex(return_value, arg_key, arg_key_len, nval);
00740                      }
00741               }
00742        } else {
00743               RETURN_FALSE;
00744        }
00745 }
00746 /* }}} */
00747 
00748 /* {{{ proto mixed filter_input(constant type, string variable_name [, long filter [, mixed options]])
00749  * Returns the filtered variable 'name'* from source `type`.
00750  */
00751 PHP_FUNCTION(filter_input)
00752 {
00753        long   fetch_from, filter = FILTER_DEFAULT;
00754        zval **filter_args = NULL, **tmp;
00755        zval  *input = NULL;
00756        char *var;
00757        int var_len;
00758 
00759        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls|lZ", &fetch_from, &var, &var_len, &filter, &filter_args) == FAILURE) {
00760               return;
00761        }
00762 
00763        if (!PHP_FILTER_ID_EXISTS(filter)) {
00764               RETURN_FALSE;
00765        }
00766 
00767        input = php_filter_get_storage(fetch_from TSRMLS_CC);
00768 
00769        if (!input || !HASH_OF(input) || zend_hash_find(HASH_OF(input), var, var_len + 1, (void **)&tmp) != SUCCESS) {
00770               long filter_flags = 0;
00771               zval **option, **opt, **def;
00772               if (filter_args) {
00773                      if (Z_TYPE_PP(filter_args) == IS_LONG) {
00774                             filter_flags = Z_LVAL_PP(filter_args);
00775                      } else if (Z_TYPE_PP(filter_args) == IS_ARRAY && zend_hash_find(HASH_OF(*filter_args), "flags", sizeof("flags"), (void **)&option) == SUCCESS) {
00776                             PHP_FILTER_GET_LONG_OPT(option, filter_flags);
00777                      }
00778                      if (Z_TYPE_PP(filter_args) == IS_ARRAY && 
00779                             zend_hash_find(HASH_OF(*filter_args), "options", sizeof("options"), (void **)&opt) == SUCCESS &&
00780                             Z_TYPE_PP(opt) == IS_ARRAY &&
00781                             zend_hash_find(HASH_OF(*opt), "default", sizeof("default"), (void **)&def) == SUCCESS
00782                      ) {
00783                             MAKE_COPY_ZVAL(def, return_value);
00784                             return;
00785                      }
00786               }
00787 
00788               /* The FILTER_NULL_ON_FAILURE flag inverts the usual return values of
00789                * the function: normally when validation fails false is returned, and
00790                * when the input value doesn't exist NULL is returned. With the flag
00791                * set, NULL and false should be returned, respectively. Ergo, although
00792                * the code below looks incorrect, it's actually right. */
00793               if (filter_flags & FILTER_NULL_ON_FAILURE) {
00794                      RETURN_FALSE;
00795               } else {
00796                      RETURN_NULL();
00797               }
00798        }
00799 
00800        MAKE_COPY_ZVAL(tmp, return_value);
00801 
00802        php_filter_call(&return_value, filter, filter_args, 1, FILTER_REQUIRE_SCALAR TSRMLS_CC);
00803 }
00804 /* }}} */
00805 
00806 /* {{{ proto mixed filter_var(mixed variable [, long filter [, mixed options]])
00807  * Returns the filtered version of the vriable.
00808  */
00809 PHP_FUNCTION(filter_var)
00810 {
00811        long filter = FILTER_DEFAULT;
00812        zval **filter_args = NULL, *data;
00813 
00814        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/|lZ", &data, &filter, &filter_args) == FAILURE) {
00815               return;
00816        }
00817 
00818        if (!PHP_FILTER_ID_EXISTS(filter)) {
00819               RETURN_FALSE;
00820        }
00821 
00822        MAKE_COPY_ZVAL(&data, return_value);
00823 
00824        php_filter_call(&return_value, filter, filter_args, 1, FILTER_REQUIRE_SCALAR TSRMLS_CC);
00825 }
00826 /* }}} */
00827 
00828 /* {{{ proto mixed filter_input_array(constant type, [, mixed options [, bool add_empty]]])
00829  * Returns an array with all arguments defined in 'definition'.
00830  */
00831 PHP_FUNCTION(filter_input_array)
00832 {
00833        long    fetch_from;
00834        zval   *array_input = NULL, **op = NULL;
00835        zend_bool add_empty = 1;
00836 
00837        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|Zb",  &fetch_from, &op, &add_empty) == FAILURE) {
00838               return;
00839        }
00840 
00841        if (op
00842               && (Z_TYPE_PP(op) != IS_ARRAY)
00843               && (Z_TYPE_PP(op) == IS_LONG && !PHP_FILTER_ID_EXISTS(Z_LVAL_PP(op)))
00844               ) {
00845               RETURN_FALSE;
00846        }
00847 
00848        array_input = php_filter_get_storage(fetch_from TSRMLS_CC);
00849 
00850        if (!array_input || !HASH_OF(array_input)) {
00851               long filter_flags = 0;
00852               zval **option;
00853               if (op) {
00854                      if (Z_TYPE_PP(op) == IS_LONG) {
00855                             filter_flags = Z_LVAL_PP(op);
00856                      } else if (Z_TYPE_PP(op) == IS_ARRAY && zend_hash_find(HASH_OF(*op), "flags", sizeof("flags"), (void **)&option) == SUCCESS) {
00857                             PHP_FILTER_GET_LONG_OPT(option, filter_flags);
00858                      }
00859               }
00860 
00861               /* The FILTER_NULL_ON_FAILURE flag inverts the usual return values of
00862                * the function: normally when validation fails false is returned, and
00863                * when the input value doesn't exist NULL is returned. With the flag
00864                * set, NULL and false should be returned, respectively. Ergo, although
00865                * the code below looks incorrect, it's actually right. */
00866               if (filter_flags & FILTER_NULL_ON_FAILURE) {
00867                      RETURN_FALSE;
00868               } else {
00869                      RETURN_NULL();
00870               }
00871        }
00872 
00873        php_filter_array_handler(array_input, op, return_value, add_empty TSRMLS_CC);
00874 }
00875 /* }}} */
00876 
00877 /* {{{ proto mixed filter_var_array(array data, [, mixed options [, bool add_empty]]])
00878  * Returns an array with all arguments defined in 'definition'.
00879  */
00880 PHP_FUNCTION(filter_var_array)
00881 {
00882        zval *array_input = NULL, **op = NULL;
00883        zend_bool add_empty = 1;
00884 
00885        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|Zb",  &array_input, &op, &add_empty) == FAILURE) {
00886               return;
00887        }
00888 
00889        if (op
00890               && (Z_TYPE_PP(op) != IS_ARRAY)
00891               && (Z_TYPE_PP(op) == IS_LONG && !PHP_FILTER_ID_EXISTS(Z_LVAL_PP(op)))
00892               ) {
00893               RETURN_FALSE;
00894        }
00895 
00896        php_filter_array_handler(array_input, op, return_value, add_empty TSRMLS_CC);
00897 }
00898 /* }}} */
00899 
00900 /* {{{ proto filter_list()
00901  * Returns a list of all supported filters */
00902 PHP_FUNCTION(filter_list)
00903 {
00904        int i, size = sizeof(filter_list) / sizeof(filter_list_entry);
00905 
00906        if (zend_parse_parameters_none() == FAILURE) {
00907               return;
00908        }
00909 
00910        array_init(return_value);
00911        for (i = 0; i < size; ++i) {
00912               add_next_index_string(return_value, (char *)filter_list[i].name, 1);
00913        }
00914 }
00915 /* }}} */
00916 
00917 /* {{{ proto filter_id(string filtername)
00918  * Returns the filter ID belonging to a named filter */
00919 PHP_FUNCTION(filter_id)
00920 {
00921        int i, filter_len;
00922        int size = sizeof(filter_list) / sizeof(filter_list_entry);
00923        char *filter;
00924 
00925        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filter, &filter_len) == FAILURE) {
00926               return;
00927        }
00928 
00929        for (i = 0; i < size; ++i) {
00930               if (strcmp(filter_list[i].name, filter) == 0) {
00931                      RETURN_LONG(filter_list[i].id);
00932               }
00933        }
00934 
00935        RETURN_FALSE;
00936 }
00937 /* }}} */
00938 
00939 /*
00940  * Local variables:
00941  * tab-width: 4
00942  * c-basic-offset: 4
00943  * End:
00944  * vim600: noet sw=4 ts=4 fdm=marker
00945  * vim<600: noet sw=4 ts=4
00946  */