| @@ -14,8 +14,11 @@ | ||
| 14 | 14 | * |
| 15 | 15 | * @return bool |
| 16 | 16 | */ |
| 17 | 17 | function wplng_str_contains( $haystack, $needle ) { |
| 18 | + if ( ! is_string( $haystack ) || ! is_string( $needle ) ) { | |
| 19 | + return false; | |
| 20 | + } | |
| 18 | 21 | return ( strpos( $haystack, $needle ) !== false ); |
| 19 | 22 | } |
| 20 | 23 | |
| 21 | 24 | |
| @@ -61,31 +64,33 @@ | ||
| 61 | 64 | * @return bool |
| 62 | 65 | */ |
| 63 | 66 | function wplng_str_is_url( $str ) { |
| 64 | 67 | |
| 68 | + if ( ! is_string( $str ) | |
| 69 | + || trim( $str ) === '' | |
| 70 | + || ! wplng_str_contains( $str, '/' ) | |
| 71 | + || wplng_str_starts_with( $str, 'GlotPress/' ) // JSON WP translation system | |
| 72 | + || wplng_str_starts_with( $str, 'wpgb-content-block/' ) // Plugin: WP Grid Builder | |
| 73 | + || wplng_str_starts_with( $str, '/wc/store/v1' ) // Plugin: WooCommerce | |
| 74 | + || wplng_str_starts_with( $str, 'contact-form-7/v1' ) // Plugin: Contact Form 7 | |
| 75 | + ) { | |
| 76 | + return false; | |
| 77 | + } | |
| 78 | + | |
| 79 | + $is_url = false; | |
| 65 | 80 | $parsed = wp_parse_url( $str ); |
| 66 | - $is_url = false; | |
| 67 | 81 | |
| 68 | - if ( is_string( $str ) | |
| 69 | - && ( '' !== trim( $str ) ) | |
| 70 | - && wplng_str_contains( $str, '/' ) | |
| 71 | - && ! wplng_str_starts_with( $str, 'wpgb-content-block/' ) // Plugin: WP Grid Builder | |
| 72 | - && ! wplng_str_starts_with( $str, '/wc/store/v1' ) // Plugin: WooCommerce | |
| 73 | - && ! wplng_str_starts_with( $str, 'GlotPress/' ) // Plugin: WooCommerce | |
| 74 | - && ! wplng_str_starts_with( $str, 'contact-form-7/v1' ) // Plugin: Contact Form 7 | |
| 82 | + if ( isset( $parsed['scheme'] ) | |
| 83 | + && ( | |
| 84 | + ( 'https' === $parsed['scheme'] ) | |
| 85 | + || ( 'http' === $parsed['scheme'] ) | |
| 86 | + ) | |
| 75 | 87 | ) { |
| 76 | - if ( isset( $parsed['scheme'] ) | |
| 77 | - && ( | |
| 78 | - ( 'https' === $parsed['scheme'] ) | |
| 79 | - || ( 'http' === $parsed['scheme'] ) | |
| 80 | - ) | |
| 81 | - ) { | |
| 82 | - // URL has http/https/... | |
| 83 | - $is_url = ! ( filter_var( $str, FILTER_VALIDATE_URL ) === false ); | |
| 84 | - } else { | |
| 85 | - // PHP filter_var does not support relative urls, so we simulate a full URL | |
| 86 | - $is_url = ( filter_var( 'https://website.com/' . ltrim( $str, '/' ), FILTER_VALIDATE_URL ) !== false ); | |
| 87 | - } | |
| 88 | + // URL has http/https/... | |
| 89 | + $is_url = ! ( filter_var( $str, FILTER_VALIDATE_URL ) === false ); | |
| 90 | + } else { | |
| 91 | + // PHP filter_var does not support relative urls, so we simulate a full URL | |
| 92 | + $is_url = ( filter_var( 'https://website.com/' . ltrim( $str, '/' ), FILTER_VALIDATE_URL ) !== false ); | |
| 88 | 93 | } |
| 89 | 94 | |
| 90 | 95 | return $is_url; |
| 91 | 96 | } |
| @@ -99,8 +104,12 @@ | ||
| 99 | 104 | * @return bool |
| 100 | 105 | */ |
| 101 | 106 | function wplng_text_is_translatable( $text ) { |
| 102 | 107 | |
| 108 | + if ( ! is_string( $text ) ) { | |
| 109 | + return false; | |
| 110 | + } | |
| 111 | + | |
| 103 | 112 | $text = trim( $text ); |
| 104 | 113 | |
| 105 | 114 | if ( '' === $text ) { |
| 106 | 115 | return false; |
| @@ -110,12 +119,8 @@ | ||
| 110 | 119 | if ( wplng_str_contains( $text, '_wplingua_no_translate_' ) ) { |
| 111 | 120 | return false; |
| 112 | 121 | } |
| 113 | 122 | |
| 114 | - if ( wplng_str_is_malicious( $text ) ) { | |
| 115 | - return false; | |
| 116 | - } | |
| 117 | - | |
| 118 | 123 | // Check for better plugin compatibility |
| 119 | 124 | if ( wplng_str_contains( $text, 'presto_player' ) |
| 120 | 125 | || wplng_str_contains( $text, 'presto-player' ) |
| 121 | 126 | ) { |
| @@ -121,13 +126,8 @@ | ||
| 121 | 126 | ) { |
| 122 | 127 | return false; |
| 123 | 128 | } |
| 124 | 129 | |
| 125 | - // Check if it's a email address | |
| 126 | - if ( filter_var( $text, FILTER_VALIDATE_EMAIL ) ) { | |
| 127 | - return false; | |
| 128 | - } | |
| 129 | - | |
| 130 | 130 | // Check bad HTML tags and templating tags |
| 131 | 131 | if ( wplng_str_starts_with( $text, '<' ) |
| 132 | 132 | && wplng_str_ends_with( $text, '>' ) |
| 133 | 133 | ) { |
| @@ -140,8 +140,13 @@ | ||
| 140 | 140 | ) { |
| 141 | 141 | return false; |
| 142 | 142 | } |
| 143 | 143 | |
| 144 | + // Check if it's a email address | |
| 145 | + if ( filter_var( $text, FILTER_VALIDATE_EMAIL ) ) { | |
| 146 | + return false; | |
| 147 | + } | |
| 148 | + | |
| 144 | 149 | // Get letters only |
| 145 | 150 | $letters = $text; |
| 146 | 151 | $letters = html_entity_decode( $letters ); |
| 147 | 152 | $letters = preg_replace( '#[^\p{L}\p{N}]#u', '', $letters ); |
| @@ -146,9 +151,18 @@ | ||
| 146 | 151 | $letters = html_entity_decode( $letters ); |
| 147 | 152 | $letters = preg_replace( '#[^\p{L}\p{N}]#u', '', $letters ); |
| 148 | 153 | $letters = preg_replace( '#[\d\s]#u', '', $letters ); |
| 149 | 154 | |
| 150 | - return ! empty( $letters ); | |
| 155 | + if ( empty( $letters ) ) { | |
| 156 | + return false; | |
| 157 | + } | |
| 158 | + | |
| 159 | + // Check if string is malicious | |
| 160 | + if ( wplng_str_is_malicious( $text ) ) { | |
| 161 | + return false; | |
| 162 | + } | |
| 163 | + | |
| 164 | + return true; | |
| 151 | 165 | } |
| 152 | 166 | |
| 153 | 167 | |
| 154 | 168 | /** |
| @@ -231,8 +245,9 @@ | ||
| 231 | 245 | * @return string Escape texte for comparison |
| 232 | 246 | */ |
| 233 | 247 | function wplng_text_esc( $text ) { |
| 234 | 248 | |
| 249 | + $text = wp_strip_all_tags( $text ); | |
| 235 | 250 | $text = html_entity_decode( $text ); |
| 236 | 251 | $text = esc_html( $text ); |
| 237 | 252 | $text = esc_attr( $text ); |
| 238 | 253 | |
| @@ -241,8 +256,9 @@ | ||
| 241 | 256 | ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 |
| 242 | 257 | ); |
| 243 | 258 | |
| 244 | 259 | $text = str_replace( '\\', '', $text ); |
| 260 | + $text = preg_replace( '/[\x00-\x1F\x7F]+/u', '', $text ); | |
| 245 | 261 | $text = preg_replace( '/\s+/u', ' ', $text ); |
| 246 | 262 | $text = trim( $text ); |
| 247 | 263 | |
| 248 | 264 | return $text; |
| @@ -364,8 +380,11 @@ | ||
| 364 | 380 | * @param string $str String to check |
| 365 | 381 | * @return bool true is $str is a JSON |
| 366 | 382 | */ |
| 367 | 383 | function wplng_str_is_json( $str ) { |
| 384 | + if ( ! is_string( $str ) ) { | |
| 385 | + return false; | |
| 386 | + } | |
| 368 | 387 | $decoded = json_decode( $str, true ); |
| 369 | 388 | return ( json_last_error() === JSON_ERROR_NONE ) && is_array( $decoded ); |
| 370 | 389 | } |
| 371 | 390 | |