2 +----------------------------------------------------------------------+
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: Rasmus Lerdorf <rasmus@php.net> |
16 | Derick Rethans <derick@php.net> |
17 | Pierre-A. Joye <pierre@php.net> |
18 | Ilia Alshanetsky <iliaa@php.net> |
19 +----------------------------------------------------------------------+
28 #include "php_filter.h"
30 ZEND_DECLARE_MODULE_GLOBALS(filter
)
32 #include "filter_private.h"
34 typedef struct filter_list_entry
{
37 void (*function
)(PHP_INPUT_FILTER_PARAM_DECL
);
41 static const filter_list_entry filter_list
[] = {
42 { "int", FILTER_VALIDATE_INT
, php_filter_int
},
43 { "boolean", FILTER_VALIDATE_BOOLEAN
, php_filter_boolean
},
44 { "float", FILTER_VALIDATE_FLOAT
, php_filter_float
},
46 { "validate_regexp", FILTER_VALIDATE_REGEXP
, php_filter_validate_regexp
},
47 { "validate_url", FILTER_VALIDATE_URL
, php_filter_validate_url
},
48 { "validate_email", FILTER_VALIDATE_EMAIL
, php_filter_validate_email
},
49 { "validate_ip", FILTER_VALIDATE_IP
, php_filter_validate_ip
},
50 { "validate_mac", FILTER_VALIDATE_MAC
, php_filter_validate_mac
},
52 { "string", FILTER_SANITIZE_STRING
, php_filter_string
},
53 { "stripped", FILTER_SANITIZE_STRING
, php_filter_string
},
54 { "encoded", FILTER_SANITIZE_ENCODED
, php_filter_encoded
},
55 { "special_chars", FILTER_SANITIZE_SPECIAL_CHARS
, php_filter_special_chars
},
56 { "full_special_chars", FILTER_SANITIZE_FULL_SPECIAL_CHARS
, php_filter_full_special_chars
},
57 { "unsafe_raw", FILTER_UNSAFE_RAW
, php_filter_unsafe_raw
},
58 { "email", FILTER_SANITIZE_EMAIL
, php_filter_email
},
59 { "url", FILTER_SANITIZE_URL
, php_filter_url
},
60 { "number_int", FILTER_SANITIZE_NUMBER_INT
, php_filter_number_int
},
61 { "number_float", FILTER_SANITIZE_NUMBER_FLOAT
, php_filter_number_float
},
62 { "magic_quotes", FILTER_SANITIZE_MAGIC_QUOTES
, php_filter_magic_quotes
},
64 { "callback", FILTER_CALLBACK
, php_filter_callback
},
73 #define PARSE_SERVER 5
77 #define PARSE_SESSION 6
80 static unsigned int php_sapi_filter(int arg
, char *var
, char **val
, unsigned int val_len
, unsigned int *new_val_len TSRMLS_DC
);
81 static unsigned int php_sapi_filter_init(TSRMLS_D
);
84 ZEND_BEGIN_ARG_INFO_EX(arginfo_filter_input
, 0, 0, 2)
85 ZEND_ARG_INFO(0, type
)
86 ZEND_ARG_INFO(0, variable_name
)
87 ZEND_ARG_INFO(0, filter
)
88 ZEND_ARG_INFO(0, options
)
91 ZEND_BEGIN_ARG_INFO_EX(arginfo_filter_var
, 0, 0, 1)
92 ZEND_ARG_INFO(0, variable
)
93 ZEND_ARG_INFO(0, filter
)
94 ZEND_ARG_INFO(0, options
)
97 ZEND_BEGIN_ARG_INFO_EX(arginfo_filter_input_array
, 0, 0, 1)
98 ZEND_ARG_INFO(0, type
)
99 ZEND_ARG_INFO(0, definition
)
100 ZEND_ARG_INFO(0, add_empty
)
103 ZEND_BEGIN_ARG_INFO_EX(arginfo_filter_var_array
, 0, 0, 1)
104 ZEND_ARG_INFO(0, data
)
105 ZEND_ARG_INFO(0, definition
)
106 ZEND_ARG_INFO(0, add_empty
)
109 ZEND_BEGIN_ARG_INFO(arginfo_filter_list
, 0)
112 ZEND_BEGIN_ARG_INFO_EX(arginfo_filter_has_var
, 0, 0, 2)
113 ZEND_ARG_INFO(0, type
)
114 ZEND_ARG_INFO(0, variable_name
)
117 ZEND_BEGIN_ARG_INFO_EX(arginfo_filter_id
, 0, 0, 1)
118 ZEND_ARG_INFO(0, filtername
)
122 /* {{{ filter_functions[]
124 static const zend_function_entry filter_functions
[] = {
125 PHP_FE(filter_input
, arginfo_filter_input
)
126 PHP_FE(filter_var
, arginfo_filter_var
)
127 PHP_FE(filter_input_array
, arginfo_filter_input_array
)
128 PHP_FE(filter_var_array
, arginfo_filter_var_array
)
129 PHP_FE(filter_list
, arginfo_filter_list
)
130 PHP_FE(filter_has_var
, arginfo_filter_has_var
)
131 PHP_FE(filter_id
, arginfo_filter_id
)
136 /* {{{ filter_module_entry
138 zend_module_entry filter_module_entry
= {
139 #if ZEND_MODULE_API_NO >= 20010901
140 STANDARD_MODULE_HEADER
,
145 PHP_MSHUTDOWN(filter
),
147 PHP_RSHUTDOWN(filter
),
150 STANDARD_MODULE_PROPERTIES
154 #ifdef COMPILE_DL_FILTER
155 ZEND_GET_MODULE(filter
)
158 static PHP_INI_MH(UpdateDefaultFilter
) /* {{{ */
160 int i
, size
= sizeof(filter_list
) / sizeof(filter_list_entry
);
162 for (i
= 0; i
< size
; ++i
) {
163 if ((strcasecmp(new_value
, filter_list
[i
].name
) == 0)) {
164 IF_G(default_filter
) = filter_list
[i
].id
;
168 /* Fallback to the default filter */
169 IF_G(default_filter
) = FILTER_DEFAULT
;
176 static PHP_INI_MH(OnUpdateFlags
)
179 IF_G(default_filter_flags
) = FILTER_FLAG_NO_ENCODE_QUOTES
;
181 IF_G(default_filter_flags
) = atoi(new_value
);
187 STD_PHP_INI_ENTRY("filter.default", "unsafe_raw", PHP_INI_SYSTEM
|PHP_INI_PERDIR
, UpdateDefaultFilter
, default_filter
, zend_filter_globals
, filter_globals
)
188 PHP_INI_ENTRY("filter.default_flags", NULL
, PHP_INI_SYSTEM
|PHP_INI_PERDIR
, OnUpdateFlags
)
192 static void php_filter_init_globals(zend_filter_globals
*filter_globals
) /* {{{ */
194 filter_globals
->post_array
= NULL
;
195 filter_globals
->get_array
= NULL
;
196 filter_globals
->cookie_array
= NULL
;
197 filter_globals
->env_array
= NULL
;
198 filter_globals
->server_array
= NULL
;
199 filter_globals
->session_array
= NULL
;
200 filter_globals
->default_filter
= FILTER_DEFAULT
;
204 #define PARSE_REQUEST 99
206 /* {{{ PHP_MINIT_FUNCTION
208 PHP_MINIT_FUNCTION(filter
)
210 ZEND_INIT_MODULE_GLOBALS(filter
, php_filter_init_globals
, NULL
);
212 REGISTER_INI_ENTRIES();
214 REGISTER_LONG_CONSTANT("INPUT_POST", PARSE_POST
, CONST_CS
| CONST_PERSISTENT
);
215 REGISTER_LONG_CONSTANT("INPUT_GET", PARSE_GET
, CONST_CS
| CONST_PERSISTENT
);
216 REGISTER_LONG_CONSTANT("INPUT_COOKIE", PARSE_COOKIE
, CONST_CS
| CONST_PERSISTENT
);
217 REGISTER_LONG_CONSTANT("INPUT_ENV", PARSE_ENV
, CONST_CS
| CONST_PERSISTENT
);
218 REGISTER_LONG_CONSTANT("INPUT_SERVER", PARSE_SERVER
, CONST_CS
| CONST_PERSISTENT
);
219 REGISTER_LONG_CONSTANT("INPUT_SESSION", PARSE_SESSION
, CONST_CS
| CONST_PERSISTENT
);
220 REGISTER_LONG_CONSTANT("INPUT_REQUEST", PARSE_REQUEST
, CONST_CS
| CONST_PERSISTENT
);
222 REGISTER_LONG_CONSTANT("FILTER_FLAG_NONE", FILTER_FLAG_NONE
, CONST_CS
| CONST_PERSISTENT
);
224 REGISTER_LONG_CONSTANT("FILTER_REQUIRE_SCALAR", FILTER_REQUIRE_SCALAR
, CONST_CS
| CONST_PERSISTENT
);
225 REGISTER_LONG_CONSTANT("FILTER_REQUIRE_ARRAY", FILTER_REQUIRE_ARRAY
, CONST_CS
| CONST_PERSISTENT
);
226 REGISTER_LONG_CONSTANT("FILTER_FORCE_ARRAY", FILTER_FORCE_ARRAY
, CONST_CS
| CONST_PERSISTENT
);
227 REGISTER_LONG_CONSTANT("FILTER_NULL_ON_FAILURE", FILTER_NULL_ON_FAILURE
, CONST_CS
| CONST_PERSISTENT
);
229 REGISTER_LONG_CONSTANT("FILTER_VALIDATE_INT", FILTER_VALIDATE_INT
, CONST_CS
| CONST_PERSISTENT
);
230 REGISTER_LONG_CONSTANT("FILTER_VALIDATE_BOOLEAN", FILTER_VALIDATE_BOOLEAN
, CONST_CS
| CONST_PERSISTENT
);
231 REGISTER_LONG_CONSTANT("FILTER_VALIDATE_FLOAT", FILTER_VALIDATE_FLOAT
, CONST_CS
| CONST_PERSISTENT
);
233 REGISTER_LONG_CONSTANT("FILTER_VALIDATE_REGEXP", FILTER_VALIDATE_REGEXP
, CONST_CS
| CONST_PERSISTENT
);
234 REGISTER_LONG_CONSTANT("FILTER_VALIDATE_URL", FILTER_VALIDATE_URL
, CONST_CS
| CONST_PERSISTENT
);
235 REGISTER_LONG_CONSTANT("FILTER_VALIDATE_EMAIL", FILTER_VALIDATE_EMAIL
, CONST_CS
| CONST_PERSISTENT
);
236 REGISTER_LONG_CONSTANT("FILTER_VALIDATE_IP", FILTER_VALIDATE_IP
, CONST_CS
| CONST_PERSISTENT
);
237 REGISTER_LONG_CONSTANT("FILTER_VALIDATE_MAC", FILTER_VALIDATE_MAC
, CONST_CS
| CONST_PERSISTENT
);
239 REGISTER_LONG_CONSTANT("FILTER_DEFAULT", FILTER_DEFAULT
, CONST_CS
| CONST_PERSISTENT
);
240 REGISTER_LONG_CONSTANT("FILTER_UNSAFE_RAW", FILTER_UNSAFE_RAW
, CONST_CS
| CONST_PERSISTENT
);
242 REGISTER_LONG_CONSTANT("FILTER_SANITIZE_STRING", FILTER_SANITIZE_STRING
, CONST_CS
| CONST_PERSISTENT
);
243 REGISTER_LONG_CONSTANT("FILTER_SANITIZE_STRIPPED", FILTER_SANITIZE_STRING
, CONST_CS
| CONST_PERSISTENT
);
244 REGISTER_LONG_CONSTANT("FILTER_SANITIZE_ENCODED", FILTER_SANITIZE_ENCODED
, CONST_CS
| CONST_PERSISTENT
);
245 REGISTER_LONG_CONSTANT("FILTER_SANITIZE_SPECIAL_CHARS", FILTER_SANITIZE_SPECIAL_CHARS
, CONST_CS
| CONST_PERSISTENT
);
246 REGISTER_LONG_CONSTANT("FILTER_SANITIZE_FULL_SPECIAL_CHARS", FILTER_SANITIZE_FULL_SPECIAL_CHARS
, CONST_CS
| CONST_PERSISTENT
);
247 REGISTER_LONG_CONSTANT("FILTER_SANITIZE_EMAIL", FILTER_SANITIZE_EMAIL
, CONST_CS
| CONST_PERSISTENT
);
248 REGISTER_LONG_CONSTANT("FILTER_SANITIZE_URL", FILTER_SANITIZE_URL
, CONST_CS
| CONST_PERSISTENT
);
249 REGISTER_LONG_CONSTANT("FILTER_SANITIZE_NUMBER_INT", FILTER_SANITIZE_NUMBER_INT
, CONST_CS
| CONST_PERSISTENT
);
250 REGISTER_LONG_CONSTANT("FILTER_SANITIZE_NUMBER_FLOAT", FILTER_SANITIZE_NUMBER_FLOAT
, CONST_CS
| CONST_PERSISTENT
);
251 REGISTER_LONG_CONSTANT("FILTER_SANITIZE_MAGIC_QUOTES", FILTER_SANITIZE_MAGIC_QUOTES
, CONST_CS
| CONST_PERSISTENT
);
253 REGISTER_LONG_CONSTANT("FILTER_CALLBACK", FILTER_CALLBACK
, CONST_CS
| CONST_PERSISTENT
);
255 REGISTER_LONG_CONSTANT("FILTER_FLAG_ALLOW_OCTAL", FILTER_FLAG_ALLOW_OCTAL
, CONST_CS
| CONST_PERSISTENT
);
256 REGISTER_LONG_CONSTANT("FILTER_FLAG_ALLOW_HEX", FILTER_FLAG_ALLOW_HEX
, CONST_CS
| CONST_PERSISTENT
);
258 REGISTER_LONG_CONSTANT("FILTER_FLAG_STRIP_LOW", FILTER_FLAG_STRIP_LOW
, CONST_CS
| CONST_PERSISTENT
);
259 REGISTER_LONG_CONSTANT("FILTER_FLAG_STRIP_HIGH", FILTER_FLAG_STRIP_HIGH
, CONST_CS
| CONST_PERSISTENT
);
260 REGISTER_LONG_CONSTANT("FILTER_FLAG_STRIP_BACKTICK", FILTER_FLAG_STRIP_BACKTICK
, CONST_CS
| CONST_PERSISTENT
);
261 REGISTER_LONG_CONSTANT("FILTER_FLAG_ENCODE_LOW", FILTER_FLAG_ENCODE_LOW
, CONST_CS
| CONST_PERSISTENT
);
262 REGISTER_LONG_CONSTANT("FILTER_FLAG_ENCODE_HIGH", FILTER_FLAG_ENCODE_HIGH
, CONST_CS
| CONST_PERSISTENT
);
263 REGISTER_LONG_CONSTANT("FILTER_FLAG_ENCODE_AMP", FILTER_FLAG_ENCODE_AMP
, CONST_CS
| CONST_PERSISTENT
);
264 REGISTER_LONG_CONSTANT("FILTER_FLAG_NO_ENCODE_QUOTES", FILTER_FLAG_NO_ENCODE_QUOTES
, CONST_CS
| CONST_PERSISTENT
);
265 REGISTER_LONG_CONSTANT("FILTER_FLAG_EMPTY_STRING_NULL", FILTER_FLAG_EMPTY_STRING_NULL
, CONST_CS
| CONST_PERSISTENT
);
267 REGISTER_LONG_CONSTANT("FILTER_FLAG_ALLOW_FRACTION", FILTER_FLAG_ALLOW_FRACTION
, CONST_CS
| CONST_PERSISTENT
);
268 REGISTER_LONG_CONSTANT("FILTER_FLAG_ALLOW_THOUSAND", FILTER_FLAG_ALLOW_THOUSAND
, CONST_CS
| CONST_PERSISTENT
);
269 REGISTER_LONG_CONSTANT("FILTER_FLAG_ALLOW_SCIENTIFIC", FILTER_FLAG_ALLOW_SCIENTIFIC
, CONST_CS
| CONST_PERSISTENT
);
271 REGISTER_LONG_CONSTANT("FILTER_FLAG_SCHEME_REQUIRED", FILTER_FLAG_SCHEME_REQUIRED
, CONST_CS
| CONST_PERSISTENT
);
272 REGISTER_LONG_CONSTANT("FILTER_FLAG_HOST_REQUIRED", FILTER_FLAG_HOST_REQUIRED
, CONST_CS
| CONST_PERSISTENT
);
273 REGISTER_LONG_CONSTANT("FILTER_FLAG_PATH_REQUIRED", FILTER_FLAG_PATH_REQUIRED
, CONST_CS
| CONST_PERSISTENT
);
274 REGISTER_LONG_CONSTANT("FILTER_FLAG_QUERY_REQUIRED", FILTER_FLAG_QUERY_REQUIRED
, CONST_CS
| CONST_PERSISTENT
);
276 REGISTER_LONG_CONSTANT("FILTER_FLAG_IPV4", FILTER_FLAG_IPV4
, CONST_CS
| CONST_PERSISTENT
);
277 REGISTER_LONG_CONSTANT("FILTER_FLAG_IPV6", FILTER_FLAG_IPV6
, CONST_CS
| CONST_PERSISTENT
);
278 REGISTER_LONG_CONSTANT("FILTER_FLAG_NO_RES_RANGE", FILTER_FLAG_NO_RES_RANGE
, CONST_CS
| CONST_PERSISTENT
);
279 REGISTER_LONG_CONSTANT("FILTER_FLAG_NO_PRIV_RANGE", FILTER_FLAG_NO_PRIV_RANGE
, CONST_CS
| CONST_PERSISTENT
);
281 sapi_register_input_filter(php_sapi_filter
, php_sapi_filter_init TSRMLS_CC
);
287 /* {{{ PHP_MSHUTDOWN_FUNCTION
289 PHP_MSHUTDOWN_FUNCTION(filter
)
291 UNREGISTER_INI_ENTRIES();
297 /* {{{ PHP_RSHUTDOWN_FUNCTION
299 #define VAR_ARRAY_COPY_DTOR(a) \
301 zval_ptr_dtor(&IF_G(a)); \
305 PHP_RSHUTDOWN_FUNCTION(filter
)
307 VAR_ARRAY_COPY_DTOR(get_array
)
308 VAR_ARRAY_COPY_DTOR(post_array
)
309 VAR_ARRAY_COPY_DTOR(cookie_array
)
310 VAR_ARRAY_COPY_DTOR(server_array
)
311 VAR_ARRAY_COPY_DTOR(env_array
)
312 VAR_ARRAY_COPY_DTOR(session_array
)
317 /* {{{ PHP_MINFO_FUNCTION
319 PHP_MINFO_FUNCTION(filter
)
321 php_info_print_table_start();
322 php_info_print_table_row( 2, "Input Validation and Filtering", "enabled" );
323 php_info_print_table_row( 2, "Revision", "$Id$");
324 php_info_print_table_end();
326 DISPLAY_INI_ENTRIES();
330 static filter_list_entry
php_find_filter(long id
) /* {{{ */
332 int i
, size
= sizeof(filter_list
) / sizeof(filter_list_entry
);
334 for (i
= 0; i
< size
; ++i
) {
335 if (filter_list
[i
].id
== id
) {
336 return filter_list
[i
];
339 /* Fallback to "string" filter */
340 for (i
= 0; i
< size
; ++i
) {
341 if (filter_list
[i
].id
== FILTER_DEFAULT
) {
342 return filter_list
[i
];
346 return filter_list
[0];
350 static unsigned int php_sapi_filter_init(TSRMLS_D
)
352 IF_G(get_array
) = NULL
;
353 IF_G(post_array
) = NULL
;
354 IF_G(cookie_array
) = NULL
;
355 IF_G(server_array
) = NULL
;
356 IF_G(env_array
) = NULL
;
357 IF_G(session_array
) = NULL
;
361 static void php_zval_filter(zval
**value
, long filter
, long flags
, zval
*options
, char* charset
, zend_bool copy TSRMLS_DC
) /* {{{ */
363 filter_list_entry filter_func
;
365 filter_func
= php_find_filter(filter
);
367 if (!filter_func
.id
) {
368 /* Find default filter */
369 filter_func
= php_find_filter(FILTER_DEFAULT
);
373 SEPARATE_ZVAL(value
);
376 /* #49274, fatal error with object without a toString method
377 Fails nicely instead of getting a recovarable fatal error. */
378 if (Z_TYPE_PP(value
) == IS_OBJECT
) {
379 zend_class_entry
*ce
;
381 ce
= Z_OBJCE_PP(value
);
382 if (!ce
->__tostring
) {
388 /* Here be strings */
389 convert_to_string(*value
);
391 filter_func
.function(*value
, flags
, options
, charset TSRMLS_CC
);
394 options
&& (Z_TYPE_P(options
) == IS_ARRAY
|| Z_TYPE_P(options
) == IS_OBJECT
) &&
395 ((flags
& FILTER_NULL_ON_FAILURE
&& Z_TYPE_PP(value
) == IS_NULL
) ||
396 (!(flags
& FILTER_NULL_ON_FAILURE
) && Z_TYPE_PP(value
) == IS_BOOL
&& Z_LVAL_PP(value
) == 0)) &&
397 zend_hash_exists(HASH_OF(options
), "default", sizeof("default"))
400 if (zend_hash_find(HASH_OF(options
), "default", sizeof("default"), (void **)&tmp
) == SUCCESS
) {
401 MAKE_COPY_ZVAL(tmp
, *value
);
407 static unsigned int php_sapi_filter(int arg
, char *var
, char **val
, unsigned int val_len
, unsigned int *new_val_len TSRMLS_DC
) /* {{{ */
409 zval new_var
, raw_var
;
410 zval
*array_ptr
= NULL
, *orig_array_ptr
= NULL
;
413 assert(*val
!= NULL
);
415 #define PARSE_CASE(s,a,t) \
418 ALLOC_ZVAL(array_ptr); \
419 array_init(array_ptr); \
420 INIT_PZVAL(array_ptr); \
421 IF_G(a) = array_ptr; \
423 array_ptr = IF_G(a); \
425 orig_array_ptr = PG(http_globals)[t]; \
429 PARSE_CASE(PARSE_POST
, post_array
, TRACK_VARS_POST
)
430 PARSE_CASE(PARSE_GET
, get_array
, TRACK_VARS_GET
)
431 PARSE_CASE(PARSE_COOKIE
, cookie_array
, TRACK_VARS_COOKIE
)
432 PARSE_CASE(PARSE_SERVER
, server_array
, TRACK_VARS_SERVER
)
433 PARSE_CASE(PARSE_ENV
, env_array
, TRACK_VARS_ENV
)
435 case PARSE_STRING
: /* PARSE_STRING is used by parse_str() function */
441 * According to rfc2965, more specific paths are listed above the less specific ones.
442 * If we encounter a duplicate cookie name, we should skip it, since it is not possible
443 * to have the same (plain text) cookie name for the same path and we should not overwrite
444 * more specific cookies with the less specific ones.
446 if (arg
== PARSE_COOKIE
&& orig_array_ptr
&& zend_symtable_exists(Z_ARRVAL_P(orig_array_ptr
), var
, strlen(var
)+1)) {
451 /* Store the RAW variable internally */
452 Z_STRLEN(raw_var
) = val_len
;
453 Z_STRVAL(raw_var
) = estrndup(*val
, val_len
);
454 Z_TYPE(raw_var
) = IS_STRING
;
456 php_register_variable_ex(var
, &raw_var
, array_ptr TSRMLS_CC
);
460 /* Register mangled variable */
461 Z_STRLEN(new_var
) = val_len
;
462 Z_TYPE(new_var
) = IS_STRING
;
464 if (IF_G(default_filter
) != FILTER_UNSAFE_RAW
) {
465 zval
*tmp_new_var
= &new_var
;
466 Z_STRVAL(new_var
) = estrndup(*val
, val_len
);
467 INIT_PZVAL(tmp_new_var
);
468 php_zval_filter(&tmp_new_var
, IF_G(default_filter
), IF_G(default_filter_flags
), NULL
, NULL
/*charset*/, 0 TSRMLS_CC
);
470 Z_STRVAL(new_var
) = estrndup(*val
, val_len
);
472 } else { /* empty string */
473 ZVAL_EMPTY_STRING(&new_var
);
476 if (orig_array_ptr
) {
477 php_register_variable_ex(var
, &new_var
, orig_array_ptr TSRMLS_CC
);
482 *new_val_len
= Z_STRLEN(new_var
);
485 if (Z_STRLEN(new_var
)) {
486 *val
= estrndup(Z_STRVAL(new_var
), Z_STRLEN(new_var
));
497 static void php_zval_filter_recursive(zval
**value
, long filter
, long flags
, zval
*options
, char *charset
, zend_bool copy TSRMLS_DC
) /* {{{ */
499 if (Z_TYPE_PP(value
) == IS_ARRAY
) {
503 if (Z_ARRVAL_PP(value
)->nApplyCount
> 1) {
507 for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(value
), &pos
);
508 zend_hash_get_current_data_ex(Z_ARRVAL_PP(value
), (void **) &element
, &pos
) == SUCCESS
;
509 zend_hash_move_forward_ex(Z_ARRVAL_PP(value
), &pos
)
511 SEPARATE_ZVAL_IF_NOT_REF(element
);
512 if (Z_TYPE_PP(element
) == IS_ARRAY
) {
513 Z_ARRVAL_PP(element
)->nApplyCount
++;
514 php_zval_filter_recursive(element
, filter
, flags
, options
, charset
, copy TSRMLS_CC
);
515 Z_ARRVAL_PP(element
)->nApplyCount
--;
517 php_zval_filter(element
, filter
, flags
, options
, charset
, copy TSRMLS_CC
);
521 php_zval_filter(value
, filter
, flags
, options
, charset
, copy TSRMLS_CC
);
526 static zval
*php_filter_get_storage(long arg TSRMLS_DC
)/* {{{ */
529 zval
*array_ptr
= NULL
;
533 array_ptr
= IF_G(get_array
);
536 array_ptr
= IF_G(post_array
);
539 array_ptr
= IF_G(cookie_array
);
542 if (PG(auto_globals_jit
)) {
543 zend_is_auto_global("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC
);
545 array_ptr
= IF_G(server_array
);
548 if (PG(auto_globals_jit
)) {
549 zend_is_auto_global("_ENV", sizeof("_ENV")-1 TSRMLS_CC
);
551 array_ptr
= IF_G(env_array
) ? IF_G(env_array
) : PG(http_globals
)[TRACK_VARS_ENV
];
554 /* FIXME: Implement session source */
555 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "INPUT_SESSION is not yet implemented");
558 /* FIXME: Implement request source */
559 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "INPUT_REQUEST is not yet implemented");
567 /* {{{ proto mixed filter_has_var(constant type, string variable_name)
568 * Returns true if the variable with the name 'name' exists in source.
570 PHP_FUNCTION(filter_has_var
)
575 zval
*array_ptr
= NULL
;
577 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "ls", &arg
, &var
, &var_len
) == FAILURE
) {
581 array_ptr
= php_filter_get_storage(arg TSRMLS_CC
);
583 if (array_ptr
&& HASH_OF(array_ptr
) && zend_hash_exists(HASH_OF(array_ptr
), var
, var_len
+ 1)) {
591 static void php_filter_call(zval
**filtered
, long filter
, zval
**filter_args
, const int copy
, long filter_flags TSRMLS_DC
) /* {{{ */
593 zval
*options
= NULL
;
595 char *charset
= NULL
;
597 if (filter_args
&& Z_TYPE_PP(filter_args
) != IS_ARRAY
) {
600 PHP_FILTER_GET_LONG_OPT(filter_args
, lval
);
602 if (filter
!= -1) { /* handler for array apply */
603 /* filter_args is the filter_flags */
606 if (!(filter_flags
& FILTER_REQUIRE_ARRAY
|| filter_flags
& FILTER_FORCE_ARRAY
)) {
607 filter_flags
|= FILTER_REQUIRE_SCALAR
;
612 } else if (filter_args
) {
613 if (zend_hash_find(HASH_OF(*filter_args
), "filter", sizeof("filter"), (void **)&option
) == SUCCESS
) {
614 PHP_FILTER_GET_LONG_OPT(option
, filter
);
617 if (zend_hash_find(HASH_OF(*filter_args
), "flags", sizeof("flags"), (void **)&option
) == SUCCESS
) {
618 PHP_FILTER_GET_LONG_OPT(option
, filter_flags
);
620 if (!(filter_flags
& FILTER_REQUIRE_ARRAY
|| filter_flags
& FILTER_FORCE_ARRAY
)) {
621 filter_flags
|= FILTER_REQUIRE_SCALAR
;
625 if (zend_hash_find(HASH_OF(*filter_args
), "options", sizeof("options"), (void **)&option
) == SUCCESS
) {
626 if (filter
!= FILTER_CALLBACK
) {
627 if (Z_TYPE_PP(option
) == IS_ARRAY
) {
637 if (Z_TYPE_PP(filtered
) == IS_ARRAY
) {
638 if (filter_flags
& FILTER_REQUIRE_SCALAR
) {
640 SEPARATE_ZVAL(filtered
);
642 zval_dtor(*filtered
);
643 if (filter_flags
& FILTER_NULL_ON_FAILURE
) {
644 ZVAL_NULL(*filtered
);
646 ZVAL_FALSE(*filtered
);
650 php_zval_filter_recursive(filtered
, filter
, filter_flags
, options
, charset
, copy TSRMLS_CC
);
653 if (filter_flags
& FILTER_REQUIRE_ARRAY
) {
655 SEPARATE_ZVAL(filtered
);
657 zval_dtor(*filtered
);
658 if (filter_flags
& FILTER_NULL_ON_FAILURE
) {
659 ZVAL_NULL(*filtered
);
661 ZVAL_FALSE(*filtered
);
666 php_zval_filter(filtered
, filter
, filter_flags
, options
, charset
, copy TSRMLS_CC
);
667 if (filter_flags
& FILTER_FORCE_ARRAY
) {
671 MAKE_COPY_ZVAL(filtered
, tmp
);
673 zval_dtor(*filtered
);
675 array_init(*filtered
);
676 add_next_index_zval(*filtered
, tmp
);
681 static void php_filter_array_handler(zval
*input
, zval
**op
, zval
*return_value
, zend_bool add_empty TSRMLS_DC
) /* {{{ */
687 zval
**tmp
, **arg_elm
;
690 zval_dtor(return_value
);
691 MAKE_COPY_ZVAL(&input
, return_value
);
692 php_filter_call(&return_value
, FILTER_DEFAULT
, NULL
, 0, FILTER_REQUIRE_ARRAY TSRMLS_CC
);
693 } else if (Z_TYPE_PP(op
) == IS_LONG
) {
694 zval_dtor(return_value
);
695 MAKE_COPY_ZVAL(&input
, return_value
);
696 php_filter_call(&return_value
, Z_LVAL_PP(op
), NULL
, 0, FILTER_REQUIRE_ARRAY TSRMLS_CC
);
697 } else if (Z_TYPE_PP(op
) == IS_ARRAY
) {
698 array_init(return_value
);
700 zend_hash_internal_pointer_reset(Z_ARRVAL_PP(op
));
701 for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(op
), &pos
);
702 zend_hash_get_current_data_ex(Z_ARRVAL_PP(op
), (void **) &arg_elm
, &pos
) == SUCCESS
;
703 zend_hash_move_forward_ex(Z_ARRVAL_PP(op
), &pos
))
705 if (zend_hash_get_current_key_ex(Z_ARRVAL_PP(op
), &arg_key
, &arg_key_len
, &index
, 0, &pos
) != HASH_KEY_IS_STRING
) {
706 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Numeric keys are not allowed in the definition array");
707 zval_dtor(return_value
);
710 if (arg_key_len
< 2) {
711 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Empty keys are not allowed in the definition array");
712 zval_dtor(return_value
);
715 if (zend_hash_find(Z_ARRVAL_P(input
), arg_key
, arg_key_len
, (void **)&tmp
) != SUCCESS
) {
717 add_assoc_null_ex(return_value
, arg_key
, arg_key_len
);
723 MAKE_COPY_ZVAL(tmp
, nval
);
725 php_filter_call(&nval
, -1, arg_elm
, 0, FILTER_REQUIRE_SCALAR TSRMLS_CC
);
726 add_assoc_zval_ex(return_value
, arg_key
, arg_key_len
, nval
);
735 /* {{{ proto mixed filter_input(constant type, string variable_name [, long filter [, mixed options]])
736 * Returns the filtered variable 'name'* from source `type`.
738 PHP_FUNCTION(filter_input
)
740 long fetch_from
, filter
= FILTER_DEFAULT
;
741 zval
**filter_args
= NULL
, **tmp
;
746 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "ls|lZ", &fetch_from
, &var
, &var_len
, &filter
, &filter_args
) == FAILURE
) {
750 if (!PHP_FILTER_ID_EXISTS(filter
)) {
754 input
= php_filter_get_storage(fetch_from TSRMLS_CC
);
756 if (!input
|| !HASH_OF(input
) || zend_hash_find(HASH_OF(input
), var
, var_len
+ 1, (void **)&tmp
) != SUCCESS
) {
757 long filter_flags
= 0;
758 zval
**option
, **opt
, **def
;
760 if (Z_TYPE_PP(filter_args
) == IS_LONG
) {
761 filter_flags
= Z_LVAL_PP(filter_args
);
762 } else if (Z_TYPE_PP(filter_args
) == IS_ARRAY
&& zend_hash_find(HASH_OF(*filter_args
), "flags", sizeof("flags"), (void **)&option
) == SUCCESS
) {
763 PHP_FILTER_GET_LONG_OPT(option
, filter_flags
);
765 if (Z_TYPE_PP(filter_args
) == IS_ARRAY
&&
766 zend_hash_find(HASH_OF(*filter_args
), "options", sizeof("options"), (void **)&opt
) == SUCCESS
&&
767 Z_TYPE_PP(opt
) == IS_ARRAY
&&
768 zend_hash_find(HASH_OF(*opt
), "default", sizeof("default"), (void **)&def
) == SUCCESS
770 MAKE_COPY_ZVAL(def
, return_value
);
775 /* The FILTER_NULL_ON_FAILURE flag inverts the usual return values of
776 * the function: normally when validation fails false is returned, and
777 * when the input value doesn't exist NULL is returned. With the flag
778 * set, NULL and false should be returned, respectively. Ergo, although
779 * the code below looks incorrect, it's actually right. */
780 if (filter_flags
& FILTER_NULL_ON_FAILURE
) {
787 MAKE_COPY_ZVAL(tmp
, return_value
);
789 php_filter_call(&return_value
, filter
, filter_args
, 1, FILTER_REQUIRE_SCALAR TSRMLS_CC
);
793 /* {{{ proto mixed filter_var(mixed variable [, long filter [, mixed options]])
794 * Returns the filtered version of the vriable.
796 PHP_FUNCTION(filter_var
)
798 long filter
= FILTER_DEFAULT
;
799 zval
**filter_args
= NULL
, *data
;
801 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "z/|lZ", &data
, &filter
, &filter_args
) == FAILURE
) {
805 if (!PHP_FILTER_ID_EXISTS(filter
)) {
809 MAKE_COPY_ZVAL(&data
, return_value
);
811 php_filter_call(&return_value
, filter
, filter_args
, 1, FILTER_REQUIRE_SCALAR TSRMLS_CC
);
815 /* {{{ proto mixed filter_input_array(constant type, [, mixed options [, bool add_empty]]])
816 * Returns an array with all arguments defined in 'definition'.
818 PHP_FUNCTION(filter_input_array
)
821 zval
*array_input
= NULL
, **op
= NULL
;
822 zend_bool add_empty
= 1;
824 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l|Zb", &fetch_from
, &op
, &add_empty
) == FAILURE
) {
829 && (Z_TYPE_PP(op
) != IS_ARRAY
)
830 && (Z_TYPE_PP(op
) == IS_LONG
&& !PHP_FILTER_ID_EXISTS(Z_LVAL_PP(op
)))
835 array_input
= php_filter_get_storage(fetch_from TSRMLS_CC
);
837 if (!array_input
|| !HASH_OF(array_input
)) {
838 long filter_flags
= 0;
841 if (Z_TYPE_PP(op
) == IS_LONG
) {
842 filter_flags
= Z_LVAL_PP(op
);
843 } else if (Z_TYPE_PP(op
) == IS_ARRAY
&& zend_hash_find(HASH_OF(*op
), "flags", sizeof("flags"), (void **)&option
) == SUCCESS
) {
844 PHP_FILTER_GET_LONG_OPT(option
, filter_flags
);
848 /* The FILTER_NULL_ON_FAILURE flag inverts the usual return values of
849 * the function: normally when validation fails false is returned, and
850 * when the input value doesn't exist NULL is returned. With the flag
851 * set, NULL and false should be returned, respectively. Ergo, although
852 * the code below looks incorrect, it's actually right. */
853 if (filter_flags
& FILTER_NULL_ON_FAILURE
) {
860 php_filter_array_handler(array_input
, op
, return_value
, add_empty TSRMLS_CC
);
864 /* {{{ proto mixed filter_var_array(array data, [, mixed options [, bool add_empty]]])
865 * Returns an array with all arguments defined in 'definition'.
867 PHP_FUNCTION(filter_var_array
)
869 zval
*array_input
= NULL
, **op
= NULL
;
870 zend_bool add_empty
= 1;
872 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "a|Zb", &array_input
, &op
, &add_empty
) == FAILURE
) {
877 && (Z_TYPE_PP(op
) != IS_ARRAY
)
878 && (Z_TYPE_PP(op
) == IS_LONG
&& !PHP_FILTER_ID_EXISTS(Z_LVAL_PP(op
)))
883 php_filter_array_handler(array_input
, op
, return_value
, add_empty TSRMLS_CC
);
887 /* {{{ proto filter_list()
888 * Returns a list of all supported filters */
889 PHP_FUNCTION(filter_list
)
891 int i
, size
= sizeof(filter_list
) / sizeof(filter_list_entry
);
893 if (zend_parse_parameters_none() == FAILURE
) {
897 array_init(return_value
);
898 for (i
= 0; i
< size
; ++i
) {
899 add_next_index_string(return_value
, (char *)filter_list
[i
].name
, 1);
904 /* {{{ proto filter_id(string filtername)
905 * Returns the filter ID belonging to a named filter */
906 PHP_FUNCTION(filter_id
)
909 int size
= sizeof(filter_list
) / sizeof(filter_list_entry
);
912 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &filter
, &filter_len
) == FAILURE
) {
916 for (i
= 0; i
< size
; ++i
) {
917 if (strcmp(filter_list
[i
].name
, filter
) == 0) {
918 RETURN_LONG(filter_list
[i
].id
);
931 * vim600: noet sw=4 ts=4 fdm=marker
932 * vim<600: noet sw=4 ts=4