PluginProbe
Booking Calendar / 11.8
Booking Calendar v11.8
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 10.11.3 All 202 releases
booking / js / captcha / captcha.php

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

434 lines 13.9 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 ( false === $stat || ! isset( $stat['mtime'] ) ) {
293 // A concurrent CAPTCHA cleanup can remove the file after readdir().
294 continue;
295 }
296
297 if ( ( $stat['mtime'] + $minutes * 60 ) < time() ) {
298 // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink
299 if ( ! @wp_delete_file( $file ) ) {
300 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_chmod
301 @chmod( $file, 0644 );
302 // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink
303 @wp_delete_file( $file );
304 }
305
306 $count += 1;
307 }
308
309 if ( $max <= $count ) {
310 break;
311 }
312 }
313
314 closedir( $handle );
315 }
316
317 return $count;
318 }
319
320 /**
321 * Make a temporary directory and generate .htaccess file in it.
322 *
323 * @return bool True on successful create, false on failure.
324 */
325 public function make_tmp_dir() {
326 $dir = trailingslashit( $this->tmp_dir );
327 $dir = $this->normalize_path( $dir );
328
329 if ( ! wp_mkdir_p( $dir ) ) {
330 return false;
331 }
332
333 $htaccess_file = $this->normalize_path( $dir . '.htaccess' );
334
335 if ( file_exists( $htaccess_file ) ) {
336 return true;
337 }
338
339 // FixIn: 8.7.7.5
340 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen
341 if ( $handle = @fopen( $htaccess_file, 'w' ) ) {
342
343 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
344 fwrite( $handle, '# apache 2.2' . "\n" );
345 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
346 fwrite( $handle, '<IfModule !mod_authz_core.c>' . "\n" );
347 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
348 fwrite( $handle, ' Order deny,allow' . "\n" );
349 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
350 fwrite( $handle, ' Deny from all' . "\n" );
351 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
352 fwrite( $handle, ' <Files ~ "^[0-9A-Za-z]+\.(jpeg|gif|png)$">' . "\n" );
353 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
354 fwrite( $handle, ' Allow from all' . "\n" );
355 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
356 fwrite( $handle, ' </Files>' . "\n" );
357 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
358 fwrite( $handle, '</IfModule>' . "\n" );
359
360 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
361 fwrite( $handle, '# apache 2.4' . "\n" );
362 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
363 fwrite( $handle, '<IfModule mod_authz_core.c>' . "\n" );
364 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
365 fwrite( $handle, ' Require all denied' . "\n" );
366 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
367 fwrite( $handle, ' <Files ~ "^[0-9A-Za-z]+\.(jpeg|gif|png)$">' . "\n" );
368 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
369 fwrite( $handle, ' Require all granted' . "\n" );
370 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
371 fwrite( $handle, ' </Files>' . "\n" );
372 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
373 fwrite( $handle, '</IfModule>' . "\n" );
374
375 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
376 fclose( $handle );
377 }
378
379 /*
380 // Check Apache version
381 $apache_ver = '0';
382 if ( ( isset( $_SERVER['SERVER_SOFTWARE'] ) ) && ( false !== strpos( $_SERVER['SERVER_SOFTWARE'], 'Apache/2.4' ) ) ) {
383
384 $apache_ver = explode( "Apache", $_SERVER['SERVER_SOFTWARE'] ); // Apache/1.3.29 (Unix) PHP
385 if ( isset( $apache_ver[1] ) ) {
386 $apache_ver = trim( $apache_ver[1], '/ ' );
387 $apache_ver = explode( " ", $apache_ver );
388 $apache_ver = trim( $apache_ver[0] );
389 } else {
390 $apache_ver = '0';
391 }
392 }
393 if ( version_compare( $apache_ver, '2.4', '>=' ) ) {
394 // Apache 2.4 or newer
395
396 if ( $handle = @fopen( $htaccess_file, 'w' ) ) {
397 fwrite( $handle, 'Require all denied' . "\n" );
398 fwrite( $handle, '<Files ~ "^[0-9A-Za-z]+\\.(jpeg|gif|png)$">' . "\n" );
399 fwrite( $handle, ' Require all granted' . "\n" );
400 fwrite( $handle, '</Files>' . "\n" );
401 fclose( $handle );
402 }
403 } else {
404
405 // Apache 2.2 or lower
406 if ( $handle = @fopen( $htaccess_file, 'w' ) ) {
407 fwrite( $handle, 'Order deny,allow' . "\n" );
408 fwrite( $handle, 'Deny from all' . "\n" );
409 fwrite( $handle, '<Files ~ "^[0-9A-Za-z]+\\.(jpeg|gif|png)$">' . "\n" );
410 fwrite( $handle, ' Allow from all' . "\n" );
411 fwrite( $handle, '</Files>' . "\n" );
412 fclose( $handle );
413 }
414 }
415 */
416 return true;
417 }
418
419 /**
420 * Normalize a filesystem path.
421 *
422 * This should be replaced by wp_normalize_path when the plugin's
423 * minimum requirement becomes WordPress 3.9 or higher.
424 *
425 * @param string $path Path to normalize.
426 * @return string Normalized path.
427 */
428 private function normalize_path( $path ) {
429 $path = str_replace( '\\', '/', $path );
430 $path = preg_replace( '|/+|', '/', $path );
431 return $path;
432 }
433 }
434