Really Simple CAPTCHA - Version 1.5

Version Description

  • The required WordPress version changed to 3.2 and higher.
  • Use plain text file as answer file (again). This time, hash value generated with hash_hmac() is stored in the file.
Download this release

Release Info

Developer takayukister
Plugin Icon 128x128 Really Simple CAPTCHA
Version 1.5
Comparing to
See all releases

Code changes from version 1.4 to 1.5

Files changed (2) hide show
  1. readme.txt +12 -7
  2. really-simple-captcha.php +249 -199
readme.txt CHANGED
@@ -2,9 +2,9 @@
2
  Contributors: takayukister
3
  Donate link: http://contactform7.com/donate/
4
  Tags: captcha
5
- Requires at least: 2.8
6
  Tested up to: 3.3.1
7
- Stable tag: 1.4
8
 
9
  Really Simple CAPTCHA is a CAPTCHA module intended to be called from other plugins. It is originally created for my Contact Form 7 plugin.
10
 
@@ -18,9 +18,9 @@ Note: This product is "really simple" as its name suggests, i.e., it is not stro
18
 
19
  Really Simple CAPTCHA does not use PHP "Sessions" for storing states, unlike many other PHP CAPTCHA solutions, but stores them as temporary files. This allows you to embed it into WordPress without worrying about conflicts.
20
 
21
- When you generate a CAPTCHA, Really Simple CAPTCHA creates two files for it; one is an image file of CAPTCHA, and the other is a PHP file which returns the correct answer to the CAPTCHA.
22
 
23
- The two files have the same (random) prefix in their file names, for example, "a7hk3ux8p.png" and "a7hk3ux8p.php." In this case, for example, when the respondent answers "K5GF" as an answer to the "a7hk3ux8p.png" image, then Really Simple CAPTCHA runs "a7hk3ux8p.php" code and tests the answer against the return value it receives. If the return value is "K5GF," the two match, and the answer is confirmed as correct.
24
 
25
  = How to use with your plugin =
26
 
@@ -41,7 +41,7 @@ Generate a random word for CAPTCHA.
41
 
42
  $word = $captcha_instance->generate_random_word();
43
 
44
- Generate an image file and a PHP code file in the temporary directory.
45
 
46
  $prefix = mt_rand();
47
  $captcha_instance->generate_image( $prefix, $word );
@@ -54,7 +54,7 @@ Check the correctness of the answer.
54
 
55
  If the $correct is true, go ahead. Otherwise, block the respondent -- as it would appear not to be human.
56
 
57
- And last, remove the temporary image and PHP files, as they are no longer in use.
58
 
59
  $captcha_instance->remove( $prefix );
60
 
@@ -89,6 +89,11 @@ If you have any further questions, please submit them [to the support forum](htt
89
 
90
  == Changelog ==
91
 
 
 
 
 
 
92
  = 1.4 =
93
 
94
  * Reverted answer file to PHP. As plain text file is visible from client side, that's not good.
@@ -102,4 +107,4 @@ If you have any further questions, please submit them [to the support forum](htt
102
 
103
  = 1.1 =
104
  * The required WordPress version changed to 2.8 and higher.
105
- * `cleanup()` method added.
2
  Contributors: takayukister
3
  Donate link: http://contactform7.com/donate/
4
  Tags: captcha
5
+ Requires at least: 3.2
6
  Tested up to: 3.3.1
7
+ Stable tag: 1.5
8
 
9
  Really Simple CAPTCHA is a CAPTCHA module intended to be called from other plugins. It is originally created for my Contact Form 7 plugin.
10
 
18
 
19
  Really Simple CAPTCHA does not use PHP "Sessions" for storing states, unlike many other PHP CAPTCHA solutions, but stores them as temporary files. This allows you to embed it into WordPress without worrying about conflicts.
20
 
21
+ When you generate a CAPTCHA, Really Simple CAPTCHA creates two files for it; one is an image file of CAPTCHA, and the other is a text file which stores the correct answer to the CAPTCHA.
22
 
23
+ The two files have the same (random) prefix in their file names, for example, "a7hk3ux8p.png" and "a7hk3ux8p.txt." In this case, for example, when the respondent answers "K5GF" as an answer to the "a7hk3ux8p.png" image, then Really Simple CAPTCHA calculates hash of "K5GF" and tests it against the hash stored in the "a7hk3ux8p.txt" file. If the two match, the answer is confirmed as correct.
24
 
25
  = How to use with your plugin =
26
 
41
 
42
  $word = $captcha_instance->generate_random_word();
43
 
44
+ Generate an image file and a corresponding text file in the temporary directory.
45
 
46
  $prefix = mt_rand();
47
  $captcha_instance->generate_image( $prefix, $word );
54
 
55
  If the $correct is true, go ahead. Otherwise, block the respondent -- as it would appear not to be human.
56
 
57
+ And last, remove the temporary image and text files, as they are no longer in use.
58
 
59
  $captcha_instance->remove( $prefix );
60
 
89
 
90
  == Changelog ==
91
 
92
+ = 1.5 =
93
+
94
+ * The required WordPress version changed to 3.2 and higher.
95
+ * Use plain text file as answer file (again). This time, hash value generated with hash_hmac() is stored in the file.
96
+
97
  = 1.4 =
98
 
99
  * Reverted answer file to PHP. As plain text file is visible from client side, that's not good.
107
 
108
  = 1.1 =
109
  * The required WordPress version changed to 2.8 and higher.
110
+ * cleanup() method added.
really-simple-captcha.php CHANGED
@@ -1,200 +1,250 @@
1
- <?php
2
- /*
3
- Plugin Name: Really Simple CAPTCHA
4
- Plugin URI: http://ideasilo.wordpress.com/2009/03/14/really-simple-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
- Version: 1.4
8
- Author URI: http://ideasilo.wordpress.com/
9
- */
10
-
11
- /* Copyright 2007-2012 Takayuki Miyoshi (email: takayukister at gmail.com)
12
-
13
- This program is free software; you can redistribute it and/or modify
14
- it under the terms of the GNU General Public License as published by
15
- the Free Software Foundation; either version 2 of the License, or
16
- (at your option) any later version.
17
-
18
- This program is distributed in the hope that it will be useful,
19
- but WITHOUT ANY WARRANTY; without even the implied warranty of
20
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
- GNU General Public License for more details.
22
-
23
- You should have received a copy of the GNU General Public License
24
- along with this program; if not, write to the Free Software
25
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26
- */
27
-
28
- class ReallySimpleCaptcha {
29
-
30
- function ReallySimpleCaptcha() {
31
-
32
- /* Characters available in images */
33
- $this->chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
34
-
35
- /* Length of a word in an image */
36
- $this->char_length = 4;
37
-
38
- /* Array of fonts. Randomly picked up per character */
39
- $this->fonts = array(
40
- dirname( __FILE__ ) . '/gentium/GenAI102.TTF',
41
- dirname( __FILE__ ) . '/gentium/GenAR102.TTF',
42
- dirname( __FILE__ ) . '/gentium/GenI102.TTF',
43
- dirname( __FILE__ ) . '/gentium/GenR102.TTF' );
44
-
45
- /* Directory temporary keeping CAPTCHA images and corresponding codes */
46
- $this->tmp_dir = dirname( __FILE__ ) . '/tmp/';
47
-
48
- /* Array of CAPTCHA image size. Width and height */
49
- $this->img_size = array( 72, 24 );
50
-
51
- /* Background color of CAPTCHA image. RGB color 0-255 */
52
- $this->bg = array( 255, 255, 255 );
53
-
54
- /* Foreground (character) color of CAPTCHA image. RGB color 0-255 */
55
- $this->fg = array( 0, 0, 0 );
56
-
57
- /* Coordinates for a text in an image. I don't know the meaning. Just adjust. */
58
- $this->base = array( 6, 18 );
59
-
60
- /* Font size */
61
- $this->font_size = 14;
62
-
63
- /* Width of a character */
64
- $this->font_char_width = 15;
65
-
66
- /* Image type. 'png', 'gif' or 'jpeg' */
67
- $this->img_type = 'png';
68
-
69
- /* Mode of temporary files */
70
- $this->file_mode = 0755;
71
- }
72
-
73
- /* Generate and return random word with $chars characters x $char_length length */
74
-
75
- function generate_random_word() {
76
- $word = '';
77
- for ( $i = 0; $i < $this->char_length; $i++ ) {
78
- $pos = mt_rand( 0, strlen( $this->chars ) - 1 );
79
- $char = $this->chars[$pos];
80
- $word .= $char;
81
- }
82
- return $word;
83
- }
84
-
85
- /* Generate CAPTCHA code and corresponding code and save them into $tmp_dir directory.
86
- $prefix is file prefix for both files.
87
- $captcha is a random word usually generated by generate_random_word()
88
- This function returns the filename of the CAPTCHA image temporary file */
89
-
90
- function generate_image( $prefix, $word ) {
91
- $dir = trailingslashit( $this->tmp_dir );
92
- $filename = null;
93
-
94
- if ( $im = imagecreatetruecolor( $this->img_size[0], $this->img_size[1] ) ) {
95
- $bg = imagecolorallocate( $im, $this->bg[0], $this->bg[1], $this->bg[2] );
96
- $fg = imagecolorallocate( $im, $this->fg[0], $this->fg[1], $this->fg[2] );
97
-
98
- imagefill( $im, 0, 0, $bg );
99
-
100
- $x = $this->base[0] + mt_rand( -2, 2 );
101
-
102
- for ( $i = 0; $i < strlen( $word ); $i++ ) {
103
- $font = $this->fonts[array_rand( $this->fonts )];
104
- imagettftext( $im, $this->font_size, mt_rand( -2, 2 ), $x,
105
- $this->base[1] + mt_rand( -2, 2 ), $fg, $font, $word[$i] );
106
- $x += $this->font_char_width;
107
- }
108
-
109
- switch ( $this->img_type ) {
110
- case 'jpeg':
111
- $filename = sanitize_file_name( $prefix . '.jpeg' );
112
- imagejpeg( $im, $dir . $filename );
113
- break;
114
- case 'gif':
115
- $filename = sanitize_file_name( $prefix . '.gif' );
116
- imagegif( $im, $dir . $filename );
117
- break;
118
- case 'png':
119
- default:
120
- $filename = sanitize_file_name( $prefix . '.png' );
121
- imagepng( $im, $dir . $filename );
122
- }
123
-
124
- imagedestroy( $im );
125
- @chmod( $dir . $filename, $this->file_mode );
126
- }
127
-
128
- $answer_file = $dir . sanitize_file_name( $prefix . '.php' );
129
-
130
- if ( $fh = fopen( $answer_file, 'w' ) ) {
131
- @chmod( $answer_file, $this->file_mode );
132
- fwrite( $fh, '<?php $captcha = "' . $word . '"; ?>' );
133
- fclose( $fh );
134
- }
135
-
136
- return $filename;
137
- }
138
-
139
- /* Check a $response against the code kept in the temporary file with $prefix
140
- Return true if the two match, otherwise return false. */
141
-
142
- function check( $prefix, $response ) {
143
- $dir = trailingslashit( $this->tmp_dir );
144
- $filename = sanitize_file_name( $prefix . '.php' );
145
- $file = $dir . $filename;
146
-
147
- if ( is_readable( $file ) ) {
148
- include( $file );
149
- if ( 0 == strcasecmp( $response, $captcha ) )
150
- return true;
151
- }
152
- return false;
153
- }
154
-
155
- /* Remove temporary files with $prefix */
156
-
157
- function remove( $prefix ) {
158
- $suffixes = array( '.jpeg', '.gif', '.png', '.php', '.txt' );
159
-
160
- foreach ( $suffixes as $suffix ) {
161
- $filename = sanitize_file_name( $prefix . $suffix );
162
- $file = trailingslashit( $this->tmp_dir ) . $filename;
163
- if ( is_file( $file ) )
164
- unlink( $file );
165
- }
166
- }
167
-
168
- /* Clean up dead files older than $minutes in the tmp folder */
169
-
170
- function cleanup( $minutes = 60 ) {
171
- $dir = trailingslashit( $this->tmp_dir );
172
-
173
- if ( ! is_dir( $dir ) || ! is_readable( $dir ) || ! is_writable( $dir ) )
174
- return false;
175
-
176
- $count = 0;
177
-
178
- if ( $handle = @opendir( $dir ) ) {
179
- while ( false !== ( $filename = readdir( $handle ) ) ) {
180
- if ( ! preg_match( '/^[0-9]+\.(php|txt|png|gif|jpeg)$/', $filename ) )
181
- continue;
182
-
183
- $file = $dir . $filename;
184
-
185
- $stat = @stat( $file );
186
- if ( ( $stat['mtime'] + $minutes * 60 ) < time() ) {
187
- @unlink( $file );
188
- $count += 1;
189
- }
190
- }
191
-
192
- closedir( $handle );
193
- }
194
-
195
- return $count;
196
- }
197
-
198
- }
199
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  ?>
1
+ <?php
2
+ /*
3
+ Plugin Name: Really Simple CAPTCHA
4
+ Plugin URI: http://ideasilo.wordpress.com/2009/03/14/really-simple-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
+ Version: 1.5
8
+ Author URI: http://ideasilo.wordpress.com/
9
+ */
10
+
11
+ /* Copyright 2007-2012 Takayuki Miyoshi (email: takayukister at gmail.com)
12
+
13
+ This program is free software; you can redistribute it and/or modify
14
+ it under the terms of the GNU General Public License as published by
15
+ the Free Software Foundation; either version 2 of the License, or
16
+ (at your option) any later version.
17
+
18
+ This program is distributed in the hope that it will be useful,
19
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
+ GNU General Public License for more details.
22
+
23
+ You should have received a copy of the GNU General Public License
24
+ along with this program; if not, write to the Free Software
25
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26
+ */
27
+
28
+ class ReallySimpleCaptcha {
29
+
30
+ function ReallySimpleCaptcha() {
31
+
32
+ /* Characters available in images */
33
+ $this->chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
34
+
35
+ /* Length of a word in an image */
36
+ $this->char_length = 4;
37
+
38
+ /* Array of fonts. Randomly picked up per character */
39
+ $this->fonts = array(
40
+ dirname( __FILE__ ) . '/gentium/GenAI102.TTF',
41
+ dirname( __FILE__ ) . '/gentium/GenAR102.TTF',
42
+ dirname( __FILE__ ) . '/gentium/GenI102.TTF',
43
+ dirname( __FILE__ ) . '/gentium/GenR102.TTF' );
44
+
45
+ /* Directory temporary keeping CAPTCHA images and corresponding text files */
46
+ $this->tmp_dir = dirname( __FILE__ ) . '/tmp/';
47
+
48
+ /* Array of CAPTCHA image size. Width and height */
49
+ $this->img_size = array( 72, 24 );
50
+
51
+ /* Background color of CAPTCHA image. RGB color 0-255 */
52
+ $this->bg = array( 255, 255, 255 );
53
+
54
+ /* Foreground (character) color of CAPTCHA image. RGB color 0-255 */
55
+ $this->fg = array( 0, 0, 0 );
56
+
57
+ /* Coordinates for a text in an image. I don't know the meaning. Just adjust. */
58
+ $this->base = array( 6, 18 );
59
+
60
+ /* Font size */
61
+ $this->font_size = 14;
62
+
63
+ /* Width of a character */
64
+ $this->font_char_width = 15;
65
+
66
+ /* Image type. 'png', 'gif' or 'jpeg' */
67
+ $this->img_type = 'png';
68
+
69
+ /* Mode of temporary image files */
70
+ $this->file_mode = 0444;
71
+
72
+ /* Mode of temporary answer text files */
73
+ $this->answer_file_mode = 0440;
74
+ }
75
+
76
+ /* Generate and return random word with $chars characters x $char_length length */
77
+
78
+ function generate_random_word() {
79
+ $word = '';
80
+
81
+ for ( $i = 0; $i < $this->char_length; $i++ ) {
82
+ $pos = mt_rand( 0, strlen( $this->chars ) - 1 );
83
+ $char = $this->chars[$pos];
84
+ $word .= $char;
85
+ }
86
+
87
+ return $word;
88
+ }
89
+
90
+ /* Generate CAPTCHA code and corresponding code and save them into $tmp_dir directory.
91
+ $prefix is file prefix for both files.
92
+ $captcha is a random word usually generated by generate_random_word()
93
+ This function returns the filename of the CAPTCHA image temporary file */
94
+
95
+ function generate_image( $prefix, $word ) {
96
+ $dir = trailingslashit( $this->tmp_dir );
97
+ $filename = null;
98
+
99
+ if ( $im = imagecreatetruecolor( $this->img_size[0], $this->img_size[1] ) ) {
100
+ $bg = imagecolorallocate( $im, $this->bg[0], $this->bg[1], $this->bg[2] );
101
+ $fg = imagecolorallocate( $im, $this->fg[0], $this->fg[1], $this->fg[2] );
102
+
103
+ imagefill( $im, 0, 0, $bg );
104
+
105
+ $x = $this->base[0] + mt_rand( -2, 2 );
106
+
107
+ for ( $i = 0; $i < strlen( $word ); $i++ ) {
108
+ $font = $this->fonts[array_rand( $this->fonts )];
109
+ imagettftext( $im, $this->font_size, mt_rand( -2, 2 ), $x,
110
+ $this->base[1] + mt_rand( -2, 2 ), $fg, $font, $word[$i] );
111
+ $x += $this->font_char_width;
112
+ }
113
+
114
+ switch ( $this->img_type ) {
115
+ case 'jpeg':
116
+ $filename = sanitize_file_name( $prefix . '.jpeg' );
117
+ imagejpeg( $im, $dir . $filename );
118
+ break;
119
+ case 'gif':
120
+ $filename = sanitize_file_name( $prefix . '.gif' );
121
+ imagegif( $im, $dir . $filename );
122
+ break;
123
+ case 'png':
124
+ default:
125
+ $filename = sanitize_file_name( $prefix . '.png' );
126
+ imagepng( $im, $dir . $filename );
127
+ }
128
+
129
+ imagedestroy( $im );
130
+ @chmod( $dir . $filename, $this->file_mode );
131
+ }
132
+
133
+ $this->generate_answer_file( $prefix, $word );
134
+
135
+ return $filename;
136
+ }
137
+
138
+ /* Generate answer file corresponding to CAPTCHA image. */
139
+
140
+ function generate_answer_file( $prefix, $word ) {
141
+ $dir = trailingslashit( $this->tmp_dir );
142
+ $answer_file = $dir . sanitize_file_name( $prefix . '.txt' );
143
+
144
+ if ( $fh = fopen( $answer_file, 'w' ) ) {
145
+ $word = strtoupper( $word );
146
+ $salt = wp_generate_password( 64 );
147
+ $hash = hash_hmac( 'md5', $word, $salt );
148
+
149
+ $code = $salt . '|' . $hash;
150
+
151
+ fwrite( $fh, $code );
152
+ fclose( $fh );
153
+ }
154
+
155
+ @chmod( $answer_file, $this->answer_file_mode );
156
+ }
157
+
158
+ /* Check a $response against the code kept in the temporary file with $prefix
159
+ Return true if the two match, otherwise return false. */
160
+
161
+ function check( $prefix, $response ) {
162
+ $response = strtoupper( $response );
163
+
164
+ $dir = trailingslashit( $this->tmp_dir );
165
+ $filename = sanitize_file_name( $prefix . '.txt' );
166
+ $file = $dir . $filename;
167
+
168
+ if ( is_readable( $file ) && ( $code = file_get_contents( $file ) ) ) {
169
+ $code = explode( '|', $code, 2 );
170
+
171
+ $salt = $code[0];
172
+ $hash = $code[1];
173
+
174
+ if ( hash_hmac( 'md5', $response, $salt ) == $hash )
175
+ return true;
176
+ }
177
+
178
+ return false;
179
+ }
180
+
181
+ /* Remove temporary files with $prefix */
182
+
183
+ function remove( $prefix ) {
184
+ $suffixes = array( '.jpeg', '.gif', '.png', '.php', '.txt' );
185
+
186
+ foreach ( $suffixes as $suffix ) {
187
+ $filename = sanitize_file_name( $prefix . $suffix );
188
+ $file = trailingslashit( $this->tmp_dir ) . $filename;
189
+ if ( is_file( $file ) )
190
+ unlink( $file );
191
+ }
192
+ }
193
+
194
+ /* Clean up dead files older than $minutes in the tmp folder */
195
+
196
+ function cleanup( $minutes = 60 ) {
197
+ $dir = trailingslashit( $this->tmp_dir );
198
+
199
+ if ( ! is_dir( $dir ) || ! is_readable( $dir ) || ! is_writable( $dir ) )
200
+ return false;
201
+
202
+ $count = 0;
203
+
204
+ if ( $handle = @opendir( $dir ) ) {
205
+ while ( false !== ( $filename = readdir( $handle ) ) ) {
206
+ if ( ! preg_match( '/^[0-9]+\.(php|txt|png|gif|jpeg)$/', $filename ) )
207
+ continue;
208
+
209
+ $file = $dir . $filename;
210
+
211
+ $stat = @stat( $file );
212
+ if ( ( $stat['mtime'] + $minutes * 60 ) < time() ) {
213
+ @unlink( $file );
214
+ $count += 1;
215
+ }
216
+ }
217
+
218
+ closedir( $handle );
219
+ }
220
+
221
+ return $count;
222
+ }
223
+
224
+ /* Make a temporary directory and generate .htaccess file in it */
225
+
226
+ function make_tmp_dir() {
227
+ $dir = trailingslashit( $this->tmp_dir );
228
+
229
+ if ( ! wp_mkdir_p( $dir ) )
230
+ return false;
231
+
232
+ $htaccess_file = $dir . '.htaccess';
233
+
234
+ if ( file_exists( $htaccess_file ) )
235
+ return true;
236
+
237
+ if ( $handle = @fopen( $htaccess_file, 'w' ) ) {
238
+ fwrite( $handle, 'Order deny,allow' . "\n" );
239
+ fwrite( $handle, 'Deny from all' . "\n" );
240
+ fwrite( $handle, '<Files ~ "^[0-9A-Za-z]+\\.(jpeg|gif|png)$">' . "\n" );
241
+ fwrite( $handle, ' Allow from all' . "\n" );
242
+ fwrite( $handle, '</Files>' . "\n" );
243
+ fclose( $handle );
244
+ }
245
+
246
+ return true;
247
+ }
248
+ }
249
+
250
  ?>