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