| @@ -2986,8 +2986,35 @@ | ||
| 2986 | 2986 | |
| 2987 | 2987 | return $data; |
| 2988 | 2988 | } |
| 2989 | 2989 | |
| 2990 | +/** | |
| 2991 | + * Build a REGEXP literal for searching inside a wp_json_encode() stored column. | |
| 2992 | + * | |
| 2993 | + * The haystack (profiles.fields, postmeta.metavalue) is written with wp_json_encode(), | |
| 2994 | + * which escapes forward slashes ("S/4HANA" is stored as S\/4HANA) and non-ASCII | |
| 2995 | + * characters (Ľ), so the needle must be encoded the same way or it can never match. | |
| 2996 | + * Callers must still wrap the result in esc_sql() before putting it in a query. | |
| 2997 | + * | |
| 2998 | + * @param string $value Raw needle. | |
| 2999 | + * | |
| 3000 | + * @return string Regex-literal needle, without SQL escaping. | |
| 3001 | + */ | |
| 3002 | +function wpforo_json_regexp_needle( $value ): string { | |
| 3003 | + $value = (string) $value; | |
| 3004 | + | |
| 3005 | + // esc_sql() cannot reliably escape invalid UTF-8 on a utf8mb4 connection and | |
| 3006 | + // wp_json_encode() returns false for it, so strip it before encoding. | |
| 3007 | + $clean = wp_check_invalid_utf8( $value, true ); | |
| 3008 | + $json = ( ! is_string( $clean ) || $clean === '' ) ? false : wp_json_encode( $clean ); | |
| 3009 | + | |
| 3010 | + // Never return an empty needle for a non-empty search term: in a substring | |
| 3011 | + // pattern that would match every row. \u0000 cannot occur in stored field data. | |
| 3012 | + if( ! is_string( $json ) || strlen( $json ) < 2 ) return ( $value === '' ) ? '' : preg_quote( '\u0000' ); | |
| 3013 | + | |
| 3014 | + return preg_quote( substr( $json, 1, -1 ) ); | |
| 3015 | +} | |
| 3016 | + | |
| 2990 | 3017 | function wpforo_trim( $data ) { |
| 2991 | 3018 | $data = is_array( $data ) ? array_map( 'wpforo_trim', $data ) : trim( (string) $data ); |
| 2992 | 3019 | |
| 2993 | 3020 | return $data; |