PluginProbe
Booking Calendar / 10.11.2
Booking Calendar v10.11.2
11.8.3 11.8.2 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 All 203 releases
booking / js / captcha / captcha.php

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

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