PluginProbe
Booking Calendar / 10.15.7
Booking Calendar v10.15.7
11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 10.11.2 10.11.3 10.11.4 All 201 releases
booking / js / captcha / captcha.php

captcha.php in Booking Calendar 10.15.7, at js/captcha/captcha.php

428 lines 13.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Really Simple CAPTCHA
4 Plugin URI: http://contactform7.com/captcha/
5 Description: Really Simple CAPTCHA is a CAPTCHA module intended to be called from other plugins. It is originally created for my Contact Form 7 plugin.
6 Author: Takayuki Miyoshi
7 Author URI: http://ideasilo.wordpress.com/
8 Text Domain: really-simple-captcha
9 Version: 1.9
10 */
11
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit; // Exit if accessed directly.
14 }
15
16 /* Copyright 2007-2016 Takayuki Miyoshi (email: takayukister at gmail.com)
17
18 This program is free software; you can redistribute it and/or modify
19 it under the terms of the GNU General Public License as published by
20 the Free Software Foundation; either version 2 of the License, or
21 (at your option) any later version.
22
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 */
32
33 define( 'WPDEVREALLYSIMPLECAPTCHA_VERSION', '1.9.0.1' );
34
35 class wpdevReallySimpleCaptcha {
36
37 public $chars;
38 public $char_length;
39 public $fonts;
40 public $tmp_dir;
41 public $img_size;
42 public $bg;
43 public $fg;
44 public $base;
45 public $font_size;
46 public $font_char_width;
47 public $img_type;
48 public $file_mode;
49 public $answer_file_mode;
50
51 public function __construct() {
52
53 /* Characters available in images */
54 $this->chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
55
56 /* Length of a word in an image */
57 $this->char_length = 4;
58
59 /* Array of fonts. Randomly picked up per character */
60 $this->fonts = array(
61 dirname( __FILE__ ) . '/gentium/GenBkBasR.ttf',
62 dirname( __FILE__ ) . '/gentium/GenBkBasI.ttf',
63 dirname( __FILE__ ) . '/gentium/GenBkBasBI.ttf',
64 dirname( __FILE__ ) . '/gentium/GenBkBasB.ttf' );
65
66 /* Directory temporary keeping CAPTCHA images and corresponding text files */
67 $this->tmp_dir = path_join( dirname( __FILE__ ), 'tmp' );
68
69 /* Array of CAPTCHA image size. Width and height */
70 $this->img_size = array( 72, 24 );
71
72 /* Background color of CAPTCHA image. RGB color 0-255 */
73 $this->bg = array( 255, 255, 255 );
74
75 /* Foreground (character) color of CAPTCHA image. RGB color 0-255 */
76 $this->fg = array( 0, 0, 0 );
77
78 // FixIn: 10.0.0.54.
79 if ( ( function_exists( 'get_bk_option' ) ) && ( 'wpbc_theme_dark_1' === get_bk_option( 'booking_form_theme' ) ) ) {
80 $this->bg = array( 39, 39, 39 );
81 $this->fg = array( 255, 255, 255 );
82 }
83
84 /* Coordinates for a text in an image. I don't know the meaning. Just adjust. */
85 $this->base = array( 6, 18 );
86
87 /* Font size */
88 $this->font_size = 14;
89
90 /* Width of a character */
91 $this->font_char_width = 15;
92
93 /* Image type. 'png', 'gif' or 'jpeg' */
94 $this->img_type = 'png';
95
96 /* Mode of temporary image files */
97 $this->file_mode = 0644;
98
99 /* Mode of temporary answer text files */
100 $this->answer_file_mode = 0640;
101 }
102
103 /**
104 * Generate and return a random word.
105 *
106 * @return string Random word with $chars characters x $char_length length
107 */
108 public function generate_random_word() {
109 $word = '';
110
111 for ( $i = 0; $i < $this->char_length; $i++ ) {
112 $pos = wp_rand( 0, strlen( $this->chars ) - 1 );
113 $char = $this->chars[$pos];
114 $word .= $char;
115 }
116
117 return $word;
118 }
119
120 /**
121 * Generate CAPTCHA image and corresponding answer file.
122 *
123 * @param string $prefix File prefix used for both files
124 * @param string $word Random word generated by generate_random_word()
125 * @return string|bool The file name of the CAPTCHA image. Return false if temp directory is not available.
126 */
127 public function generate_image( $prefix, $word ) {
128 if ( ! $this->make_tmp_dir() ) {
129 return false;
130 }
131
132 $this->cleanup();
133
134 $dir = trailingslashit( $this->tmp_dir );
135 $filename = null;
136
137 if ( $im = imagecreatetruecolor( $this->img_size[0], $this->img_size[1] ) ) {
138
139 $bg = imagecolorallocate( $im, $this->bg[0], $this->bg[1], $this->bg[2] );
140 $fg = imagecolorallocate( $im, $this->fg[0], $this->fg[1], $this->fg[2] );
141
142 imagefill( $im, 0, 0, $bg );
143 // phpcs:ignore WordPress.WP.AlternativeFunctions.rand_mt_rand
144 $x = $this->base[0] + mt_rand( -2, 2 );
145
146 for ( $i = 0; $i < strlen( $word ); $i++ ) {
147 $font = $this->fonts[array_rand( $this->fonts )];
148 $font = $this->normalize_path( $font );
149 // phpcs:ignore WordPress.WP.AlternativeFunctions.rand_mt_rand
150 imagettftext( $im, $this->font_size, mt_rand( -12, 12 ), $x, $this->base[1] + mt_rand( -2, 2 ), $fg, $font, $word[$i] );
151 $x += $this->font_char_width;
152 }
153
154 switch ( $this->img_type ) {
155 case 'jpeg':
156 $filename = sanitize_file_name( $prefix . '.jpeg' );
157 $file = $this->normalize_path( $dir . $filename );
158 imagejpeg( $im, $file );
159 break;
160 case 'gif':
161 $filename = sanitize_file_name( $prefix . '.gif' );
162 $file = $this->normalize_path( $dir . $filename );
163 imagegif( $im, $file );
164 break;
165 case 'png':
166 default:
167 $filename = sanitize_file_name( $prefix . '.png' );
168 $file = $this->normalize_path( $dir . $filename );
169 imagepng( $im, $file );
170 }
171
172 imagedestroy( $im );
173 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_chmod
174 @chmod( $file, $this->file_mode );
175 }
176
177 $this->generate_answer_file( $prefix, $word );
178
179 return $filename;
180 }
181
182 /**
183 * Generate answer file corresponding to CAPTCHA image.
184 *
185 * @param string $prefix File prefix used for answer file
186 * @param string $word Random word generated by generate_random_word()
187 */
188 public function generate_answer_file( $prefix, $word ) {
189 $dir = trailingslashit( $this->tmp_dir );
190 $answer_file = $dir . sanitize_file_name( $prefix . '.txt' );
191 $answer_file = $this->normalize_path( $answer_file );
192 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen
193 if ( $fh = @fopen( $answer_file, 'w' ) ) {
194 $word = strtoupper( $word );
195 $salt = wp_generate_password( 64 );
196 $hash = hash_hmac( 'md5', $word, $salt );
197
198 $code = $salt . '|' . $hash;
199 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
200 fwrite( $fh, $code );
201 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
202 fclose( $fh );
203 }
204 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_chmod
205 @chmod( $answer_file, $this->answer_file_mode );
206 }
207
208 /**
209 * Check a response against the code kept in the temporary file.
210 *
211 * @param string $prefix File prefix used for both files
212 * @param string $response CAPTCHA response
213 * @return bool Return true if the two match, otherwise return false.
214 */
215 public function check( $prefix, $response ) {
216 if ( 0 == strlen( $prefix ) ) {
217 return false;
218 }
219
220 $response = str_replace( array( " ", "\t" ), '', $response );
221 $response = strtoupper( $response );
222
223 $dir = trailingslashit( $this->tmp_dir );
224 $filename = sanitize_file_name( $prefix . '.txt' );
225 $file = $this->normalize_path( $dir . $filename );
226 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
227 if ( @is_readable( $file ) && ( $code = file_get_contents( $file ) ) ) {
228 $code = explode( '|', $code, 2 );
229
230 $salt = $code[0];
231 $hash = $code[1];
232
233 if ( hash_hmac( 'md5', $response, $salt ) == $hash ) {
234 return true;
235 }
236 }
237
238 return false;
239 }
240
241 /**
242 * Remove temporary files with given prefix.
243 *
244 * @param string $prefix File prefix
245 */
246 public function remove( $prefix ) {
247 $dir = trailingslashit( $this->tmp_dir );
248 $suffixes = array( '.jpeg', '.gif', '.png', '.php', '.txt' );
249
250 foreach ( $suffixes as $suffix ) {
251 $filename = sanitize_file_name( $prefix . $suffix );
252 $file = $this->normalize_path( $dir . $filename );
253
254 if ( @is_file( $file ) ) {
255 // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink
256 @wp_delete_file( $file );
257 }
258 }
259 }
260
261 /**
262 * Clean up dead files older than given length of time.
263 *
264 * @param int $minutes Consider older files than this time as dead files
265 * @return int|bool The number of removed files. Return false if error occurred.
266 */
267 public function cleanup( $minutes = 60, $max = 100 ) {
268 $dir = trailingslashit( $this->tmp_dir );
269 $dir = $this->normalize_path( $dir );
270
271 if ( ! @is_dir( $dir ) || ! @is_readable( $dir ) ) {
272 return false;
273 }
274
275 $is_win = ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) );
276 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable
277 if ( ! ( $is_win ? win_is_writable( $dir ) : @is_writable( $dir ) ) ) {
278 return false;
279 }
280
281 $count = 0;
282
283 if ( $handle = @opendir( $dir ) ) {
284 while ( false !== ( $filename = readdir( $handle ) ) ) {
285 if ( ! preg_match( '/^[0-9]+\.(php|txt|png|gif|jpeg)$/', $filename ) ) {
286 continue;
287 }
288
289 $file = $this->normalize_path( $dir . $filename );
290
291 $stat = @stat( $file );
292 if ( ( $stat['mtime'] + $minutes * 60 ) < time() ) {
293 // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink
294 if ( ! @wp_delete_file( $file ) ) {
295 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_chmod
296 @chmod( $file, 0644 );
297 // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink
298 @wp_delete_file( $file );
299 }
300
301 $count += 1;
302 }
303
304 if ( $max <= $count ) {
305 break;
306 }
307 }
308
309 closedir( $handle );
310 }
311
312 return $count;
313 }
314
315 /**
316 * Make a temporary directory and generate .htaccess file in it.
317 *
318 * @return bool True on successful create, false on failure.
319 */
320 public function make_tmp_dir() {
321 $dir = trailingslashit( $this->tmp_dir );
322 $dir = $this->normalize_path( $dir );
323
324 if ( ! wp_mkdir_p( $dir ) ) {
325 return false;
326 }
327
328 $htaccess_file = $this->normalize_path( $dir . '.htaccess' );
329
330 if ( file_exists( $htaccess_file ) ) {
331 return true;
332 }
333
334 // FixIn: 8.7.7.5
335 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen
336 if ( $handle = @fopen( $htaccess_file, 'w' ) ) {
337
338 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
339 fwrite( $handle, '# apache 2.2' . "\n" );
340 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
341 fwrite( $handle, '<IfModule !mod_authz_core.c>' . "\n" );
342 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
343 fwrite( $handle, ' Order deny,allow' . "\n" );
344 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
345 fwrite( $handle, ' Deny from all' . "\n" );
346 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
347 fwrite( $handle, ' <Files ~ "^[0-9A-Za-z]+\.(jpeg|gif|png)$">' . "\n" );
348 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
349 fwrite( $handle, ' Allow from all' . "\n" );
350 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
351 fwrite( $handle, ' </Files>' . "\n" );
352 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
353 fwrite( $handle, '</IfModule>' . "\n" );
354
355 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
356 fwrite( $handle, '# apache 2.4' . "\n" );
357 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
358 fwrite( $handle, '<IfModule mod_authz_core.c>' . "\n" );
359 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
360 fwrite( $handle, ' Require all denied' . "\n" );
361 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
362 fwrite( $handle, ' <Files ~ "^[0-9A-Za-z]+\.(jpeg|gif|png)$">' . "\n" );
363 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
364 fwrite( $handle, ' Require all granted' . "\n" );
365 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
366 fwrite( $handle, ' </Files>' . "\n" );
367 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
368 fwrite( $handle, '</IfModule>' . "\n" );
369
370 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
371 fclose( $handle );
372 }
373
374 /*
375 // Check Apache version
376 $apache_ver = '0';
377 if ( ( isset( $_SERVER['SERVER_SOFTWARE'] ) ) && ( false !== strpos( $_SERVER['SERVER_SOFTWARE'], 'Apache/2.4' ) ) ) {
378
379 $apache_ver = explode( "Apache", $_SERVER['SERVER_SOFTWARE'] ); // Apache/1.3.29 (Unix) PHP
380 if ( isset( $apache_ver[1] ) ) {
381 $apache_ver = trim( $apache_ver[1], '/ ' );
382 $apache_ver = explode( " ", $apache_ver );
383 $apache_ver = trim( $apache_ver[0] );
384 } else {
385 $apache_ver = '0';
386 }
387 }
388 if ( version_compare( $apache_ver, '2.4', '>=' ) ) {
389 // Apache 2.4 or newer
390
391 if ( $handle = @fopen( $htaccess_file, 'w' ) ) {
392 fwrite( $handle, 'Require all denied' . "\n" );
393 fwrite( $handle, '<Files ~ "^[0-9A-Za-z]+\\.(jpeg|gif|png)$">' . "\n" );
394 fwrite( $handle, ' Require all granted' . "\n" );
395 fwrite( $handle, '</Files>' . "\n" );
396 fclose( $handle );
397 }
398 } else {
399
400 // Apache 2.2 or lower
401 if ( $handle = @fopen( $htaccess_file, 'w' ) ) {
402 fwrite( $handle, 'Order deny,allow' . "\n" );
403 fwrite( $handle, 'Deny from all' . "\n" );
404 fwrite( $handle, '<Files ~ "^[0-9A-Za-z]+\\.(jpeg|gif|png)$">' . "\n" );
405 fwrite( $handle, ' Allow from all' . "\n" );
406 fwrite( $handle, '</Files>' . "\n" );
407 fclose( $handle );
408 }
409 }
410 */
411 return true;
412 }
413
414 /**
415 * Normalize a filesystem path.
416 *
417 * This should be replaced by wp_normalize_path when the plugin's
418 * minimum requirement becomes WordPress 3.9 or higher.
419 *
420 * @param string $path Path to normalize.
421 * @return string Normalized path.
422 */
423 private function normalize_path( $path ) {
424 $path = str_replace( '\\', '/', $path );
425 $path = preg_replace( '|/+|', '/', $path );
426 return $path;
427 }
428 }