@@ -279,9 +279,11 @@ static void php_zval_filter(zval *value, zend_long filter, zend_long flags, zval
279279
280280static unsigned int php_sapi_filter (int arg , const char * var , char * * val , size_t val_len , size_t * new_val_len ) /* {{{ */
281281{
282- zval new_var , raw_var ;
282+ zval raw_var , new_var ;
283283 zval * array_ptr = NULL , * orig_array_ptr = NULL ;
284284 int retval = 0 ;
285+ int is_raw = (IF_G (default_filter ) == FILTER_UNSAFE_RAW );
286+ size_t var_len = strlen (var );
285287
286288 assert (* val != NULL );
287289
@@ -313,10 +315,54 @@ static unsigned int php_sapi_filter(int arg, const char *var, char **val, size_t
313315 * more specific cookies with the less specific ones.
314316 */
315317 if (arg == PARSE_COOKIE && orig_array_ptr &&
316- zend_symtable_str_exists (Z_ARRVAL_P (orig_array_ptr ), var , strlen ( var ) )) {
318+ zend_symtable_str_exists (Z_ARRVAL_P (orig_array_ptr ), var , var_len )) {
317319 return 0 ;
318320 }
319321
322+ /*
323+ * Fast path: if the default filter is UNSAFE_RAW, we can build a single zval, register it twice, and be done
324+ */
325+ if (is_raw )
326+ {
327+ if (array_ptr || orig_array_ptr )
328+ {
329+ if (val_len )
330+ {
331+ ZVAL_STRINGL (& raw_var , * val , val_len );
332+ } else
333+ {
334+ ZVAL_EMPTY_STRING (& raw_var );
335+ }
336+ if (array_ptr )
337+ {
338+ php_register_variable_ex (var , & raw_var , array_ptr );
339+ }
340+ if (orig_array_ptr )
341+ {
342+ php_register_variable_ex (var , & raw_var , orig_array_ptr );
343+ }
344+
345+ if (retval )
346+ {
347+ if (new_val_len )
348+ {
349+ * new_val_len = Z_STRLEN_P (& raw_var );
350+ }
351+ efree (* val );
352+ if (Z_STRLEN_P (& raw_var ))
353+ {
354+ * val = estrndup (Z_STRVAL_P (& raw_var ), Z_STRLEN_P (& raw_var ));
355+ } else
356+ {
357+ * val = strdup ("" );
358+ }
359+ }
360+
361+ zval_ptr_dtor (& raw_var );
362+ }
363+ return retval ;
364+ }
365+
320366 if (array_ptr ) {
321367 /* Store the RAW variable internally */
322368 ZVAL_STRINGL (& raw_var , * val , val_len );
0 commit comments