PluginProbe ʕ •ᴥ•ʔ
Contact Form 7 / 6.0.4
Contact Form 7 v6.0.4
6.1.6 5.0.2 5.0.3 5.0.4 5.0.5 5.1 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.2 5.2.1 5.2.2 5.3 5.3.1 5.3.2 5.4 5.4.1 5.4.2 5.5 5.5.1 5.5.2 5.5.3 5.5.4 5.5.5 5.5.6 5.5.6.1 5.6 5.6.1 5.6.2 5.6.3 5.6.4 5.7 5.7.1 5.7.2 5.7.3 5.7.4 5.7.5 5.7.5.1 5.7.6 5.7.7 5.8 5.8.1 5.8.2 5.8.3 5.8.4 5.8.5 5.8.6 5.8.7 5.9 5.9.2 5.9.3 5.9.4 5.9.5 5.9.6 5.9.7 5.9.8 6.0 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.0.6 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 trunk 1.1 1.10 1.10.0.1 1.10.1 1.2 1.3 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.5 1.6 1.6.1 1.7 1.7.1 1.7.2 1.7.4 1.7.5 1.7.6 1.7.6.1 1.7.7 1.7.7.1 1.7.8 1.8 1.8.0.1 1.8.0.2 1.8.0.3 1.8.0.4 1.8.1 1.8.1.1 1.9 1.9.1 1.9.2 1.9.2.1 1.9.2.2 1.9.3 1.9.4 1.9.5 1.9.5.1 2.0 2.0-beta 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1 2.1.1 2.1.2 2.2 2.2.1 2.3 2.3.1 2.4 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 3.0 3.0-beta 3.0.1 3.0.2 3.0.2.1 3.1 3.1.1 3.1.2 3.2 3.2.1 3.3 3.3.1 3.3.2 3.3.3 3.4 3.4.1 3.4.2 3.5 3.5.1 3.5.2 3.5.3 3.5.4 3.6 3.7 3.7.1 3.7.2 3.8 3.8.1 3.9 3.9-beta 3.9.1 3.9.2 3.9.3 4.0 4.0.1 4.0.2 4.0.3 4.1 4.1-beta 4.1.1 4.1.2 4.2 4.2-beta 4.2.1 4.2.2 4.3 4.3.1 4.4 4.4.1 4.4.2 4.5 4.5.1 4.6 4.6.1 4.7 4.8 4.8.1 4.9 4.9.1 4.9.2 5.0 5.0.1
contact-form-7 / includes / formatting.php
contact-form-7 / includes Last commit date
block-editor 1 year ago config-validator 1 year ago css 2 years ago js 1 year ago swv 1 year ago capabilities.php 7 years ago contact-form-functions.php 1 year ago contact-form-template.php 1 year ago contact-form.php 1 year ago controller.php 1 year ago file.php 1 year ago form-tag.php 1 year ago form-tags-manager.php 1 year ago formatting.php 1 year ago functions.php 1 year ago html-formatter.php 1 year ago integration.php 1 year ago l10n.php 1 year ago mail-tag.php 2 years ago mail.php 1 year ago pipe.php 1 year ago pocket-holder.php 3 years ago rest-api.php 1 year ago shortcodes.php 1 year ago special-mail-tags.php 1 year ago submission.php 1 year ago upgrade.php 2 years ago validation-functions.php 1 year ago validation.php 1 year ago
formatting.php
614 lines
1 <?php
2
3 /**
4 * Replaces double line breaks with paragraph elements.
5 *
6 * @param string $input The text which has to be formatted.
7 * @param bool $br Optional. If set, this will convert all remaining
8 * line breaks after paragraphing. Default true.
9 * @return string Text which has been converted into correct paragraph tags.
10 */
11 function wpcf7_autop( $input, $br = true ) {
12 $placeholders = array();
13
14 // Replace non-HTML embedded elements with placeholders.
15 $input = preg_replace_callback(
16 '/<(math|svg).*?<\/\1>/is',
17 static function ( $matches ) use ( &$placeholders ) {
18 $placeholder = sprintf(
19 '<%1$s id="%2$s" />',
20 WPCF7_HTMLFormatter::placeholder_inline,
21 sha1( $matches[0] )
22 );
23
24 list( $placeholder ) =
25 WPCF7_HTMLFormatter::normalize_start_tag( $placeholder );
26
27 $placeholders[$placeholder] = $matches[0];
28
29 return $placeholder;
30 },
31 $input
32 );
33
34 $formatter = new WPCF7_HTMLFormatter( array(
35 'auto_br' => $br,
36 ) );
37
38 $chunks = $formatter->separate_into_chunks( $input );
39
40 $output = $formatter->format( $chunks );
41
42 // Restore from placeholders.
43 $output = str_replace(
44 array_keys( $placeholders ),
45 array_values( $placeholders ),
46 $output
47 );
48
49 return $output;
50 }
51
52
53 /**
54 * Newline preservation help function for wpcf7_autop().
55 *
56 * @deprecated 5.7 Unnecessary to use any more.
57 *
58 * @param array $matches preg_replace_callback() matches array.
59 * @return string Text including newline placeholders.
60 */
61 function wpcf7_autop_preserve_newline_callback( $matches ) {
62 return str_replace( "\n", '<WPPreserveNewline />', $matches[0] );
63 }
64
65
66 /**
67 * Sanitizes the query variables.
68 *
69 * @param string $text Query variable.
70 * @return string Text sanitized.
71 */
72 function wpcf7_sanitize_query_var( $text ) {
73 $text = wp_unslash( $text );
74 $text = wp_check_invalid_utf8( $text );
75
76 if ( false !== strpos( $text, '<' ) ) {
77 $text = wp_pre_kses_less_than( $text );
78 $text = wp_strip_all_tags( $text );
79 }
80
81 $text = preg_replace( '/%[a-f0-9]{2}/i', '', $text );
82 $text = preg_replace( '/ +/', ' ', $text );
83 $text = trim( $text, ' ' );
84
85 return $text;
86 }
87
88
89 /**
90 * Strips quote characters surrounding the input.
91 *
92 * @param string $text Input text.
93 * @return string Processed output.
94 */
95 function wpcf7_strip_quote( $text ) {
96 $text = trim( $text );
97
98 if ( preg_match( '/^"(.*)"$/s', $text, $matches ) ) {
99 $text = $matches[1];
100 } elseif ( preg_match( "/^'(.*)'$/s", $text, $matches ) ) {
101 $text = $matches[1];
102 }
103
104 return $text;
105 }
106
107
108 /**
109 * Navigates through an array, object, or scalar, and
110 * strips quote characters surrounding the each value.
111 *
112 * @param mixed $input The array or string to be processed.
113 * @return mixed Processed value.
114 */
115 function wpcf7_strip_quote_deep( $input ) {
116 if ( is_string( $input ) ) {
117 return wpcf7_strip_quote( $input );
118 }
119
120 if ( is_array( $input ) ) {
121 $result = array();
122
123 foreach ( $input as $key => $text ) {
124 $result[$key] = wpcf7_strip_quote_deep( $text );
125 }
126
127 return $result;
128 }
129 }
130
131
132 /**
133 * Normalizes newline characters.
134 *
135 * @param string $text Input text.
136 * @param string $to Optional. The newline character that is used in the output.
137 * @return string Normalized text.
138 */
139 function wpcf7_normalize_newline( $text, $to = "\n" ) {
140 if ( ! is_string( $text ) ) {
141 return $text;
142 }
143
144 $nls = array( "\r\n", "\r", "\n" );
145
146 if ( ! in_array( $to, $nls, true ) ) {
147 return $text;
148 }
149
150 return str_replace( $nls, $to, $text );
151 }
152
153
154 /**
155 * Navigates through an array, object, or scalar, and
156 * normalizes newline characters in the each value.
157 *
158 * @param mixed $input The array or string to be processed.
159 * @param string $to Optional. The newline character that is used in the output.
160 * @return mixed Processed value.
161 */
162 function wpcf7_normalize_newline_deep( $input, $to = "\n" ) {
163 if ( is_array( $input ) ) {
164 $result = array();
165
166 foreach ( $input as $key => $text ) {
167 $result[$key] = wpcf7_normalize_newline_deep( $text, $to );
168 }
169
170 return $result;
171 }
172
173 return wpcf7_normalize_newline( $input, $to );
174 }
175
176
177 /**
178 * Strips newline characters.
179 *
180 * @param string $text Input text.
181 * @return string Processed one-line text.
182 */
183 function wpcf7_strip_newline( $text ) {
184 $text = (string) $text;
185 $text = str_replace( array( "\r", "\n" ), '', $text );
186 return trim( $text );
187 }
188
189
190 /**
191 * Canonicalizes text.
192 *
193 * @param string $text Input text.
194 * @param string|array|object $options Options.
195 * @return string Canonicalized text.
196 */
197 function wpcf7_canonicalize( $text, $options = '' ) {
198 // for back-compat
199 if ( is_string( $options ) and '' !== $options
200 and false === strpos( $options, '=' ) ) {
201 $options = array(
202 'strto' => $options,
203 );
204 }
205
206 $options = wp_parse_args( $options, array(
207 'strto' => 'lower',
208 'strip_separators' => false,
209 ) );
210
211 static $charset = null;
212
213 if ( ! isset( $charset ) ) {
214 $charset = get_option( 'blog_charset' );
215
216 $is_utf8 = in_array(
217 $charset,
218 array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ),
219 true
220 );
221
222 if ( $is_utf8 ) {
223 $charset = 'UTF-8';
224 }
225 }
226
227 $text = html_entity_decode( $text, ENT_QUOTES | ENT_HTML5, $charset );
228
229 if ( function_exists( 'mb_convert_kana' ) ) {
230 $text = mb_convert_kana( $text, 'asKV', $charset );
231 }
232
233 if ( $options['strip_separators'] ) {
234 $text = preg_replace( '/[\r\n\t ]+/', '', $text );
235 } else {
236 $text = preg_replace( '/[\r\n\t ]+/', ' ', $text );
237 }
238
239 if ( 'lower' === $options['strto'] ) {
240 if ( function_exists( 'mb_strtolower' ) ) {
241 $text = mb_strtolower( $text, $charset );
242 } else {
243 $text = strtolower( $text );
244 }
245 } elseif ( 'upper' === $options['strto'] ) {
246 if ( function_exists( 'mb_strtoupper' ) ) {
247 $text = mb_strtoupper( $text, $charset );
248 } else {
249 $text = strtoupper( $text );
250 }
251 }
252
253 $text = trim( $text );
254 return $text;
255 }
256
257
258 /**
259 * Returns a canonical keyword usable for a name or an ID purposes.
260 */
261 function wpcf7_canonicalize_name( $text ) {
262 return preg_replace( '/[^0-9a-z]+/i', '-', $text );
263 }
264
265
266 /**
267 * Sanitizes Contact Form 7's form unit-tag.
268 *
269 * @param string $tag Unit-tag.
270 * @return string Sanitized unit-tag.
271 */
272 function wpcf7_sanitize_unit_tag( $tag ) {
273 $tag = preg_replace( '/[^A-Za-z0-9_-]/', '', (string) $tag );
274 return $tag;
275 }
276
277
278 /**
279 * Converts a file name to one that is not executable as a script.
280 *
281 * @param string $filename File name.
282 * @return string Converted file name.
283 */
284 function wpcf7_antiscript_file_name( $filename ) {
285 $filename = wp_basename( $filename );
286
287 // Apply part of protection logic from sanitize_file_name().
288 $filename = str_replace(
289 array(
290 '?', '[', ']', '/', '\\', '=', '<', '>', ':', ';', ',', "'", '"',
291 '&', '$', '#', '*', '(', ')', '|', '~', '`', '!', '{', '}',
292 '%', '+', '', '«', '»', '', '', chr( 0 )
293 ),
294 '',
295 $filename
296 );
297
298 $filename = preg_replace( '/[\r\n\t -]+/', '-', $filename );
299 $filename = preg_replace( '/[\pC\pZ]+/iu', '', $filename );
300
301 $parts = explode( '.', $filename );
302
303 if ( count( $parts ) < 2 ) {
304 return $filename;
305 }
306
307 $script_pattern = '/^(php|phtml|pl|py|rb|cgi|asp|aspx)\d?$/i';
308
309 $filename = array_shift( $parts );
310 $extension = array_pop( $parts );
311
312 foreach ( $parts as $part ) {
313 if ( preg_match( $script_pattern, $part ) ) {
314 $filename .= '.' . $part . '_';
315 } else {
316 $filename .= '.' . $part;
317 }
318 }
319
320 if ( preg_match( $script_pattern, $extension ) ) {
321 $filename .= '.' . $extension . '_.txt';
322 } else {
323 $filename .= '.' . $extension;
324 }
325
326 return $filename;
327 }
328
329
330 /**
331 * Masks a password with asterisks (*).
332 *
333 * @param int $right Length of right-hand unmasked text. Default 0.
334 * @param int $left Length of left-hand unmasked text. Default 0.
335 * @return string Text of masked password.
336 */
337 function wpcf7_mask_password( $text, $right = 0, $left = 0 ) {
338 $length = strlen( $text );
339
340 $right = absint( $right );
341 $left = absint( $left );
342
343 if ( $length < $right + $left ) {
344 $right = $left = 0;
345 }
346
347 if ( $length <= 48 ) {
348 $masked = str_repeat( '*', $length - ( $right + $left ) );
349 } elseif ( $right + $left < 48 ) {
350 $masked = str_repeat( '*', 48 - ( $right + $left ) );
351 } else {
352 $masked = '****';
353 }
354
355 $left_unmasked = $left ? substr( $text, 0, $left ) : '';
356 $right_unmasked = $right ? substr( $text, -1 * $right ) : '';
357
358 $text = $left_unmasked . $masked . $right_unmasked;
359
360 return $text;
361 }
362
363
364 /**
365 * Returns an array of allowed HTML tags and attributes for a given context.
366 *
367 * @param string $context Context used to decide allowed tags and attributes.
368 * @return array Array of allowed HTML tags and their allowed attributes.
369 */
370 function wpcf7_kses_allowed_html( $context = 'form' ) {
371 static $allowed_tags = array();
372
373 if ( isset( $allowed_tags[$context] ) ) {
374 return apply_filters(
375 'wpcf7_kses_allowed_html',
376 $allowed_tags[$context],
377 $context
378 );
379 }
380
381 $allowed_tags[$context] = wp_kses_allowed_html( 'post' );
382
383 if ( 'form' === $context ) {
384 $additional_tags_for_form = array(
385 'button' => array(
386 'disabled' => true,
387 'name' => true,
388 'type' => true,
389 'value' => true,
390 ),
391 'datalist' => array(),
392 'fieldset' => array(
393 'disabled' => true,
394 'name' => true,
395 ),
396 'input' => array(
397 'accept' => true,
398 'alt' => true,
399 'capture' => true,
400 'checked' => true,
401 'disabled' => true,
402 'list' => true,
403 'max' => true,
404 'maxlength' => true,
405 'min' => true,
406 'minlength' => true,
407 'multiple' => true,
408 'name' => true,
409 'placeholder' => true,
410 'readonly' => true,
411 'size' => true,
412 'step' => true,
413 'type' => true,
414 'value' => true,
415 ),
416 'label' => array(
417 'for' => true,
418 ),
419 'legend' => array(),
420 'meter' => array(
421 'value' => true,
422 'min' => true,
423 'max' => true,
424 'low' => true,
425 'high' => true,
426 'optimum' => true,
427 ),
428 'optgroup' => array(
429 'disabled' => true,
430 'label' => true,
431 ),
432 'option' => array(
433 'disabled' => true,
434 'label' => true,
435 'selected' => true,
436 'value' => true,
437 ),
438 'output' => array(
439 'for' => true,
440 'name' => true,
441 ),
442 'progress' => array(
443 'max' => true,
444 'value' => true,
445 ),
446 'select' => array(
447 'disabled' => true,
448 'multiple' => true,
449 'name' => true,
450 'size' => true,
451 ),
452 'textarea' => array(
453 'cols' => true,
454 'disabled' => true,
455 'maxlength' => true,
456 'minlength' => true,
457 'name' => true,
458 'placeholder' => true,
459 'readonly' => true,
460 'rows' => true,
461 'spellcheck' => true,
462 'wrap' => true,
463 ),
464 );
465
466 $additional_tags_for_form = array_map(
467 static function ( $elm ) {
468 $global_attributes = array(
469 'aria-atomic' => true,
470 'aria-checked' => true,
471 'aria-describedby' => true,
472 'aria-details' => true,
473 'aria-disabled' => true,
474 'aria-hidden' => true,
475 'aria-invalid' => true,
476 'aria-label' => true,
477 'aria-labelledby' => true,
478 'aria-live' => true,
479 'aria-relevant' => true,
480 'aria-required' => true,
481 'aria-selected' => true,
482 'class' => true,
483 'data-*' => true,
484 'id' => true,
485 'inputmode' => true,
486 'role' => true,
487 'style' => true,
488 'tabindex' => true,
489 'title' => true,
490 );
491
492 return array_merge( $global_attributes, (array) $elm );
493 },
494 $additional_tags_for_form
495 );
496
497 $allowed_tags[$context] = array_merge(
498 $allowed_tags[$context],
499 $additional_tags_for_form
500 );
501 }
502
503 return apply_filters(
504 'wpcf7_kses_allowed_html',
505 $allowed_tags[$context],
506 $context
507 );
508 }
509
510
511 /**
512 * Sanitizes content for allowed HTML tags for the specified context.
513 *
514 * @param string $input Content to filter.
515 * @param string $context Context used to decide allowed tags and attributes.
516 * @return string Filtered text with allowed HTML tags and attributes intact.
517 */
518 function wpcf7_kses( $input, $context = 'form' ) {
519 $output = wp_kses(
520 $input,
521 wpcf7_kses_allowed_html( $context )
522 );
523
524 return $output;
525 }
526
527
528 /**
529 * Returns a formatted string of HTML attributes.
530 *
531 * @param array $atts Associative array of attribute name and value pairs.
532 * @return string Formatted HTML attributes.
533 */
534 function wpcf7_format_atts( $atts ) {
535 $atts_filtered = array();
536
537 foreach ( $atts as $name => $value ) {
538 $name = strtolower( trim( $name ) );
539
540 if ( ! preg_match( '/^[a-z_:][a-z_:.0-9-]*$/', $name ) ) {
541 continue;
542 }
543
544 static $boolean_attributes = array(
545 'checked',
546 'disabled',
547 'inert',
548 'multiple',
549 'readonly',
550 'required',
551 'selected',
552 );
553
554 if ( in_array( $name, $boolean_attributes, true ) and '' === $value ) {
555 $value = false;
556 }
557
558 if ( is_numeric( $value ) ) {
559 $value = (string) $value;
560 }
561
562 if ( null === $value or false === $value ) {
563 unset( $atts_filtered[$name] );
564 } elseif ( true === $value ) {
565 $atts_filtered[$name] = $name; // boolean attribute
566 } elseif ( is_string( $value ) ) {
567 $atts_filtered[$name] = trim( $value );
568 }
569 }
570
571 $output = '';
572
573 foreach ( $atts_filtered as $name => $value ) {
574 $output .= sprintf( ' %1$s="%2$s"', $name, esc_attr( $value ) );
575 }
576
577 return trim( $output );
578 }
579
580
581 /**
582 * Strips surrounding whitespaces.
583 *
584 * @link https://contactform7.com/2024/07/13/consistent-handling-policy-of-surrounding-whitespaces/
585 *
586 * @param string|array $input Input text.
587 * @return string|array Output text.
588 */
589 function wpcf7_strip_whitespaces( $input ) {
590 if ( is_array( $input ) ) {
591 return array_map( 'wpcf7_strip_whitespaces', $input );
592 }
593
594 // https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt
595 // https://tc39.es/ecma262/multipage/ecmascript-language-lexical-grammar.html
596 $whitespaces = '\x09-\x0D\x20\x85\xA0\x{1680}\x{2000}-\x{200A}\x{2028}\x{2029}\x{202F}\x{205F}\x{3000}\x{FEFF}';
597
598 // Strip leading whitespaces
599 $input = preg_replace(
600 sprintf( '/^[%s]+/u', $whitespaces ),
601 '',
602 $input
603 );
604
605 // Strip trailing whitespaces
606 $input = preg_replace(
607 sprintf( '/[%s]+$/u', $whitespaces ),
608 '',
609 $input
610 );
611
612 return $input;
613 }
614