@@ -180,6 +180,10 @@ static zend_always_inline zend_string *zend_add_interned_string(zend_string *str
180180 GC_SET_REFCOUNT (str , 1 );
181181 GC_ADD_FLAGS (str , IS_STR_INTERNED | flags );
182182
183+ if (!ZSTR_IS_VALID_UTF8 (str ) && zend_string_validate_utf8 (str )) {
184+ GC_ADD_FLAGS (str , IS_STR_VALID_UTF8 );
185+ }
186+
183187 ZVAL_INTERNED_STR (& val , str );
184188
185189 zend_hash_add_new (interned_strings , str , & val );
@@ -493,3 +497,45 @@ ZEND_API zend_string *zend_string_concat3(
493497
494498 return res ;
495499}
500+
501+ // Copyright (c) 2008-2009 Bjoern Hoehrmann <[email protected] > 502+ // See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
503+ // https://stackoverflow.com/a/22135005/1320374
504+
505+ enum {
506+ UTF8_ACCEPT = 0 ,
507+ UTF8_REJECT = 1 ,
508+ };
509+
510+ static const uint8_t utf8d [] = {
511+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 00..1f
512+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 20..3f
513+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 40..5f
514+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 60..7f
515+ 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 , // 80..9f
516+ 7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 , // a0..bf
517+ 8 ,8 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 , // c0..df
518+ 0xa ,0x3 ,0x3 ,0x3 ,0x3 ,0x3 ,0x3 ,0x3 ,0x3 ,0x3 ,0x3 ,0x3 ,0x3 ,0x4 ,0x3 ,0x3 , // e0..ef
519+ 0xb ,0x6 ,0x6 ,0x6 ,0x5 ,0x8 ,0x8 ,0x8 ,0x8 ,0x8 ,0x8 ,0x8 ,0x8 ,0x8 ,0x8 ,0x8 , // f0..ff
520+ 0x0 ,0x1 ,0x2 ,0x3 ,0x5 ,0x8 ,0x7 ,0x1 ,0x1 ,0x1 ,0x4 ,0x6 ,0x1 ,0x1 ,0x1 ,0x1 , // s0..s0
521+ 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,0 ,1 ,1 ,1 ,1 ,1 ,0 ,1 ,0 ,1 ,1 ,1 ,1 ,1 ,1 , // s1..s2
522+ 1 ,2 ,1 ,1 ,1 ,1 ,1 ,2 ,1 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , // s3..s4
523+ 1 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,3 ,1 ,3 ,1 ,1 ,1 ,1 ,1 ,1 , // s5..s6
524+ 1 ,3 ,1 ,1 ,1 ,1 ,1 ,3 ,1 ,3 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,3 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , // s7..s8
525+ };
526+
527+ ZEND_API bool zend_string_validate_utf8 (zend_string * string ) {
528+ char * str = ZSTR_VAL (string );
529+ size_t len = ZSTR_LEN (string );
530+ uint32_t state = UTF8_ACCEPT ;
531+
532+ for (size_t i = 0 ; i < len ; i ++ ) {
533+ uint32_t type = utf8d [(uint8_t )str [i ]];
534+ state = utf8d [256 + state * 16 + type ];
535+
536+ if (state == UTF8_REJECT )
537+ break ;
538+ }
539+
540+ return state == UTF8_ACCEPT ;
541+ }
0 commit comments