PluginProbe ʕ •ᴥ•ʔ
Contact Form 7 / 6.0.6
Contact Form 7 v6.0.6
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 / modules / really-simple-captcha.php
contact-form-7 / modules Last commit date
akismet 1 year ago constant-contact 1 year ago recaptcha 1 year ago sendinblue 1 year ago stripe 1 year ago acceptance.php 1 year ago checkbox.php 1 year ago count.php 1 year ago date.php 1 year ago disallowed-list.php 1 year ago doi-helper.php 4 years ago file.php 1 year ago flamingo.php 1 year ago hidden.php 7 years ago listo.php 2 years ago number.php 1 year ago quiz.php 1 year ago really-simple-captcha.php 1 year ago reflection.php 3 years ago response.php 6 years ago select.php 1 year ago submit.php 1 year ago text.php 1 year ago textarea.php 1 year ago
really-simple-captcha.php
611 lines
1 <?php
2 /**
3 ** A base module for [captchac] and [captchar]
4 **/
5
6 /* form_tag handler */
7
8 add_action( 'wpcf7_init', 'wpcf7_add_form_tag_captcha', 10, 0 );
9
10 function wpcf7_add_form_tag_captcha() {
11 // CAPTCHA-Challenge (image)
12 wpcf7_add_form_tag( 'captchac',
13 'wpcf7_captchac_form_tag_handler',
14 array(
15 'name-attr' => true,
16 'zero-controls-container' => true,
17 'not-for-mail' => true,
18 )
19 );
20
21 // CAPTCHA-Response (input)
22 wpcf7_add_form_tag( 'captchar',
23 'wpcf7_captchar_form_tag_handler',
24 array(
25 'name-attr' => true,
26 'do-not-store' => true,
27 'not-for-mail' => true,
28 )
29 );
30 }
31
32 function wpcf7_captchac_form_tag_handler( $tag ) {
33 if ( ! class_exists( 'ReallySimpleCaptcha' ) ) {
34 $error = sprintf(
35 /* translators: %s: link labeled 'Really Simple CAPTCHA' */
36 esc_html( __( "To use CAPTCHA, you need %s plugin installed.", 'contact-form-7' ) ),
37 wpcf7_link( 'https://wordpress.org/plugins/really-simple-captcha/', 'Really Simple CAPTCHA' )
38 );
39
40 return sprintf( '<em>%s</em>', $error );
41 }
42
43 if ( empty( $tag->name ) ) {
44 return '';
45 }
46
47 $class = wpcf7_form_controls_class( $tag->type );
48 $class .= ' wpcf7-captcha-' . str_replace( ':', '', $tag->name );
49
50 $atts = array();
51 $atts['class'] = $tag->get_class_option( $class );
52 $atts['id'] = $tag->get_id_option();
53
54 $op = array( // Default
55 'img_size' => array( 72, 24 ),
56 'base' => array( 6, 18 ),
57 'font_size' => 14,
58 'font_char_width' => 15,
59 );
60
61 $op = array_merge( $op, wpcf7_captchac_options( $tag->options ) );
62
63 if ( ! $filename = wpcf7_generate_captcha( $op ) ) {
64 return '';
65 }
66
67 if ( ! empty( $op['img_size'] ) ) {
68 if ( isset( $op['img_size'][0] ) ) {
69 $atts['width'] = $op['img_size'][0];
70 }
71
72 if ( isset( $op['img_size'][1] ) ) {
73 $atts['height'] = $op['img_size'][1];
74 }
75 }
76
77 $atts['alt'] = 'captcha';
78 $atts['src'] = wpcf7_captcha_url( $filename );
79
80 $atts = wpcf7_format_atts( $atts );
81
82 $prefix = substr( $filename, 0, strrpos( $filename, '.' ) );
83
84 $html = sprintf(
85 '<input type="hidden" name="%1$s" value="%2$s" /><img %3$s />',
86 esc_attr( sprintf( '_wpcf7_captcha_challenge_%s', $tag->name ) ),
87 esc_attr( $prefix ),
88 $atts
89 );
90
91 return $html;
92 }
93
94 function wpcf7_captchar_form_tag_handler( $tag ) {
95 if ( empty( $tag->name ) ) {
96 return '';
97 }
98
99 $validation_error = wpcf7_get_validation_error( $tag->name );
100
101 $class = wpcf7_form_controls_class( $tag->type );
102
103 if ( $validation_error ) {
104 $class .= ' wpcf7-not-valid';
105 }
106
107 $atts = array();
108
109 $atts['size'] = $tag->get_size_option( '40' );
110 $atts['maxlength'] = $tag->get_maxlength_option();
111 $atts['minlength'] = $tag->get_minlength_option();
112
113 if ( $atts['maxlength'] and $atts['minlength']
114 and $atts['maxlength'] < $atts['minlength'] ) {
115 unset( $atts['maxlength'], $atts['minlength'] );
116 }
117
118 $atts['class'] = $tag->get_class_option( $class );
119 $atts['id'] = $tag->get_id_option();
120 $atts['tabindex'] = $tag->get_option( 'tabindex', 'signed_int', true );
121 $atts['autocomplete'] = 'off';
122
123 if ( $validation_error ) {
124 $atts['aria-invalid'] = 'true';
125 $atts['aria-describedby'] = wpcf7_get_validation_error_reference(
126 $tag->name
127 );
128 } else {
129 $atts['aria-invalid'] = 'false';
130 }
131
132 $value = (string) reset( $tag->values );
133
134 if ( wpcf7_is_posted() ) {
135 $value = '';
136 }
137
138 if ( $tag->has_option( 'placeholder' )
139 or $tag->has_option( 'watermark' ) ) {
140 $atts['placeholder'] = $value;
141 $value = '';
142 }
143
144 $atts['value'] = $value;
145 $atts['type'] = 'text';
146 $atts['name'] = $tag->name;
147
148 $html = sprintf(
149 '<span class="wpcf7-form-control-wrap" data-name="%1$s"><input %2$s />%3$s</span>',
150 esc_attr( $tag->name ),
151 wpcf7_format_atts( $atts ),
152 $validation_error
153 );
154
155 return $html;
156 }
157
158
159 /* Validation filter */
160
161 add_filter( 'wpcf7_validate_captchar',
162 'wpcf7_captcha_validation_filter', 10, 2 );
163
164 function wpcf7_captcha_validation_filter( $result, $tag ) {
165 $type = $tag->type;
166 $name = $tag->name;
167
168 $captchac = '_wpcf7_captcha_challenge_' . $name;
169
170 $prefix = (string) ( $_POST[$captchac] ?? '' );
171 $response = (string) ( $_POST[$name] ?? '' );
172 $response = wpcf7_canonicalize( $response );
173
174 if ( 0 === strlen( $prefix )
175 or ! wpcf7_check_captcha( $prefix, $response ) ) {
176 $result->invalidate( $tag, wpcf7_get_message( 'captcha_not_match' ) );
177 }
178
179 if ( 0 !== strlen( $prefix ) ) {
180 wpcf7_remove_captcha( $prefix );
181 }
182
183 return $result;
184 }
185
186
187 /* Ajax echo filter */
188
189 add_filter( 'wpcf7_refill_response', 'wpcf7_captcha_ajax_refill', 10, 1 );
190 add_filter( 'wpcf7_feedback_response', 'wpcf7_captcha_ajax_refill', 10, 1 );
191
192 function wpcf7_captcha_ajax_refill( $items ) {
193 if ( ! is_array( $items ) ) {
194 return $items;
195 }
196
197 $tags = wpcf7_scan_form_tags( array( 'type' => 'captchac' ) );
198
199 if ( empty( $tags ) ) {
200 return $items;
201 }
202
203 $refill = array();
204
205 foreach ( $tags as $tag ) {
206 $name = $tag->name;
207 $options = $tag->options;
208
209 if ( empty( $name ) ) {
210 continue;
211 }
212
213 $op = wpcf7_captchac_options( $options );
214
215 if ( $filename = wpcf7_generate_captcha( $op ) ) {
216 $captcha_url = wpcf7_captcha_url( $filename );
217 $refill[$name] = $captcha_url;
218 }
219 }
220
221 if ( ! empty( $refill ) ) {
222 $items['captcha'] = $refill;
223 }
224
225 return $items;
226 }
227
228
229 /* Messages */
230
231 add_filter( 'wpcf7_messages', 'wpcf7_captcha_messages', 10, 1 );
232
233 function wpcf7_captcha_messages( $messages ) {
234 $messages = array_merge( $messages, array(
235 'captcha_not_match' => array(
236 'description' =>
237 __( "The code that sender entered does not match the CAPTCHA", 'contact-form-7' ),
238 'default' =>
239 __( 'Your entered code is incorrect.', 'contact-form-7' ),
240 ),
241 ) );
242
243 return $messages;
244 }
245
246
247 /* Warning message */
248
249 add_action( 'wpcf7_admin_warnings',
250 'wpcf7_captcha_display_warning_message', 10, 3 );
251
252 function wpcf7_captcha_display_warning_message( $page, $action, $object ) {
253 if ( $object instanceof WPCF7_ContactForm ) {
254 $contact_form = $object;
255 } else {
256 return;
257 }
258
259 $has_tags = (bool) $contact_form->scan_form_tags(
260 array( 'type' => array( 'captchac' ) ) );
261
262 if ( ! $has_tags ) {
263 return;
264 }
265
266 if ( ! class_exists( 'ReallySimpleCaptcha' ) ) {
267 return;
268 }
269
270 $uploads_dir = wpcf7_captcha_tmp_dir();
271 wpcf7_init_captcha();
272
273 if ( ! is_dir( $uploads_dir ) or ! wp_is_writable( $uploads_dir ) ) {
274 $message = sprintf(
275 /* translators: %s: Path to the temporary folder */
276 __( 'This contact form contains CAPTCHA fields, but the temporary folder for the files (%s) does not exist or is not writable. You can create the folder or change its permission manually.', 'contact-form-7' ),
277 $uploads_dir
278 );
279
280 wp_admin_notice( esc_html( $message ), array( 'type' => 'warning' ) );
281 }
282
283 if (
284 ! function_exists( 'imagecreatetruecolor' ) or
285 ! function_exists( 'imagettftext' )
286 ) {
287 $message = __( "This contact form contains CAPTCHA fields, but the necessary libraries (GD and FreeType) are not available on your server.", 'contact-form-7' );
288
289 wp_admin_notice( esc_html( $message ), array( 'type' => 'warning' ) );
290 }
291 }
292
293
294 /* CAPTCHA functions */
295
296 function wpcf7_init_captcha() {
297 static $captcha = null;
298
299 if ( $captcha ) {
300 return $captcha;
301 }
302
303 if ( class_exists( 'ReallySimpleCaptcha' ) ) {
304 $captcha = new ReallySimpleCaptcha();
305 } else {
306 return false;
307 }
308
309 $dir = trailingslashit( wpcf7_captcha_tmp_dir() );
310
311 $captcha->tmp_dir = $dir;
312
313 if ( is_callable( array( $captcha, 'make_tmp_dir' ) ) ) {
314 $result = $captcha->make_tmp_dir();
315
316 if ( ! $result ) {
317 return false;
318 }
319
320 return $captcha;
321 }
322
323 $result = wp_mkdir_p( $dir );
324
325 if ( ! $result ) {
326 return false;
327 }
328
329 $htaccess_file = path_join( $dir, '.htaccess' );
330
331 if ( file_exists( $htaccess_file ) ) {
332 list( $first_line_comment ) = (array) file(
333 $htaccess_file,
334 FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES
335 );
336
337 if ( '# Apache 2.4+' === $first_line_comment ) {
338 return $captcha;
339 }
340 }
341
342 if ( $handle = @fopen( $htaccess_file, 'w' ) ) {
343 fwrite( $handle, "# Apache 2.4+\n" );
344 fwrite( $handle, "<IfModule authz_core_module>\n" );
345 fwrite( $handle, " Require all denied\n" );
346 fwrite( $handle, ' <FilesMatch "^\w+\.(jpe?g|gif|png)$">' . "\n" );
347 fwrite( $handle, " Require all granted\n" );
348 fwrite( $handle, " </FilesMatch>\n" );
349 fwrite( $handle, "</IfModule>\n" );
350 fwrite( $handle, "\n" );
351 fwrite( $handle, "# Apache 2.2\n" );
352 fwrite( $handle, "<IfModule !authz_core_module>\n" );
353 fwrite( $handle, " Order deny,allow\n" );
354 fwrite( $handle, " Deny from all\n" );
355 fwrite( $handle, ' <FilesMatch "^\w+\.(jpe?g|gif|png)$">' . "\n" );
356 fwrite( $handle, " Allow from all\n" );
357 fwrite( $handle, " </FilesMatch>\n" );
358 fwrite( $handle, "</IfModule>\n" );
359
360 fclose( $handle );
361 }
362
363 return $captcha;
364 }
365
366
367 /**
368 * Returns the directory path for Really Simple CAPTCHA files.
369 *
370 * @return string Directory path.
371 */
372 function wpcf7_captcha_tmp_dir() {
373 if ( defined( 'WPCF7_CAPTCHA_TMP_DIR' ) ) {
374 $dir = path_join( WP_CONTENT_DIR, WPCF7_CAPTCHA_TMP_DIR );
375 wp_mkdir_p( $dir );
376
377 if ( wpcf7_is_file_path_in_content_dir( $dir ) ) {
378 return $dir;
379 }
380 }
381
382 $dir = path_join( wpcf7_upload_dir( 'dir' ), 'wpcf7_captcha' );
383 wp_mkdir_p( $dir );
384 return $dir;
385 }
386
387
388 function wpcf7_captcha_tmp_url() {
389 if ( defined( 'WPCF7_CAPTCHA_TMP_URL' ) ) {
390 return WPCF7_CAPTCHA_TMP_URL;
391 } else {
392 return path_join( wpcf7_upload_dir( 'url' ), 'wpcf7_captcha' );
393 }
394 }
395
396 function wpcf7_captcha_url( $filename ) {
397 $url = path_join( wpcf7_captcha_tmp_url(), $filename );
398
399 if ( is_ssl() and 'http:' === substr( $url, 0, 5 ) ) {
400 $url = 'https:' . substr( $url, 5 );
401 }
402
403 return apply_filters( 'wpcf7_captcha_url', sanitize_url( $url ) );
404 }
405
406 function wpcf7_generate_captcha( $options = null ) {
407 if ( ! $captcha = wpcf7_init_captcha() ) {
408 return false;
409 }
410
411 if ( ! is_dir( $captcha->tmp_dir )
412 or ! wp_is_writable( $captcha->tmp_dir ) ) {
413 return false;
414 }
415
416 $img_type = imagetypes();
417
418 if ( $img_type & IMG_PNG ) {
419 $captcha->img_type = 'png';
420 } elseif ( $img_type & IMG_GIF ) {
421 $captcha->img_type = 'gif';
422 } elseif ( $img_type & IMG_JPG ) {
423 $captcha->img_type = 'jpeg';
424 } else {
425 return false;
426 }
427
428 if ( is_array( $options ) ) {
429 if ( isset( $options['img_size'] ) ) {
430 $captcha->img_size = $options['img_size'];
431 }
432
433 if ( isset( $options['base'] ) ) {
434 $captcha->base = $options['base'];
435 }
436
437 if ( isset( $options['font_size'] ) ) {
438 $captcha->font_size = $options['font_size'];
439 }
440
441 if ( isset( $options['font_char_width'] ) ) {
442 $captcha->font_char_width = $options['font_char_width'];
443 }
444
445 if ( isset( $options['fg'] ) ) {
446 $captcha->fg = $options['fg'];
447 }
448
449 if ( isset( $options['bg'] ) ) {
450 $captcha->bg = $options['bg'];
451 }
452 }
453
454 $prefix = wp_rand();
455 $captcha_word = $captcha->generate_random_word();
456 return $captcha->generate_image( $prefix, $captcha_word );
457 }
458
459 function wpcf7_check_captcha( $prefix, $response ) {
460 if ( ! $captcha = wpcf7_init_captcha() ) {
461 return false;
462 }
463
464 return $captcha->check( $prefix, $response );
465 }
466
467 function wpcf7_remove_captcha( $prefix ) {
468 if ( ! $captcha = wpcf7_init_captcha() ) {
469 return false;
470 }
471
472 // Contact Form 7 generates $prefix with wp_rand()
473 if ( preg_match( '/[^0-9]/', $prefix ) ) {
474 return false;
475 }
476
477 $captcha->remove( $prefix );
478 }
479
480 add_action( 'shutdown', 'wpcf7_cleanup_captcha_files', 20, 0 );
481
482 function wpcf7_cleanup_captcha_files() {
483 if ( ! $captcha = wpcf7_init_captcha() ) {
484 return false;
485 }
486
487 if ( is_callable( array( $captcha, 'cleanup' ) ) ) {
488 return $captcha->cleanup();
489 }
490
491 $dir = trailingslashit( wpcf7_captcha_tmp_dir() );
492
493 if ( ! is_dir( $dir )
494 or ! is_readable( $dir )
495 or ! wp_is_writable( $dir ) ) {
496 return false;
497 }
498
499 if ( $handle = opendir( $dir ) ) {
500 while ( false !== ( $file = readdir( $handle ) ) ) {
501 if ( ! preg_match( '/^[0-9]+\.(php|txt|png|gif|jpeg)$/', $file ) ) {
502 continue;
503 }
504
505 $stat = stat( path_join( $dir, $file ) );
506
507 if ( $stat['mtime'] + HOUR_IN_SECONDS < time() ) {
508 @unlink( path_join( $dir, $file ) );
509 }
510 }
511
512 closedir( $handle );
513 }
514 }
515
516 function wpcf7_captchac_options( $options ) {
517 if ( ! is_array( $options ) ) {
518 return array();
519 }
520
521 $op = array();
522 $image_size_array = preg_grep( '%^size:[smlSML]$%', $options );
523
524 if ( $image_size = array_shift( $image_size_array ) ) {
525 preg_match( '%^size:([smlSML])$%', $image_size, $is_matches );
526
527 switch ( strtolower( $is_matches[1] ) ) {
528 case 's':
529 $op['img_size'] = array( 60, 20 );
530 $op['base'] = array( 6, 15 );
531 $op['font_size'] = 11;
532 $op['font_char_width'] = 13;
533 break;
534 case 'l':
535 $op['img_size'] = array( 84, 28 );
536 $op['base'] = array( 6, 20 );
537 $op['font_size'] = 17;
538 $op['font_char_width'] = 19;
539 break;
540 case 'm':
541 default:
542 $op['img_size'] = array( 72, 24 );
543 $op['base'] = array( 6, 18 );
544 $op['font_size'] = 14;
545 $op['font_char_width'] = 15;
546 }
547 }
548
549 $fg_color_array = preg_grep(
550 '%^fg:#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$%', $options );
551
552 if ( $fg_color = array_shift( $fg_color_array ) ) {
553 preg_match( '%^fg:#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$%',
554 $fg_color, $fc_matches );
555
556 if ( 3 === strlen( $fc_matches[1] ) ) {
557 $r = substr( $fc_matches[1], 0, 1 );
558 $g = substr( $fc_matches[1], 1, 1 );
559 $b = substr( $fc_matches[1], 2, 1 );
560
561 $op['fg'] = array(
562 hexdec( $r . $r ),
563 hexdec( $g . $g ),
564 hexdec( $b . $b ),
565 );
566 } elseif ( 6 === strlen( $fc_matches[1] ) ) {
567 $r = substr( $fc_matches[1], 0, 2 );
568 $g = substr( $fc_matches[1], 2, 2 );
569 $b = substr( $fc_matches[1], 4, 2 );
570
571 $op['fg'] = array(
572 hexdec( $r ),
573 hexdec( $g ),
574 hexdec( $b ),
575 );
576 }
577 }
578
579 $bg_color_array = preg_grep(
580 '%^bg:#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$%', $options );
581
582 if ( $bg_color = array_shift( $bg_color_array ) ) {
583 preg_match( '%^bg:#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$%',
584 $bg_color, $bc_matches );
585
586 if ( 3 === strlen( $bc_matches[1] ) ) {
587 $r = substr( $bc_matches[1], 0, 1 );
588 $g = substr( $bc_matches[1], 1, 1 );
589 $b = substr( $bc_matches[1], 2, 1 );
590
591 $op['bg'] = array(
592 hexdec( $r . $r ),
593 hexdec( $g . $g ),
594 hexdec( $b . $b ),
595 );
596 } elseif ( 6 === strlen( $bc_matches[1] ) ) {
597 $r = substr( $bc_matches[1], 0, 2 );
598 $g = substr( $bc_matches[1], 2, 2 );
599 $b = substr( $bc_matches[1], 4, 2 );
600
601 $op['bg'] = array(
602 hexdec( $r ),
603 hexdec( $g ),
604 hexdec( $b ),
605 );
606 }
607 }
608
609 return $op;
610 }
611