@@ -29,11 +29,12 @@ ZEND_DECLARE_MODULE_GLOBALS(filter)
29
29
30
30
#include "filter_private.h"
31
31
#include "filter_arginfo.h"
32
+ #include "zend_exceptions.h"
32
33
33
34
typedef struct filter_list_entry {
34
35
const char * name ;
35
36
int id ;
36
- void (* function )(PHP_INPUT_FILTER_PARAM_DECL );
37
+ zend_result (* function )(PHP_INPUT_FILTER_PARAM_DECL );
37
38
} filter_list_entry ;
38
39
39
40
/* {{{ filter_list */
@@ -76,6 +77,9 @@ static const filter_list_entry filter_list[] = {
76
77
static unsigned int php_sapi_filter (int arg , const char * var , char * * val , size_t val_len , size_t * new_val_len );
77
78
static unsigned int php_sapi_filter_init (void );
78
79
80
+ zend_class_entry * php_filter_exception_ce ;
81
+ zend_class_entry * php_filter_failed_exception_ce ;
82
+
79
83
/* {{{ filter_module_entry */
80
84
zend_module_entry filter_module_entry = {
81
85
STANDARD_MODULE_HEADER ,
@@ -159,6 +163,9 @@ PHP_MINIT_FUNCTION(filter)
159
163
160
164
sapi_register_input_filter (php_sapi_filter , php_sapi_filter_init );
161
165
166
+ php_filter_exception_ce = register_class_Filter_FilterException (zend_ce_exception );
167
+ php_filter_failed_exception_ce = register_class_Filter_FilterFailedException (php_filter_exception_ce );
168
+
162
169
return SUCCESS ;
163
170
}
164
171
/* }}} */
@@ -250,6 +257,16 @@ static void php_zval_filter(zval *value, zend_long filter, zend_long flags, zval
250
257
ce = Z_OBJCE_P (value );
251
258
if (!ce -> __tostring ) {
252
259
zval_ptr_dtor (value );
260
+ if (flags & FILTER_THROW_ON_FAILURE ) {
261
+ zend_throw_exception_ex (
262
+ php_filter_failed_exception_ce ,
263
+ 0 ,
264
+ "filter validation failed: object of type %s has no __toString() method" ,
265
+ ZSTR_VAL (ce -> name )
266
+ );
267
+ ZVAL_NULL (value );
268
+ return ;
269
+ }
253
270
/* #67167: doesn't return null on failure for objects */
254
271
if (flags & FILTER_NULL_ON_FAILURE ) {
255
272
ZVAL_NULL (value );
@@ -263,7 +280,29 @@ static void php_zval_filter(zval *value, zend_long filter, zend_long flags, zval
263
280
/* Here be strings */
264
281
convert_to_string (value );
265
282
266
- filter_func .function (value , flags , options , charset );
283
+ zend_string * copy_for_throwing = NULL ;
284
+ if (flags & FILTER_THROW_ON_FAILURE ) {
285
+ copy_for_throwing = zend_string_copy (Z_STR_P (value ));
286
+ }
287
+
288
+ zend_result result = filter_func .function (value , flags , options , charset );
289
+
290
+ if (flags & FILTER_THROW_ON_FAILURE ) {
291
+ ZEND_ASSERT (copy_for_throwing != NULL );
292
+ if (result == FAILURE ) {
293
+ zend_throw_exception_ex (
294
+ php_filter_failed_exception_ce ,
295
+ 0 ,
296
+ "filter validation failed: filter %s not satisfied by %s" ,
297
+ filter_func .name ,
298
+ ZSTR_VAL (copy_for_throwing )
299
+ );
300
+ zend_string_delref (copy_for_throwing );
301
+ return ;
302
+ }
303
+ zend_string_delref (copy_for_throwing );
304
+ copy_for_throwing = NULL ;
305
+ }
267
306
268
307
handle_default :
269
308
if (options && Z_TYPE_P (options ) == IS_ARRAY &&
@@ -449,7 +488,8 @@ PHP_FUNCTION(filter_has_var)
449
488
450
489
static void php_filter_call (
451
490
zval * filtered , zend_long filter , HashTable * filter_args_ht , zend_long filter_args_long ,
452
- zend_long filter_flags
491
+ zend_long filter_flags ,
492
+ uint32_t options_arg_num
453
493
) /* {{{ */ {
454
494
zval * options = NULL ;
455
495
char * charset = NULL ;
@@ -491,10 +531,28 @@ static void php_filter_call(
491
531
}
492
532
}
493
533
534
+ /* Cannot use both FILTER_NULL_ON_FAILURE and FILTER_THROW_ON_FAILURE */
535
+ if ((filter_flags & FILTER_NULL_ON_FAILURE ) && (filter_flags & FILTER_THROW_ON_FAILURE )) {
536
+ zval_ptr_dtor (filtered );
537
+ ZVAL_NULL (filtered );
538
+ zend_argument_value_error (
539
+ options_arg_num ,
540
+ "cannot use both FILTER_NULL_ON_FAILURE and FILTER_THROW_ON_FAILURE"
541
+ );
542
+ return ;
543
+ }
544
+
494
545
if (Z_TYPE_P (filtered ) == IS_ARRAY ) {
495
546
if (filter_flags & FILTER_REQUIRE_SCALAR ) {
496
547
zval_ptr_dtor (filtered );
497
- if (filter_flags & FILTER_NULL_ON_FAILURE ) {
548
+ if (filter_flags & FILTER_THROW_ON_FAILURE ) {
549
+ ZVAL_NULL (filtered );
550
+ zend_throw_exception (
551
+ php_filter_failed_exception_ce ,
552
+ "filter validation failed: not a scalar value (got an array)" ,
553
+ 0
554
+ );
555
+ } else if (filter_flags & FILTER_NULL_ON_FAILURE ) {
498
556
ZVAL_NULL (filtered );
499
557
} else {
500
558
ZVAL_FALSE (filtered );
@@ -505,6 +563,17 @@ static void php_filter_call(
505
563
return ;
506
564
}
507
565
if (filter_flags & FILTER_REQUIRE_ARRAY ) {
566
+ if (filter_flags & FILTER_THROW_ON_FAILURE ) {
567
+ zend_throw_exception_ex (
568
+ php_filter_failed_exception_ce ,
569
+ 0 ,
570
+ "filter validation failed: not an array (got %s)" ,
571
+ zend_zval_value_name (filtered )
572
+ );
573
+ zval_ptr_dtor (filtered );
574
+ ZVAL_NULL (filtered );
575
+ return ;
576
+ }
508
577
zval_ptr_dtor (filtered );
509
578
if (filter_flags & FILTER_NULL_ON_FAILURE ) {
510
579
ZVAL_NULL (filtered );
@@ -515,6 +584,10 @@ static void php_filter_call(
515
584
}
516
585
517
586
php_zval_filter (filtered , filter , filter_flags , options , charset );
587
+ // Don't wrap in an array if we are throwing an exception
588
+ if (EG (exception )) {
589
+ return ;
590
+ }
518
591
if (filter_flags & FILTER_FORCE_ARRAY ) {
519
592
zval tmp ;
520
593
ZVAL_COPY_VALUE (& tmp , filtered );
@@ -529,7 +602,7 @@ static void php_filter_array_handler(zval *input, HashTable *op_ht, zend_long op
529
602
) /* {{{ */ {
530
603
if (!op_ht ) {
531
604
ZVAL_DUP (return_value , input );
532
- php_filter_call (return_value , -1 , NULL , op_long , FILTER_REQUIRE_ARRAY );
605
+ php_filter_call (return_value , -1 , NULL , op_long , FILTER_REQUIRE_ARRAY , 2 );
533
606
} else {
534
607
array_init (return_value );
535
608
zend_string * arg_key ;
@@ -556,8 +629,12 @@ static void php_filter_array_handler(zval *input, HashTable *op_ht, zend_long op
556
629
php_filter_call (& nval , -1 ,
557
630
Z_TYPE_P (arg_elm ) == IS_ARRAY ? Z_ARRVAL_P (arg_elm ) : NULL ,
558
631
Z_TYPE_P (arg_elm ) == IS_ARRAY ? 0 : zval_get_long (arg_elm ),
559
- FILTER_REQUIRE_SCALAR
632
+ FILTER_REQUIRE_SCALAR ,
633
+ 2
560
634
);
635
+ if (EG (exception )) {
636
+ RETURN_THROWS ();
637
+ }
561
638
zend_hash_update (Z_ARRVAL_P (return_value ), arg_key , & nval );
562
639
}
563
640
} ZEND_HASH_FOREACH_END ();
@@ -597,11 +674,34 @@ PHP_FUNCTION(filter_input)
597
674
if (!filter_args_ht ) {
598
675
filter_flags = filter_args_long ;
599
676
} else {
600
- zval * option , * opt , * def ;
677
+ zval * option ;
601
678
if ((option = zend_hash_str_find (filter_args_ht , "flags" , sizeof ("flags" ) - 1 )) != NULL ) {
602
679
filter_flags = zval_get_long (option );
603
680
}
681
+ }
682
+
683
+ /* Cannot use both FILTER_NULL_ON_FAILURE and FILTER_THROW_ON_FAILURE */
684
+ if ((filter_flags & FILTER_NULL_ON_FAILURE ) && (filter_flags & FILTER_THROW_ON_FAILURE )) {
685
+ zend_argument_value_error (
686
+ 4 ,
687
+ "cannot use both FILTER_NULL_ON_FAILURE and FILTER_THROW_ON_FAILURE"
688
+ );
689
+ RETURN_THROWS ();
690
+ }
691
+
692
+ if (filter_flags & FILTER_THROW_ON_FAILURE ) {
693
+ zend_throw_exception (
694
+ php_filter_failed_exception_ce ,
695
+ "input value not found" ,
696
+ 0
697
+ );
698
+ RETURN_THROWS ();
699
+ }
604
700
701
+ /* FILTER_THROW_ON_FAILURE overrides defaults, needs to be checked
702
+ * before the default is used. */
703
+ if (filter_args_ht ) {
704
+ zval * opt , * def ;
605
705
if ((opt = zend_hash_str_find_deref (filter_args_ht , "options" , sizeof ("options" ) - 1 )) != NULL &&
606
706
Z_TYPE_P (opt ) == IS_ARRAY &&
607
707
(def = zend_hash_str_find_deref (Z_ARRVAL_P (opt ), "default" , sizeof ("default" ) - 1 )) != NULL
@@ -625,7 +725,7 @@ PHP_FUNCTION(filter_input)
625
725
626
726
ZVAL_DUP (return_value , tmp );
627
727
628
- php_filter_call (return_value , filter , filter_args_ht , filter_args_long , FILTER_REQUIRE_SCALAR );
728
+ php_filter_call (return_value , filter , filter_args_ht , filter_args_long , FILTER_REQUIRE_SCALAR , 4 );
629
729
}
630
730
/* }}} */
631
731
@@ -651,7 +751,7 @@ PHP_FUNCTION(filter_var)
651
751
652
752
ZVAL_DUP (return_value , data );
653
753
654
- php_filter_call (return_value , filter , filter_args_ht , filter_args_long , FILTER_REQUIRE_SCALAR );
754
+ php_filter_call (return_value , filter , filter_args_ht , filter_args_long , FILTER_REQUIRE_SCALAR , 3 );
655
755
}
656
756
/* }}} */
657
757
0 commit comments