Version Description
Download this release
Release Info
Developer | Cimmo |
Plugin | Cimy User Extra Fields |
Version | 2.6.2 |
Comparing to | |
See all releases |
Code changes from version 2.6.1 to 2.6.2
- README_OFFICIAL.txt +4 -0
- cimy_uef_register.php +4 -4
- cimy_user_extra_fields.php +2 -2
- readme.txt +2 -2
- securimage/README.txt +53 -30
- securimage/WavFile.php +50 -15
- securimage/audio/.htaccess +1 -0
- securimage/audio/en/0.wav +0 -0
- securimage/audio/en/1.wav +0 -0
- securimage/audio/en/10.wav +0 -0
- securimage/audio/en/11.wav +0 -0
- securimage/audio/en/12.wav +0 -0
- securimage/audio/en/13.wav +0 -0
- securimage/audio/en/14.wav +0 -0
- securimage/audio/en/15.wav +0 -0
- securimage/audio/en/16.wav +0 -0
- securimage/audio/en/17.wav +0 -0
- securimage/audio/en/18.wav +0 -0
- securimage/audio/en/19.wav +0 -0
- securimage/audio/en/2.wav +0 -0
- securimage/audio/en/20.wav +0 -0
- securimage/audio/en/3.wav +0 -0
- securimage/audio/en/4.wav +0 -0
- securimage/audio/en/5.wav +0 -0
- securimage/audio/en/6.wav +0 -0
- securimage/audio/en/7.wav +0 -0
- securimage/audio/en/8.wav +0 -0
- securimage/audio/en/9.wav +0 -0
- securimage/audio/en/A.wav +0 -0
- securimage/audio/en/B.wav +0 -0
- securimage/audio/en/C.wav +0 -0
- securimage/audio/en/D.wav +0 -0
- securimage/audio/en/E.wav +0 -0
- securimage/audio/en/F.wav +0 -0
- securimage/audio/en/G.wav +0 -0
- securimage/audio/en/H.wav +0 -0
- securimage/audio/en/I.wav +0 -0
- securimage/audio/en/J.wav +0 -0
- securimage/audio/en/K.wav +0 -0
- securimage/audio/en/L.wav +0 -0
- securimage/audio/en/M.wav +0 -0
- securimage/audio/en/N.wav +0 -0
- securimage/audio/en/O.wav +0 -0
- securimage/audio/en/P.wav +0 -0
- securimage/audio/en/Q.wav +0 -0
- securimage/audio/en/R.wav +0 -0
- securimage/audio/en/S.wav +0 -0
- securimage/audio/en/T.wav +0 -0
- securimage/audio/en/U.wav +0 -0
- securimage/audio/en/V.wav +0 -0
- securimage/audio/en/W.wav +0 -0
- securimage/audio/en/X.wav +0 -0
- securimage/audio/en/Y.wav +0 -0
- securimage/audio/en/Z.wav +0 -0
- securimage/example_form.ajax.php +2 -2
- securimage/example_form.php +38 -27
- securimage/securimage.php +520 -102
- securimage/securimage_play.php +19 -1
- securimage/securimage_show.php +3 -1
README_OFFICIAL.txt
CHANGED
@@ -631,6 +631,10 @@ A lot of times I cannot reproduce the problem and I need more details, so if you
|
|
631 |
|
632 |
|
633 |
CHANGELOG:
|
|
|
|
|
|
|
|
|
634 |
v2.6.1 - 30/09/2013
|
635 |
- Added dropdowns for the year and the month selectors to the date picker
|
636 |
- Added Min and Max date support for the new 'date' extra field (no backend support yet)
|
631 |
|
632 |
|
633 |
CHANGELOG:
|
634 |
+
v2.6.2 - 18/04/2014
|
635 |
+
- Fixed date picker on registration page was conflicting with Google Chrome's one (thanks to Francesca)
|
636 |
+
- Updated Securimage Captcha to v3.5.2
|
637 |
+
|
638 |
v2.6.1 - 30/09/2013
|
639 |
- Added dropdowns for the year and the month selectors to the date picker
|
640 |
- Added Min and Max date support for the new 'date' extra field (no backend support yet)
|
cimy_uef_register.php
CHANGED
@@ -672,7 +672,7 @@ function cimy_uef_validate_username($valid, $username) {
|
|
672 |
// show_type == 1 - search form, all fields are text, password fields are skipped
|
673 |
// show_type == 2 - confirmation form, all fields are plain text, images can be cropped
|
674 |
function cimy_registration_form($errors=null, $show_type=0) {
|
675 |
-
global $wpdb, $start_cimy_uef_comment, $end_cimy_uef_comment, $rule_maxlen_needed, $fields_name_prefix, $wp_fields_name_prefix, $cuef_plugin_dir, $cimy_uef_file_types, $cimy_uef_textarea_types, $user_level, $cimy_uef_domain, $cimy_uef_file_images_types;
|
676 |
|
677 |
if (cimy_is_at_least_wordpress35())
|
678 |
cimy_switch_to_blog();
|
@@ -889,7 +889,7 @@ function cimy_registration_form($errors=null, $show_type=0) {
|
|
889 |
$obj_class = ' class="'.$input_class.$obj_class.'"';
|
890 |
$obj_name = ' name="'.$input_name.'"';
|
891 |
|
892 |
-
if ($type
|
893 |
$obj_type = ' type="text"';
|
894 |
else
|
895 |
$obj_type = ' type="'.$type.'"';
|
@@ -1218,13 +1218,13 @@ function cimy_registration_form($errors=null, $show_type=0) {
|
|
1218 |
else
|
1219 |
$width = 278;
|
1220 |
?>
|
1221 |
-
<div style="width: <?php echo $width; ?>px;
|
1222 |
<img id="captcha" align="left" style="padding-right: 5px; border: 0" src="<?php echo $cuef_securimage_webpath; ?>/securimage_show_captcha.php" alt="CAPTCHA Image" />
|
1223 |
<object type="application/x-shockwave-flash" data="<?php echo $cuef_securimage_webpath; ?>/securimage_play.swf?audio_file=<?php echo $cuef_securimage_webpath; ?>/securimage_play.php&bgColor1=#fff&bgColor2=#fff&iconColor=#777&borderWidth=1&borderColor=#000" height="19" width="19"><param name="movie" value="<?php echo $cuef_securimage_webpath; ?>/securimage_play.swf?audio_file=<?php echo $cuef_securimage_webpath; ?>/securimage_play.php&bgColor1=#fff&bgColor2=#fff&iconColor=#777&borderWidth=1&borderColor=#000" /></object>
|
1224 |
<br /><br /><br />
|
1225 |
<a align="right"<?php if (!empty($obj_tabindex)) echo " tabindex=\"".$tabindex."\""; $tabindex++; ?> style="border-style: none" href="#" onclick="document.getElementById('captcha').src = '<?php echo $cuef_securimage_webpath; ?>/securimage_show_captcha.php?' + Math.random(); return false"><img src="<?php echo $cuef_securimage_webpath; ?>/images/refresh.png" alt="<?php _e("Change image", $cimy_uef_domain); ?>" border="0" onclick="this.blur()" align="bottom" height="19" width="19" /></a>
|
1226 |
</div>
|
1227 |
-
<div style="width: <?php echo $width; ?>px;
|
1228 |
<?php _e("Insert the code:", $cimy_uef_domain); ?> <input type="text" name="securimage_response_field" size="12" maxlength="16"<?php if (!empty($obj_tabindex)) echo " tabindex=\"".$tabindex."\""; $tabindex++; ?> />
|
1229 |
</div>
|
1230 |
<?php
|
672 |
// show_type == 1 - search form, all fields are text, password fields are skipped
|
673 |
// show_type == 2 - confirmation form, all fields are plain text, images can be cropped
|
674 |
function cimy_registration_form($errors=null, $show_type=0) {
|
675 |
+
global $wpdb, $start_cimy_uef_comment, $end_cimy_uef_comment, $rule_maxlen_needed, $fields_name_prefix, $wp_fields_name_prefix, $cuef_plugin_dir, $cimy_uef_file_types, $cimy_uef_textarea_types, $user_level, $cimy_uef_domain, $cimy_uef_file_images_types, $cimy_uef_text_types;
|
676 |
|
677 |
if (cimy_is_at_least_wordpress35())
|
678 |
cimy_switch_to_blog();
|
889 |
$obj_class = ' class="'.$input_class.$obj_class.'"';
|
890 |
$obj_name = ' name="'.$input_name.'"';
|
891 |
|
892 |
+
if (in_array($type, $cimy_uef_text_types))
|
893 |
$obj_type = ' type="text"';
|
894 |
else
|
895 |
$obj_type = ' type="'.$type.'"';
|
1218 |
else
|
1219 |
$width = 278;
|
1220 |
?>
|
1221 |
+
<div style="width: <?php echo $width; ?>px; clear: both; height: 80px; vertical-align: text-top;">
|
1222 |
<img id="captcha" align="left" style="padding-right: 5px; border: 0" src="<?php echo $cuef_securimage_webpath; ?>/securimage_show_captcha.php" alt="CAPTCHA Image" />
|
1223 |
<object type="application/x-shockwave-flash" data="<?php echo $cuef_securimage_webpath; ?>/securimage_play.swf?audio_file=<?php echo $cuef_securimage_webpath; ?>/securimage_play.php&bgColor1=#fff&bgColor2=#fff&iconColor=#777&borderWidth=1&borderColor=#000" height="19" width="19"><param name="movie" value="<?php echo $cuef_securimage_webpath; ?>/securimage_play.swf?audio_file=<?php echo $cuef_securimage_webpath; ?>/securimage_play.php&bgColor1=#fff&bgColor2=#fff&iconColor=#777&borderWidth=1&borderColor=#000" /></object>
|
1224 |
<br /><br /><br />
|
1225 |
<a align="right"<?php if (!empty($obj_tabindex)) echo " tabindex=\"".$tabindex."\""; $tabindex++; ?> style="border-style: none" href="#" onclick="document.getElementById('captcha').src = '<?php echo $cuef_securimage_webpath; ?>/securimage_show_captcha.php?' + Math.random(); return false"><img src="<?php echo $cuef_securimage_webpath; ?>/images/refresh.png" alt="<?php _e("Change image", $cimy_uef_domain); ?>" border="0" onclick="this.blur()" align="bottom" height="19" width="19" /></a>
|
1226 |
</div>
|
1227 |
+
<div style="width: <?php echo $width; ?>px; clear: both; height: 70px; vertical-align: bottom; padding: 5px;">
|
1228 |
<?php _e("Insert the code:", $cimy_uef_domain); ?> <input type="text" name="securimage_response_field" size="12" maxlength="16"<?php if (!empty($obj_tabindex)) echo " tabindex=\"".$tabindex."\""; $tabindex++; ?> />
|
1229 |
</div>
|
1230 |
<?php
|
cimy_user_extra_fields.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
Plugin Name: Cimy User Extra Fields
|
4 |
Plugin URI: http://www.marcocimmino.net/cimy-wordpress-plugins/cimy-user-extra-fields/
|
5 |
Description: Add some useful fields to registration and user's info
|
6 |
-
Version: 2.6.
|
7 |
Author: Marco Cimmino
|
8 |
Author URI: mailto:cimmino.marco@gmail.com
|
9 |
License: GPL2
|
@@ -162,7 +162,7 @@ add_action('admin_init', 'cimy_uef_admin_init');
|
|
162 |
add_action('init', 'cimy_uef_init');
|
163 |
|
164 |
$cimy_uef_name = "Cimy User Extra Fields";
|
165 |
-
$cimy_uef_version = "2.6.
|
166 |
$cimy_uef_url = "http://www.marcocimmino.net/cimy-wordpress-plugins/cimy-user-extra-fields/";
|
167 |
$cimy_project_url = "http://www.marcocimmino.net/cimy-wordpress-plugins/support-the-cimy-project-paypal/";
|
168 |
|
3 |
Plugin Name: Cimy User Extra Fields
|
4 |
Plugin URI: http://www.marcocimmino.net/cimy-wordpress-plugins/cimy-user-extra-fields/
|
5 |
Description: Add some useful fields to registration and user's info
|
6 |
+
Version: 2.6.2
|
7 |
Author: Marco Cimmino
|
8 |
Author URI: mailto:cimmino.marco@gmail.com
|
9 |
License: GPL2
|
162 |
add_action('init', 'cimy_uef_init');
|
163 |
|
164 |
$cimy_uef_name = "Cimy User Extra Fields";
|
165 |
+
$cimy_uef_version = "2.6.2";
|
166 |
$cimy_uef_url = "http://www.marcocimmino.net/cimy-wordpress-plugins/cimy-user-extra-fields/";
|
167 |
$cimy_project_url = "http://www.marcocimmino.net/cimy-wordpress-plugins/support-the-cimy-project-paypal/";
|
168 |
|
readme.txt
CHANGED
@@ -4,8 +4,8 @@ Donate link: http://www.marcocimmino.net/cimy-wordpress-plugins/support-the-cimy
|
|
4 |
Website link: http://www.marcocimmino.net/cimy-wordpress-plugins/cimy-user-extra-fields/
|
5 |
Tags: cimy, admin, registration, profile, extra fields, avatar, gravatar, recaptcha, captcha
|
6 |
Requires at least: 3.1
|
7 |
-
Tested up to: 3.
|
8 |
-
Stable tag: 2.6.
|
9 |
|
10 |
Add some useful fields to registration and user's info
|
11 |
|
4 |
Website link: http://www.marcocimmino.net/cimy-wordpress-plugins/cimy-user-extra-fields/
|
5 |
Tags: cimy, admin, registration, profile, extra fields, avatar, gravatar, recaptcha, captcha
|
6 |
Requires at least: 3.1
|
7 |
+
Tested up to: 3.9
|
8 |
+
Stable tag: 2.6.2
|
9 |
|
10 |
Add some useful fields to registration and user's info
|
11 |
|
securimage/README.txt
CHANGED
@@ -2,7 +2,9 @@ NAME:
|
|
2 |
|
3 |
Securimage - A PHP class for creating captcha images and audio with many options.
|
4 |
|
5 |
-
VERSION:
|
|
|
|
|
6 |
|
7 |
AUTHOR:
|
8 |
|
@@ -19,6 +21,7 @@ DOCUMENTATION:
|
|
19 |
be found at http://www.phpcaptcha.org/Securimage_Docs/
|
20 |
|
21 |
REQUIREMENTS:
|
|
|
22 |
PHP 5.2 or greater
|
23 |
GD 2.0
|
24 |
FreeType (Required, for TTF fonts)
|
@@ -27,15 +30,24 @@ REQUIREMENTS:
|
|
27 |
SYNOPSIS:
|
28 |
|
29 |
require_once 'securimage.php';
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
|
35 |
// Code Validation
|
36 |
|
37 |
$image = new Securimage();
|
38 |
-
if ($image->check($_POST['
|
39 |
echo "Correct!";
|
40 |
} else {
|
41 |
echo "Sorry, wrong code.";
|
@@ -45,19 +57,26 @@ DESCRIPTION:
|
|
45 |
|
46 |
What is Securimage?
|
47 |
|
48 |
-
Securimage is a PHP class that is used to generate and validate CAPTCHA
|
49 |
-
|
50 |
-
|
51 |
-
The
|
52 |
-
|
53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
|
55 |
COPYRIGHT:
|
56 |
-
|
|
|
57 |
All rights reserved.
|
58 |
|
59 |
-
Redistribution and use in source and binary forms, with or without
|
60 |
-
are permitted provided that the following conditions are met:
|
61 |
|
62 |
- Redistributions of source code must retain the above copyright notice,
|
63 |
this list of conditions and the following disclaimer.
|
@@ -77,17 +96,18 @@ COPYRIGHT:
|
|
77 |
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
78 |
POSSIBILITY OF SUCH DAMAGE.
|
79 |
|
80 |
-
|
81 |
-
|
82 |
-
used
|
|
|
83 |
Many thanks to Paul Voegler (http://www.voegler.eu/) for contributing to
|
84 |
Securimage.
|
85 |
|
86 |
-
|
87 |
-
Flash code created
|
88 |
Many thanks for releasing this to the project!
|
89 |
|
90 |
-
|
91 |
Portions of Securimage contain code from Han-Kwang Nienhuys' PHP captcha
|
92 |
|
93 |
Han-Kwang Nienhuys' PHP captcha
|
@@ -99,10 +119,12 @@ COPYRIGHT:
|
|
99 |
The original, unrestricted version can be obtained from
|
100 |
http://www.lagom.nl/linux/hkcaptcha/
|
101 |
|
102 |
-
|
103 |
-
AHGBold.ttf (AlteHaasGroteskBold.ttf) font was created by Yann Le Coroller
|
|
|
104 |
|
105 |
-
Alte Haas Grotesk is a typeface that look like an helvetica printed in an
|
|
|
106 |
|
107 |
These fonts are freeware and can be distributed as long as they are
|
108 |
together with this text file.
|
@@ -113,13 +135,15 @@ COPYRIGHT:
|
|
113 |
www.yannlecoroller.com
|
114 |
yann@lecoroller.com
|
115 |
|
116 |
-
|
117 |
-
Portions of securimage_play.swf use the PopForge flash library for
|
|
|
118 |
|
119 |
/**
|
120 |
* Copyright(C) 2007 Andre Michelle and Joa Ebert
|
121 |
*
|
122 |
-
* PopForge is an ActionScript3 code sandbox developed by Andre Michelle
|
|
|
123 |
* http://sandbox.popforge.de
|
124 |
*
|
125 |
* PopforgeAS3Audio is free software; you can redistribute it and/or modify
|
@@ -136,14 +160,14 @@ COPYRIGHT:
|
|
136 |
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
137 |
*/
|
138 |
|
139 |
-
|
140 |
Some graphics used are from the Humility Icon Pack by WorLord
|
141 |
|
142 |
License: GNU/GPL (http://findicons.com/pack/1723/humility)
|
143 |
http://findicons.com/icon/192558/gnome_volume_control
|
144 |
http://findicons.com/icon/192562/gtk_refresh
|
145 |
|
146 |
-
|
147 |
Background noise sound files are from SoundJay.com
|
148 |
http://www.soundjay.com/tos.html
|
149 |
|
@@ -178,4 +202,3 @@ COPYRIGHT:
|
|
178 |
If you use the sound effects, please consider giving us a credit and
|
179 |
linking back to us but it's not required.
|
180 |
|
181 |
-
|
2 |
|
3 |
Securimage - A PHP class for creating captcha images and audio with many options.
|
4 |
|
5 |
+
VERSION:
|
6 |
+
|
7 |
+
3.5.2
|
8 |
|
9 |
AUTHOR:
|
10 |
|
21 |
be found at http://www.phpcaptcha.org/Securimage_Docs/
|
22 |
|
23 |
REQUIREMENTS:
|
24 |
+
|
25 |
PHP 5.2 or greater
|
26 |
GD 2.0
|
27 |
FreeType (Required, for TTF fonts)
|
30 |
SYNOPSIS:
|
31 |
|
32 |
require_once 'securimage.php';
|
33 |
+
|
34 |
+
**Within your HTML form**
|
35 |
+
|
36 |
+
<form metod="post" action="">
|
37 |
+
.. form elements
|
38 |
+
|
39 |
+
<div>
|
40 |
+
<?php echo Securimage::getCaptchaHtml() ?>
|
41 |
+
</div>
|
42 |
+
</form>
|
43 |
+
|
44 |
+
|
45 |
+
**Within your PHP form processor**
|
46 |
|
47 |
// Code Validation
|
48 |
|
49 |
$image = new Securimage();
|
50 |
+
if ($image->check($_POST['captcha_code']) == true) {
|
51 |
echo "Correct!";
|
52 |
} else {
|
53 |
echo "Sorry, wrong code.";
|
57 |
|
58 |
What is Securimage?
|
59 |
|
60 |
+
Securimage is a PHP class that is used to generate and validate CAPTCHA
|
61 |
+
images.
|
62 |
+
|
63 |
+
The classes uses an existing PHP session or creates its own if
|
64 |
+
none is found to store the CAPTCHA code. In addition, a database can be
|
65 |
+
used instead of session storage.
|
66 |
+
|
67 |
+
Variables within the class are used to control the style and display of
|
68 |
+
the image. The class uses TTF fonts and effects for strengthening the
|
69 |
+
security of the image.
|
70 |
+
|
71 |
+
It also creates audible codes which are played for visually impared users.
|
72 |
|
73 |
COPYRIGHT:
|
74 |
+
|
75 |
+
Copyright (c) 2014 Drew Phillips
|
76 |
All rights reserved.
|
77 |
|
78 |
+
Redistribution and use in source and binary forms, with or without
|
79 |
+
modification, are permitted provided that the following conditions are met:
|
80 |
|
81 |
- Redistributions of source code must retain the above copyright notice,
|
82 |
this list of conditions and the following disclaimer.
|
96 |
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
97 |
POSSIBILITY OF SUCH DAMAGE.
|
98 |
|
99 |
+
LICENSES:
|
100 |
+
|
101 |
+
The WavFile.php class used in Securimage by Drew Phillips and Paul Voegler
|
102 |
+
is used under the BSD License. See WavFile.php for details.
|
103 |
Many thanks to Paul Voegler (http://www.voegler.eu/) for contributing to
|
104 |
Securimage.
|
105 |
|
106 |
+
---------------------------------------------------------------------------
|
107 |
+
Flash code created by Age Bosma & Mario Romero (animario@hotmail.com)
|
108 |
Many thanks for releasing this to the project!
|
109 |
|
110 |
+
---------------------------------------------------------------------------
|
111 |
Portions of Securimage contain code from Han-Kwang Nienhuys' PHP captcha
|
112 |
|
113 |
Han-Kwang Nienhuys' PHP captcha
|
119 |
The original, unrestricted version can be obtained from
|
120 |
http://www.lagom.nl/linux/hkcaptcha/
|
121 |
|
122 |
+
---------------------------------------------------------------------------
|
123 |
+
AHGBold.ttf (AlteHaasGroteskBold.ttf) font was created by Yann Le Coroller
|
124 |
+
and is distributed as freeware.
|
125 |
|
126 |
+
Alte Haas Grotesk is a typeface that look like an helvetica printed in an
|
127 |
+
old Muller-Brockmann Book.
|
128 |
|
129 |
These fonts are freeware and can be distributed as long as they are
|
130 |
together with this text file.
|
135 |
www.yannlecoroller.com
|
136 |
yann@lecoroller.com
|
137 |
|
138 |
+
---------------------------------------------------------------------------
|
139 |
+
Portions of securimage_play.swf use the PopForge flash library for
|
140 |
+
playing audio
|
141 |
|
142 |
/**
|
143 |
* Copyright(C) 2007 Andre Michelle and Joa Ebert
|
144 |
*
|
145 |
+
* PopForge is an ActionScript3 code sandbox developed by Andre Michelle
|
146 |
+
* and Joa Ebert
|
147 |
* http://sandbox.popforge.de
|
148 |
*
|
149 |
* PopforgeAS3Audio is free software; you can redistribute it and/or modify
|
160 |
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
161 |
*/
|
162 |
|
163 |
+
--------------------------------------------------------------------------
|
164 |
Some graphics used are from the Humility Icon Pack by WorLord
|
165 |
|
166 |
License: GNU/GPL (http://findicons.com/pack/1723/humility)
|
167 |
http://findicons.com/icon/192558/gnome_volume_control
|
168 |
http://findicons.com/icon/192562/gtk_refresh
|
169 |
|
170 |
+
--------------------------------------------------------------------------
|
171 |
Background noise sound files are from SoundJay.com
|
172 |
http://www.soundjay.com/tos.html
|
173 |
|
202 |
If you use the sound effects, please consider giving us a credit and
|
203 |
linking back to us but it's not required.
|
204 |
|
|
securimage/WavFile.php
CHANGED
@@ -6,7 +6,7 @@
|
|
6 |
* Project: PHPWavUtils: Classes for creating, reading, and manipulating WAV files in PHP<br />
|
7 |
* File: WavFile.php<br />
|
8 |
*
|
9 |
-
* Copyright (c) 2012, Drew Phillips
|
10 |
* All rights reserved.
|
11 |
*
|
12 |
* Redistribution and use in source and binary forms, with or without modification,
|
@@ -36,12 +36,18 @@
|
|
36 |
* @copyright 2012 Drew Phillips
|
37 |
* @author Drew Phillips <drew@drew-phillips.com>
|
38 |
* @author Paul Voegler <http://www.voegler.eu/>
|
39 |
-
* @version 1.
|
40 |
* @package PHPWavUtils
|
41 |
* @license BSD License
|
42 |
*
|
43 |
* Changelog:
|
44 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
* 1.0 (10/2/2012)
|
46 |
* - Fix insertSilence() creating invalid block size
|
47 |
*
|
@@ -80,6 +86,9 @@ class WavFile
|
|
80 |
/** @var int Filter flag for degrading audio data */
|
81 |
const FILTER_DEGRADE = 0x04;
|
82 |
|
|
|
|
|
|
|
83 |
/** @var int Maximum number of channels */
|
84 |
const MAX_CHANNEL = 18;
|
85 |
|
@@ -194,6 +203,9 @@ class WavFile
|
|
194 |
/** @var int Bytes per second */
|
195 |
protected $_byteRate;
|
196 |
|
|
|
|
|
|
|
197 |
/** @var string Binary string of samples */
|
198 |
protected $_samples;
|
199 |
|
@@ -239,6 +251,7 @@ class WavFile
|
|
239 |
$this->_blockAlign = 1;
|
240 |
$this->_numBlocks = 0;
|
241 |
$this->_byteRate = 8000;
|
|
|
242 |
$this->_samples = '';
|
243 |
$this->_fp = null;
|
244 |
|
@@ -774,6 +787,17 @@ class WavFile
|
|
774 |
return $this;
|
775 |
}
|
776 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
777 |
public function getSamples() {
|
778 |
return $this->_samples;
|
779 |
}
|
@@ -832,7 +856,7 @@ class WavFile
|
|
832 |
// Wave file methods
|
833 |
|
834 |
/**
|
835 |
-
* Construct a wav header from this object. Includes "fact" chunk
|
836 |
* http://www-mmsp.ece.mcgill.ca/documents/audioformats/wave/wave.html
|
837 |
*
|
838 |
* @return string The RIFF header data.
|
@@ -1046,10 +1070,11 @@ class WavFile
|
|
1046 |
throw new WavFormatException('Not wav format. "RIFF" signature missing.', 2);
|
1047 |
}
|
1048 |
|
1049 |
-
if ($
|
|
|
|
|
1050 |
trigger_error('"RIFF" chunk size does not match actual file size. Found ' . $RIFF['ChunkSize'] . ', expected ' . ($actualSize - 8) . '.', E_USER_NOTICE);
|
1051 |
$RIFF['ChunkSize'] = $actualSize - 8;
|
1052 |
-
//throw new WavFormatException('"RIFF" chunk size does not match actual file size. Found ' . $RIFF['ChunkSize'] . ', expected ' . ($actualSize - 8) . '.', 3);
|
1053 |
}
|
1054 |
|
1055 |
if ($RIFF['Format'] != 0x57415645) { // "WAVE"
|
@@ -1098,14 +1123,12 @@ class WavFile
|
|
1098 |
if ($blockAlign != $fmt['BlockAlign']) {
|
1099 |
trigger_error('Invalid block align in "fmt " subchunk. Found ' . $fmt['BlockAlign'] . ', expected ' . $blockAlign . '.', E_USER_NOTICE);
|
1100 |
$fmt['BlockAlign'] = $blockAlign;
|
1101 |
-
//throw new WavFormatException('Invalid block align in "fmt " subchunk. Found ' . $fmt['BlockAlign'] . ', expected ' . $blockAlign . '.', 17);
|
1102 |
}
|
1103 |
|
1104 |
$byteRate = $fmt['SampleRate'] * $blockAlign;
|
1105 |
if ($byteRate != $fmt['ByteRate']) {
|
1106 |
trigger_error('Invalid average byte rate in "fmt " subchunk. Found ' . $fmt['ByteRate'] . ', expected ' . $byteRate . '.', E_USER_NOTICE);
|
1107 |
$fmt['ByteRate'] = $byteRate;
|
1108 |
-
//throw new WavFormatException('Invalid average byte rate in "fmt " subchunk. Found ' . $fmt['ByteRate'] . ', expected ' . $byteRate . '.', 18);
|
1109 |
}
|
1110 |
|
1111 |
$this->_fmtChunkSize = $fmt['SubchunkSize'];
|
@@ -1151,13 +1174,11 @@ class WavFile
|
|
1151 |
if ($extensibleFmt['Size'] != 22) {
|
1152 |
trigger_error('Invaid extension size in EXTENSIBLE "fmt " subchunk.', E_USER_NOTICE);
|
1153 |
$extensibleFmt['Size'] = 22;
|
1154 |
-
//throw new WavFormatException('Invaid extension size in EXTENSIBLE "fmt " subchunk.', 20);
|
1155 |
}
|
1156 |
|
1157 |
if ($extensibleFmt['ValidBitsPerSample'] != $fmt['BitsPerSample']) {
|
1158 |
trigger_error('Invaid or unsupported valid bits per sample in EXTENSIBLE "fmt " subchunk.', E_USER_NOTICE);
|
1159 |
$extensibleFmt['ValidBitsPerSample'] = $fmt['BitsPerSample'];
|
1160 |
-
//throw new WavFormatException('Invaid or unsupported valid bits per sample in EXTENSIBLE "fmt " subchunk.', 21);
|
1161 |
}
|
1162 |
|
1163 |
if ($extensibleFmt['ChannelMask'] != 0) {
|
@@ -1171,7 +1192,6 @@ class WavFile
|
|
1171 |
if ($n != $fmt['NumChannels'] || (((int)$extensibleFmt['ChannelMask'] | self::SPEAKER_ALL) != self::SPEAKER_ALL)) {
|
1172 |
trigger_error('Invalid channel mask in EXTENSIBLE "fmt " subchunk. The number of channels does not match the number of locations in the mask.', E_USER_NOTICE);
|
1173 |
$extensibleFmt['ChannelMask'] = 0;
|
1174 |
-
//throw new WavFormatException('Invalid channel mask in EXTENSIBLE "fmt " subchunk. The number of channels does not match the number of locations in the mask.', 22);
|
1175 |
}
|
1176 |
}
|
1177 |
|
@@ -1234,10 +1254,11 @@ class WavFile
|
|
1234 |
|
1235 |
// check "data" subchunk
|
1236 |
$dataOffset = ftell($this->_fp);
|
1237 |
-
if ($
|
1238 |
-
|
|
|
|
|
1239 |
$dataSubchunk['SubchunkSize'] = $actualSize - $dataOffset;
|
1240 |
-
//throw new WavFormatException('Invalid "data" subchunk size.', 104);
|
1241 |
}
|
1242 |
|
1243 |
$this->_dataOffset = $dataOffset;
|
@@ -1257,7 +1278,6 @@ class WavFile
|
|
1257 |
if ($factSubchunk['SampleLength'] != $numBlocks) {
|
1258 |
trigger_error('Invalid sample length in "fact" subchunk.', E_USER_NOTICE);
|
1259 |
$factSubchunk['SampleLength'] = $numBlocks;
|
1260 |
-
//throw new WavFormatException('Invalid sample length in "fact" subchunk.', 105);
|
1261 |
}
|
1262 |
|
1263 |
$this->_factChunkSize = $factSubchunk['SubchunkSize'];
|
@@ -1557,6 +1577,7 @@ class WavFile
|
|
1557 |
* ),
|
1558 |
* WavFile::FILTER_NORMALIZE => 0.6, // (Required) Normalization of (mixed) audio samples - see threshold parameter for normalizeSample().
|
1559 |
* WavFile::FILTER_DEGRADE => 0.9 // (Required) Introduce random noise. The quality relative to the amplitude. 1 = no noise, 0 = max. noise.
|
|
|
1560 |
* ),
|
1561 |
* 0, // (Optional) The block number of this WavFile to start with.
|
1562 |
* null // (Optional) The number of blocks to process.
|
@@ -1626,6 +1647,16 @@ class WavFile
|
|
1626 |
if ($degrade_quality >= 0 && $degrade_quality < 1) $filter_degrade = true;
|
1627 |
}
|
1628 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1629 |
|
1630 |
// loop through all sample blocks
|
1631 |
for ($block = 0; $block < $numBlocks; ++$block) {
|
@@ -1659,6 +1690,10 @@ class WavFile
|
|
1659 |
$sampleFloat += rand(1000000 * ($degrade_quality - 1), 1000000 * (1 - $degrade_quality)) / 1000000;
|
1660 |
}
|
1661 |
|
|
|
|
|
|
|
|
|
1662 |
|
1663 |
// write current sample
|
1664 |
$this->setSampleValue($sampleFloat, $currentBlock, $channel);
|
6 |
* Project: PHPWavUtils: Classes for creating, reading, and manipulating WAV files in PHP<br />
|
7 |
* File: WavFile.php<br />
|
8 |
*
|
9 |
+
* Copyright (c) 2012 - 2014, Drew Phillips
|
10 |
* All rights reserved.
|
11 |
*
|
12 |
* Redistribution and use in source and binary forms, with or without modification,
|
36 |
* @copyright 2012 Drew Phillips
|
37 |
* @author Drew Phillips <drew@drew-phillips.com>
|
38 |
* @author Paul Voegler <http://www.voegler.eu/>
|
39 |
+
* @version 1.1 (Feb 2014)
|
40 |
* @package PHPWavUtils
|
41 |
* @license BSD License
|
42 |
*
|
43 |
* Changelog:
|
44 |
+
*
|
45 |
+
* 1.1 (02/8/2014)
|
46 |
+
* - Add method setIgnoreChunkSizes() to allow reading of wav data with bogus chunk sizes set.
|
47 |
+
* This allows streamed wav data to be processed where the chunk sizes were not known when
|
48 |
+
* writing the header. Instead calculates the chunk sizes automatically.
|
49 |
+
* - Add simple volume filter to attenuate or amplify the audio signal.
|
50 |
+
*
|
51 |
* 1.0 (10/2/2012)
|
52 |
* - Fix insertSilence() creating invalid block size
|
53 |
*
|
86 |
/** @var int Filter flag for degrading audio data */
|
87 |
const FILTER_DEGRADE = 0x04;
|
88 |
|
89 |
+
/** @var int Filter flag for amplifying or attenuating audio data. */
|
90 |
+
const FILTER_VOLUME = 0x08;
|
91 |
+
|
92 |
/** @var int Maximum number of channels */
|
93 |
const MAX_CHANNEL = 18;
|
94 |
|
203 |
/** @var int Bytes per second */
|
204 |
protected $_byteRate;
|
205 |
|
206 |
+
/** @var bool Ignore chunk sizes when reading wav data (useful when reading data from a stream where chunk sizes contain dummy values) */
|
207 |
+
protected $_ignoreChunkSizes;
|
208 |
+
|
209 |
/** @var string Binary string of samples */
|
210 |
protected $_samples;
|
211 |
|
251 |
$this->_blockAlign = 1;
|
252 |
$this->_numBlocks = 0;
|
253 |
$this->_byteRate = 8000;
|
254 |
+
$this->_ignoreChunkSizes = false;
|
255 |
$this->_samples = '';
|
256 |
$this->_fp = null;
|
257 |
|
787 |
return $this;
|
788 |
}
|
789 |
|
790 |
+
public function getIgnoreChunkSizes()
|
791 |
+
{
|
792 |
+
return $this->_ignoreChunkSizes;
|
793 |
+
}
|
794 |
+
|
795 |
+
public function setIgnoreChunkSizes($ignoreChunkSizes)
|
796 |
+
{
|
797 |
+
$this->_ignoreChunkSizes = (bool)$ignoreChunkSizes;
|
798 |
+
return $this;
|
799 |
+
}
|
800 |
+
|
801 |
public function getSamples() {
|
802 |
return $this->_samples;
|
803 |
}
|
856 |
// Wave file methods
|
857 |
|
858 |
/**
|
859 |
+
* Construct a wav header from this object. Includes "fact" chunk if necessary.
|
860 |
* http://www-mmsp.ece.mcgill.ca/documents/audioformats/wave/wave.html
|
861 |
*
|
862 |
* @return string The RIFF header data.
|
1070 |
throw new WavFormatException('Not wav format. "RIFF" signature missing.', 2);
|
1071 |
}
|
1072 |
|
1073 |
+
if ($this->getIgnoreChunkSizes()) {
|
1074 |
+
$RIFF['ChunkSize'] = $actualSize - 8;
|
1075 |
+
} else if ($actualSize - 8 < $RIFF['ChunkSize']) {
|
1076 |
trigger_error('"RIFF" chunk size does not match actual file size. Found ' . $RIFF['ChunkSize'] . ', expected ' . ($actualSize - 8) . '.', E_USER_NOTICE);
|
1077 |
$RIFF['ChunkSize'] = $actualSize - 8;
|
|
|
1078 |
}
|
1079 |
|
1080 |
if ($RIFF['Format'] != 0x57415645) { // "WAVE"
|
1123 |
if ($blockAlign != $fmt['BlockAlign']) {
|
1124 |
trigger_error('Invalid block align in "fmt " subchunk. Found ' . $fmt['BlockAlign'] . ', expected ' . $blockAlign . '.', E_USER_NOTICE);
|
1125 |
$fmt['BlockAlign'] = $blockAlign;
|
|
|
1126 |
}
|
1127 |
|
1128 |
$byteRate = $fmt['SampleRate'] * $blockAlign;
|
1129 |
if ($byteRate != $fmt['ByteRate']) {
|
1130 |
trigger_error('Invalid average byte rate in "fmt " subchunk. Found ' . $fmt['ByteRate'] . ', expected ' . $byteRate . '.', E_USER_NOTICE);
|
1131 |
$fmt['ByteRate'] = $byteRate;
|
|
|
1132 |
}
|
1133 |
|
1134 |
$this->_fmtChunkSize = $fmt['SubchunkSize'];
|
1174 |
if ($extensibleFmt['Size'] != 22) {
|
1175 |
trigger_error('Invaid extension size in EXTENSIBLE "fmt " subchunk.', E_USER_NOTICE);
|
1176 |
$extensibleFmt['Size'] = 22;
|
|
|
1177 |
}
|
1178 |
|
1179 |
if ($extensibleFmt['ValidBitsPerSample'] != $fmt['BitsPerSample']) {
|
1180 |
trigger_error('Invaid or unsupported valid bits per sample in EXTENSIBLE "fmt " subchunk.', E_USER_NOTICE);
|
1181 |
$extensibleFmt['ValidBitsPerSample'] = $fmt['BitsPerSample'];
|
|
|
1182 |
}
|
1183 |
|
1184 |
if ($extensibleFmt['ChannelMask'] != 0) {
|
1192 |
if ($n != $fmt['NumChannels'] || (((int)$extensibleFmt['ChannelMask'] | self::SPEAKER_ALL) != self::SPEAKER_ALL)) {
|
1193 |
trigger_error('Invalid channel mask in EXTENSIBLE "fmt " subchunk. The number of channels does not match the number of locations in the mask.', E_USER_NOTICE);
|
1194 |
$extensibleFmt['ChannelMask'] = 0;
|
|
|
1195 |
}
|
1196 |
}
|
1197 |
|
1254 |
|
1255 |
// check "data" subchunk
|
1256 |
$dataOffset = ftell($this->_fp);
|
1257 |
+
if ($this->getIgnoreChunkSizes()) {
|
1258 |
+
$dataSubchunk['SubchunkSize'] = $actualSize - $dataOffset;
|
1259 |
+
} elseif ($dataSubchunk['SubchunkSize'] < 0 || $actualSize - $dataOffset < $dataSubchunk['SubchunkSize']) {
|
1260 |
+
trigger_error("Invalid \"data\" subchunk size (found {$dataSubchunk['SubchunkSize']}.", E_USER_NOTICE);
|
1261 |
$dataSubchunk['SubchunkSize'] = $actualSize - $dataOffset;
|
|
|
1262 |
}
|
1263 |
|
1264 |
$this->_dataOffset = $dataOffset;
|
1278 |
if ($factSubchunk['SampleLength'] != $numBlocks) {
|
1279 |
trigger_error('Invalid sample length in "fact" subchunk.', E_USER_NOTICE);
|
1280 |
$factSubchunk['SampleLength'] = $numBlocks;
|
|
|
1281 |
}
|
1282 |
|
1283 |
$this->_factChunkSize = $factSubchunk['SubchunkSize'];
|
1577 |
* ),
|
1578 |
* WavFile::FILTER_NORMALIZE => 0.6, // (Required) Normalization of (mixed) audio samples - see threshold parameter for normalizeSample().
|
1579 |
* WavFile::FILTER_DEGRADE => 0.9 // (Required) Introduce random noise. The quality relative to the amplitude. 1 = no noise, 0 = max. noise.
|
1580 |
+
* WavFile::FILTER_VOLUME => 1.0 // (Required) Amplify or attenuate the audio signal. Beware of clipping when amplifying. Values range from >= 0 - <= 2. 1 = no change in volume; 0.5 = 50% reduction of volume; 1.5 = 150% increase in volume.
|
1581 |
* ),
|
1582 |
* 0, // (Optional) The block number of this WavFile to start with.
|
1583 |
* null // (Optional) The number of blocks to process.
|
1647 |
if ($degrade_quality >= 0 && $degrade_quality < 1) $filter_degrade = true;
|
1648 |
}
|
1649 |
|
1650 |
+
$filter_vol = false;
|
1651 |
+
if (array_key_exists(self::FILTER_VOLUME, $filters)) {
|
1652 |
+
$volume_amount = @$filters[self::FILTER_VOLUME];
|
1653 |
+
if (is_null($volume_amount)) $volume_amount = 1;
|
1654 |
+
|
1655 |
+
if ($volume_amount >= 0 && $volume_amount <= 2 && $volume_amount != 1.0) {
|
1656 |
+
$filter_vol = true;
|
1657 |
+
}
|
1658 |
+
}
|
1659 |
+
|
1660 |
|
1661 |
// loop through all sample blocks
|
1662 |
for ($block = 0; $block < $numBlocks; ++$block) {
|
1690 |
$sampleFloat += rand(1000000 * ($degrade_quality - 1), 1000000 * (1 - $degrade_quality)) / 1000000;
|
1691 |
}
|
1692 |
|
1693 |
+
/************* VOLUME FILTER *******************/
|
1694 |
+
if ($filter_vol) {
|
1695 |
+
$sampleFloat *= $volume_amount;
|
1696 |
+
}
|
1697 |
|
1698 |
// write current sample
|
1699 |
$this->setSampleValue($sampleFloat, $currentBlock, $channel);
|
securimage/audio/.htaccess
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
deny from all
|
securimage/audio/en/0.wav
CHANGED
Binary file
|
securimage/audio/en/1.wav
CHANGED
Binary file
|
securimage/audio/en/10.wav
CHANGED
Binary file
|
securimage/audio/en/11.wav
CHANGED
Binary file
|
securimage/audio/en/12.wav
CHANGED
Binary file
|
securimage/audio/en/13.wav
CHANGED
Binary file
|
securimage/audio/en/14.wav
CHANGED
Binary file
|
securimage/audio/en/15.wav
CHANGED
Binary file
|
securimage/audio/en/16.wav
CHANGED
Binary file
|
securimage/audio/en/17.wav
CHANGED
Binary file
|
securimage/audio/en/18.wav
CHANGED
Binary file
|
securimage/audio/en/19.wav
CHANGED
Binary file
|
securimage/audio/en/2.wav
CHANGED
Binary file
|
securimage/audio/en/20.wav
CHANGED
Binary file
|
securimage/audio/en/3.wav
CHANGED
Binary file
|
securimage/audio/en/4.wav
CHANGED
Binary file
|
securimage/audio/en/5.wav
CHANGED
Binary file
|
securimage/audio/en/6.wav
CHANGED
Binary file
|
securimage/audio/en/7.wav
CHANGED
Binary file
|
securimage/audio/en/8.wav
CHANGED
Binary file
|
securimage/audio/en/9.wav
CHANGED
Binary file
|
securimage/audio/en/A.wav
CHANGED
Binary file
|
securimage/audio/en/B.wav
CHANGED
Binary file
|
securimage/audio/en/C.wav
CHANGED
Binary file
|
securimage/audio/en/D.wav
CHANGED
Binary file
|
securimage/audio/en/E.wav
CHANGED
Binary file
|
securimage/audio/en/F.wav
CHANGED
Binary file
|
securimage/audio/en/G.wav
CHANGED
Binary file
|
securimage/audio/en/H.wav
CHANGED
Binary file
|
securimage/audio/en/I.wav
CHANGED
Binary file
|
securimage/audio/en/J.wav
CHANGED
Binary file
|
securimage/audio/en/K.wav
CHANGED
Binary file
|
securimage/audio/en/L.wav
CHANGED
Binary file
|
securimage/audio/en/M.wav
CHANGED
Binary file
|
securimage/audio/en/N.wav
CHANGED
Binary file
|
securimage/audio/en/O.wav
CHANGED
Binary file
|
securimage/audio/en/P.wav
CHANGED
Binary file
|
securimage/audio/en/Q.wav
CHANGED
Binary file
|
securimage/audio/en/R.wav
CHANGED
Binary file
|
securimage/audio/en/S.wav
CHANGED
Binary file
|
securimage/audio/en/T.wav
CHANGED
Binary file
|
securimage/audio/en/U.wav
CHANGED
Binary file
|
securimage/audio/en/V.wav
CHANGED
Binary file
|
securimage/audio/en/W.wav
CHANGED
Binary file
|
securimage/audio/en/X.wav
CHANGED
Binary file
|
securimage/audio/en/Y.wav
CHANGED
Binary file
|
securimage/audio/en/Z.wav
CHANGED
Binary file
|
securimage/example_form.ajax.php
CHANGED
@@ -87,7 +87,7 @@ process_si_contact_form();
|
|
87 |
|
88 |
function reloadCaptcha()
|
89 |
{
|
90 |
-
jQuery('#siimage').src
|
91 |
}
|
92 |
|
93 |
function processForm()
|
@@ -102,7 +102,7 @@ process_si_contact_form();
|
|
102 |
jQuery('#success_message').show();
|
103 |
jQuery('#contact_form')[0].reset();
|
104 |
reloadCaptcha();
|
105 |
-
setTimeout("jQuery('#success_message').fadeOut()",
|
106 |
} else {
|
107 |
alert("There was an error with your submission.\n\n" + data.message);
|
108 |
}
|
87 |
|
88 |
function reloadCaptcha()
|
89 |
{
|
90 |
+
jQuery('#siimage').prop('src', './securimage_show.php?sid=' + Math.random());
|
91 |
}
|
92 |
|
93 |
function processForm()
|
102 |
jQuery('#success_message').show();
|
103 |
jQuery('#contact_form')[0].reset();
|
104 |
reloadCaptcha();
|
105 |
+
setTimeout("jQuery('#success_message').fadeOut()", 12000);
|
106 |
} else {
|
107 |
alert("There was an error with your submission.\n\n" + data.message);
|
108 |
}
|
securimage/example_form.php
CHANGED
@@ -5,7 +5,7 @@ $GLOBALS['DEBUG_MODE'] = 1;
|
|
5 |
// CHANGE TO 0 TO TURN OFF DEBUG MODE
|
6 |
// IN DEBUG MODE, ONLY THE CAPTCHA CODE IS VALIDATED, AND NO EMAIL IS SENT
|
7 |
|
8 |
-
$GLOBALS['ct_recipient'] = 'YOU@EXAMPLE.COM'; // Change to your email address!
|
9 |
$GLOBALS['ct_msg_subject'] = 'Securimage Test Contact Form';
|
10 |
|
11 |
?>
|
@@ -16,8 +16,10 @@ $GLOBALS['ct_msg_subject'] = 'Securimage Test Contact Form';
|
|
16 |
<title>Securimage Example Form</title>
|
17 |
<style type="text/css">
|
18 |
<!--
|
19 |
-
.error { color: #f00; font-weight: bold; font-size: 1.2em; }
|
|
|
20 |
.success { color: #00f; font-weight: bold; font-size: 1.2em; }
|
|
|
21 |
fieldset { width: 90%; }
|
22 |
legend { font-size: 24px; }
|
23 |
.note { font-size: 18px;
|
@@ -39,44 +41,52 @@ $GLOBALS['ct_msg_subject'] = 'Securimage Test Contact Form';
|
|
39 |
process_si_contact_form(); // Process the form, if it was submitted
|
40 |
|
41 |
if (isset($_SESSION['ctform']['error']) && $_SESSION['ctform']['error'] == true): /* The last form submission had 1 or more errors */ ?>
|
42 |
-
<
|
43 |
<?php elseif (isset($_SESSION['ctform']['success']) && $_SESSION['ctform']['success'] == true): /* form was processed successfully */ ?>
|
44 |
-
<
|
45 |
<?php endif; ?>
|
46 |
|
47 |
<form method="post" action="<?php echo htmlspecialchars($_SERVER['REQUEST_URI'] . $_SERVER['QUERY_STRING']) ?>" id="contact_form">
|
48 |
<input type="hidden" name="do" value="contact" />
|
49 |
|
50 |
<p>
|
51 |
-
<
|
|
|
52 |
<input type="text" name="ct_name" size="35" value="<?php echo htmlspecialchars(@$_SESSION['ctform']['ct_name']) ?>" />
|
53 |
</p>
|
54 |
|
55 |
<p>
|
56 |
-
<
|
|
|
57 |
<input type="text" name="ct_email" size="35" value="<?php echo htmlspecialchars(@$_SESSION['ctform']['ct_email']) ?>" />
|
58 |
</p>
|
59 |
|
60 |
<p>
|
61 |
-
<
|
|
|
62 |
<input type="text" name="ct_URL" size="35" value="<?php echo htmlspecialchars(@$_SESSION['ctform']['ct_URL']) ?>" />
|
63 |
</p>
|
64 |
|
65 |
<p>
|
66 |
-
<
|
|
|
67 |
<textarea name="ct_message" rows="12" cols="60"><?php echo htmlspecialchars(@$_SESSION['ctform']['ct_message']) ?></textarea>
|
68 |
</p>
|
69 |
|
70 |
<p>
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
|
|
|
|
|
|
|
|
80 |
</p>
|
81 |
|
82 |
<p>
|
@@ -135,7 +145,7 @@ function process_si_contact_form()
|
|
135 |
|
136 |
if (strlen($message) < 20) {
|
137 |
// message length too short
|
138 |
-
$errors['message_error'] = '
|
139 |
}
|
140 |
}
|
141 |
|
@@ -154,22 +164,23 @@ function process_si_contact_form()
|
|
154 |
// no errors, send the form
|
155 |
$time = date('r');
|
156 |
$message = "A message was submitted from the contact form. The following information was provided.<br /><br />"
|
157 |
-
. "Name: $name
|
158 |
-
. "Email: $email
|
159 |
-
. "URL: $URL
|
160 |
-
. "Message
|
161 |
. "<pre>$message</pre>"
|
162 |
-
. "<br /><br
|
163 |
-
. "Time
|
164 |
-
. "Browser
|
165 |
|
166 |
$message = wordwrap($message, 70);
|
167 |
|
168 |
if (isset($GLOBALS['DEBUG_MODE']) && $GLOBALS['DEBUG_MODE'] == false) {
|
169 |
// send the message with mail()
|
170 |
-
mail($GLOBALS['ct_recipient'], $GLOBALS['ct_msg_subject'], $message, "From: {$GLOBALS['ct_recipient']}\r\nReply-To: {$email}\r\nContent-type: text/html; charset=
|
171 |
}
|
172 |
|
|
|
173 |
$_SESSION['ctform']['error'] = false; // no error with form
|
174 |
$_SESSION['ctform']['success'] = true; // message sent
|
175 |
} else {
|
@@ -181,7 +192,7 @@ function process_si_contact_form()
|
|
181 |
|
182 |
foreach($errors as $key => $error) {
|
183 |
// set up error messages to display with each field
|
184 |
-
$_SESSION['ctform'][$key] = "<span
|
185 |
}
|
186 |
|
187 |
$_SESSION['ctform']['error'] = true; // set error floag
|
5 |
// CHANGE TO 0 TO TURN OFF DEBUG MODE
|
6 |
// IN DEBUG MODE, ONLY THE CAPTCHA CODE IS VALIDATED, AND NO EMAIL IS SENT
|
7 |
|
8 |
+
$GLOBALS['ct_recipient'] = 'YOU@EXAMPLE.COM'; // Change to your email address! Make sure DEBUG_MODE above is 0 for mail to send!
|
9 |
$GLOBALS['ct_msg_subject'] = 'Securimage Test Contact Form';
|
10 |
|
11 |
?>
|
16 |
<title>Securimage Example Form</title>
|
17 |
<style type="text/css">
|
18 |
<!--
|
19 |
+
div.error { display: block; color: #f00; font-weight: bold; font-size: 1.2em; }
|
20 |
+
span.error { display: block; color: #f00; font-style: italic; }
|
21 |
.success { color: #00f; font-weight: bold; font-size: 1.2em; }
|
22 |
+
form label { display: block; font-weight: bold; }
|
23 |
fieldset { width: 90%; }
|
24 |
legend { font-size: 24px; }
|
25 |
.note { font-size: 18px;
|
41 |
process_si_contact_form(); // Process the form, if it was submitted
|
42 |
|
43 |
if (isset($_SESSION['ctform']['error']) && $_SESSION['ctform']['error'] == true): /* The last form submission had 1 or more errors */ ?>
|
44 |
+
<div class="error">There was a problem with your submission. Errors are displayed below in red.</div><br />
|
45 |
<?php elseif (isset($_SESSION['ctform']['success']) && $_SESSION['ctform']['success'] == true): /* form was processed successfully */ ?>
|
46 |
+
<div class="success">The captcha was correct and the message has been sent! The captcha was solved in <?php echo $_SESSION['ctform']['timetosolve'] ?> seconds.</div><br />
|
47 |
<?php endif; ?>
|
48 |
|
49 |
<form method="post" action="<?php echo htmlspecialchars($_SERVER['REQUEST_URI'] . $_SERVER['QUERY_STRING']) ?>" id="contact_form">
|
50 |
<input type="hidden" name="do" value="contact" />
|
51 |
|
52 |
<p>
|
53 |
+
<label for="ct_name">Name*:</label>
|
54 |
+
<?php echo @$_SESSION['ctform']['name_error'] ?>
|
55 |
<input type="text" name="ct_name" size="35" value="<?php echo htmlspecialchars(@$_SESSION['ctform']['ct_name']) ?>" />
|
56 |
</p>
|
57 |
|
58 |
<p>
|
59 |
+
<label for="ct_email">Email*:</label>
|
60 |
+
<?php echo @$_SESSION['ctform']['email_error'] ?>
|
61 |
<input type="text" name="ct_email" size="35" value="<?php echo htmlspecialchars(@$_SESSION['ctform']['ct_email']) ?>" />
|
62 |
</p>
|
63 |
|
64 |
<p>
|
65 |
+
<label for="ct_URL">URL:</label>
|
66 |
+
<?php echo @$_SESSION['ctform']['URL_error'] ?>
|
67 |
<input type="text" name="ct_URL" size="35" value="<?php echo htmlspecialchars(@$_SESSION['ctform']['ct_URL']) ?>" />
|
68 |
</p>
|
69 |
|
70 |
<p>
|
71 |
+
<label for="ct_message">Message*:</label>
|
72 |
+
<?php echo @$_SESSION['ctform']['message_error'] ?>
|
73 |
<textarea name="ct_message" rows="12" cols="60"><?php echo htmlspecialchars(@$_SESSION['ctform']['ct_message']) ?></textarea>
|
74 |
</p>
|
75 |
|
76 |
<p>
|
77 |
+
<?php
|
78 |
+
// show captcha HTML using Securimage::getCaptchaHtml()
|
79 |
+
require_once 'securimage.php';
|
80 |
+
$options = array();
|
81 |
+
$options['input_name'] = 'ct_captcha'; // change name of input element for form post
|
82 |
+
|
83 |
+
if (!empty($_SESSION['ctform']['captcha_error'])) {
|
84 |
+
// error html to show in captcha output
|
85 |
+
$options['error_html'] = $_SESSION['ctform']['captcha_error'];
|
86 |
+
}
|
87 |
+
|
88 |
+
echo Securimage::getCaptchaHtml($options);
|
89 |
+
?>
|
90 |
</p>
|
91 |
|
92 |
<p>
|
145 |
|
146 |
if (strlen($message) < 20) {
|
147 |
// message length too short
|
148 |
+
$errors['message_error'] = 'Your message must be longer than 20 characters';
|
149 |
}
|
150 |
}
|
151 |
|
164 |
// no errors, send the form
|
165 |
$time = date('r');
|
166 |
$message = "A message was submitted from the contact form. The following information was provided.<br /><br />"
|
167 |
+
. "<em>Name: $name</em><br />"
|
168 |
+
. "<em>Email: $email</em><br />"
|
169 |
+
. "<em>URL: $URL</em><br />"
|
170 |
+
. "<em>Message:</em><br />"
|
171 |
. "<pre>$message</pre>"
|
172 |
+
. "<br /><br /><em>IP Address:</em> {$_SERVER['REMOTE_ADDR']}<br />"
|
173 |
+
. "<em>Time:</em> $time<br />"
|
174 |
+
. "<em>Browser:</em> {$_SERVER['HTTP_USER_AGENT']}<br />";
|
175 |
|
176 |
$message = wordwrap($message, 70);
|
177 |
|
178 |
if (isset($GLOBALS['DEBUG_MODE']) && $GLOBALS['DEBUG_MODE'] == false) {
|
179 |
// send the message with mail()
|
180 |
+
mail($GLOBALS['ct_recipient'], $GLOBALS['ct_msg_subject'], $message, "From: {$GLOBALS['ct_recipient']}\r\nReply-To: {$email}\r\nContent-type: text/html; charset=UTF-8\r\nMIME-Version: 1.0");
|
181 |
}
|
182 |
|
183 |
+
$_SESSION['ctform']['timetosolve'] = $securimage->getTimeToSolve();
|
184 |
$_SESSION['ctform']['error'] = false; // no error with form
|
185 |
$_SESSION['ctform']['success'] = true; // message sent
|
186 |
} else {
|
192 |
|
193 |
foreach($errors as $key => $error) {
|
194 |
// set up error messages to display with each field
|
195 |
+
$_SESSION['ctform'][$key] = "<span class=\"error\">$error</span>";
|
196 |
}
|
197 |
|
198 |
$_SESSION['ctform']['error'] = true; // set error floag
|
securimage/securimage.php
CHANGED
@@ -6,7 +6,7 @@
|
|
6 |
* Project: Securimage: A PHP class for creating and managing form CAPTCHA images<br />
|
7 |
* File: securimage.php<br />
|
8 |
*
|
9 |
-
* Copyright (c)
|
10 |
* All rights reserved.
|
11 |
*
|
12 |
* Redistribution and use in source and binary forms, with or without modification,
|
@@ -39,9 +39,9 @@
|
|
39 |
* @link http://www.phpcaptcha.org Securimage PHP CAPTCHA
|
40 |
* @link http://www.phpcaptcha.org/latest.zip Download Latest Version
|
41 |
* @link http://www.phpcaptcha.org/Securimage_Docs/ Online Documentation
|
42 |
-
* @copyright
|
43 |
* @author Drew Phillips <drew@drew-phillips.com>
|
44 |
-
* @version 3.5.
|
45 |
* @package Securimage
|
46 |
*
|
47 |
*/
|
@@ -49,6 +49,20 @@
|
|
49 |
/**
|
50 |
ChangeLog
|
51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
3.5.1
|
53 |
- Fix XSS vulnerability in example_form.php (discovered by Gjoko Krstic - <gjoko@zeroscience.mk>)
|
54 |
|
@@ -156,7 +170,7 @@
|
|
156 |
/**
|
157 |
* Securimage CAPTCHA Class.
|
158 |
*
|
159 |
-
* @version 3.5
|
160 |
* @package Securimage
|
161 |
* @subpackage classes
|
162 |
* @author Drew Phillips <drew@drew-phillips.com>
|
@@ -234,6 +248,16 @@ class Securimage
|
|
234 |
* @var int
|
235 |
*/
|
236 |
public $image_height = 80;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
237 |
/**
|
238 |
* The type of the image, default = png
|
239 |
* @var int
|
@@ -289,7 +313,7 @@ class Securimage
|
|
289 |
public $charset = 'ABCDEFGHKLMNPRSTUVWYZabcdefghklmnprstuvwyz23456789';
|
290 |
/**
|
291 |
* How long in seconds a captcha remains valid, after this time it will not be accepted
|
292 |
-
* @var
|
293 |
*/
|
294 |
public $expiry_time = 900;
|
295 |
|
@@ -357,6 +381,14 @@ class Securimage
|
|
357 |
*/
|
358 |
public $use_database = false;
|
359 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
360 |
/**
|
361 |
* Database driver to use for database support.
|
362 |
* Allowable values: 'mysql', 'pgsql', 'sqlite'.
|
@@ -470,6 +502,22 @@ class Securimage
|
|
470 |
* </code>
|
471 |
*/
|
472 |
public $audio_path;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
473 |
/**
|
474 |
* The path to the directory containing audio files that will be selected
|
475 |
* randomly and mixed with the captcha audio.
|
@@ -508,7 +556,7 @@ class Securimage
|
|
508 |
* @since 3.0.4
|
509 |
* @var float
|
510 |
*/
|
511 |
-
public $audio_mix_normalization = 0.
|
512 |
/**
|
513 |
* Whether or not to degrade audio by introducing random noise (improves security of audio captcha)
|
514 |
* Default: true
|
@@ -530,7 +578,7 @@ class Securimage
|
|
530 |
* @since 3.0.3
|
531 |
* @var float
|
532 |
*/
|
533 |
-
public $audio_gap_max =
|
534 |
|
535 |
/**
|
536 |
* Captcha ID if using static captcha
|
@@ -576,6 +624,13 @@ class Securimage
|
|
576 |
*/
|
577 |
protected $captcha_code;
|
578 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
579 |
/**
|
580 |
* Flag that can be specified telling securimage not to call exit after generating a captcha image or audio file
|
581 |
*
|
@@ -705,7 +760,7 @@ class Securimage
|
|
705 |
|
706 |
if ($this->no_session != true) {
|
707 |
// Initialize session or attach to existing
|
708 |
-
if ( session_id() == '' ) { // no session has been started yet, which is needed for validation
|
709 |
if (!is_null($this->session_name) && trim($this->session_name) != '') {
|
710 |
session_name(trim($this->session_name)); // set session name if provided
|
711 |
}
|
@@ -835,6 +890,162 @@ class Securimage
|
|
835 |
return $this->correct_code;
|
836 |
}
|
837 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
838 |
/**
|
839 |
* Output a wav file of the captcha code to the browser
|
840 |
*
|
@@ -853,13 +1064,13 @@ class Securimage
|
|
853 |
try {
|
854 |
$audio = $this->getAudibleCode();
|
855 |
} catch (Exception $ex) {
|
856 |
-
if (($fp = @fopen(dirname(__FILE__) . '/si.error_log', 'a+')) !== false) {
|
857 |
-
fwrite($fp, date('Y-m-d H:i:s') . ': Securimage audio error "' . $ex->getMessage() . '"' . "\n");
|
858 |
-
fclose($fp);
|
859 |
}
|
860 |
|
861 |
$audio = $this->audioError();
|
862 |
-
}
|
863 |
|
864 |
if ($this->canSendHeaders() || $this->send_headers == false) {
|
865 |
if ($this->send_headers) {
|
@@ -890,52 +1101,58 @@ class Securimage
|
|
890 |
if (!$this->no_exit) exit;
|
891 |
}
|
892 |
|
893 |
-
/**
|
894 |
-
* Return the code from the session or sqlite database if used. If none exists yet, an empty string is returned
|
895 |
-
*
|
896 |
-
* @param $array bool True to receive an array containing the code and properties
|
897 |
-
* @return array|string Array if $array = true, otherwise a string containing the code
|
898 |
-
*/
|
899 |
-
public function getCode($array = false, $returnExisting = false)
|
900 |
-
{
|
901 |
-
$code =
|
902 |
$time = 0;
|
903 |
$disp = 'error';
|
904 |
|
905 |
if ($returnExisting && strlen($this->code) > 0) {
|
906 |
if ($array) {
|
907 |
-
return array(
|
908 |
-
|
909 |
-
|
910 |
-
|
|
|
911 |
} else {
|
912 |
return $this->code;
|
913 |
}
|
914 |
-
}
|
915 |
-
|
916 |
-
if ($this->no_session != true) {
|
917 |
-
if (isset($_SESSION['securimage_code_value'][$this->namespace]) &&
|
918 |
-
trim($_SESSION['securimage_code_value'][$this->namespace]) != '') {
|
919 |
-
if ($this->isCodeExpired(
|
920 |
-
$_SESSION['securimage_code_ctime'][$this->namespace]) == false) {
|
921 |
-
$code = $_SESSION['securimage_code_value'][$this->namespace];
|
922 |
-
$time = $_SESSION['securimage_code_ctime'][$this->namespace];
|
923 |
-
$
|
924 |
-
}
|
925 |
}
|
926 |
}
|
927 |
|
928 |
-
if (empty($code) && $this->use_database) {
|
929 |
-
// no code in session - may mean user has cookies turned off
|
930 |
-
$this->openDatabase();
|
931 |
-
$code = $this->getCodeFromDatabase();
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
|
|
|
|
|
|
|
|
|
|
939 |
}
|
940 |
|
941 |
/**
|
@@ -1189,12 +1406,17 @@ class Securimage
|
|
1189 |
{
|
1190 |
$width2 = $this->image_width * $this->iscale;
|
1191 |
$height2 = $this->image_height * $this->iscale;
|
|
|
|
|
|
|
|
|
|
|
1192 |
|
1193 |
if (!is_readable($this->ttf_file)) {
|
1194 |
imagestring($this->im, 4, 10, ($this->image_height / 2) - 5, 'Failed to load TTF font file!', $this->gdtextcolor);
|
1195 |
} else {
|
1196 |
if ($this->perturbation > 0) {
|
1197 |
-
$font_size = $height2 *
|
1198 |
$bb = imageftbbox($font_size, 0, $this->ttf_file, $this->code_display);
|
1199 |
$tx = $bb[4] - $bb[0];
|
1200 |
$ty = $bb[5] - $bb[1];
|
@@ -1203,7 +1425,7 @@ class Securimage
|
|
1203 |
|
1204 |
imagettftext($this->tmpimg, $font_size, 0, $x, $y, $this->gdtextcolor, $this->ttf_file, $this->code_display);
|
1205 |
} else {
|
1206 |
-
$font_size = $this->image_height *
|
1207 |
$bb = imageftbbox($font_size, 0, $this->ttf_file, $this->code_display);
|
1208 |
$tx = $bb[4] - $bb[0];
|
1209 |
$ty = $bb[5] - $bb[1];
|
@@ -1378,24 +1600,24 @@ class Securimage
|
|
1378 |
header("Pragma: no-cache");
|
1379 |
}
|
1380 |
|
1381 |
-
switch ($this->image_type) {
|
1382 |
-
case self::SI_IMAGE_JPEG:
|
1383 |
-
if ($this->send_headers) header("Content-Type: image/jpeg");
|
1384 |
-
imagejpeg($this->im, null, 90);
|
1385 |
-
break;
|
1386 |
-
case self::SI_IMAGE_GIF:
|
1387 |
-
if ($this->send_headers) header("Content-Type: image/gif");
|
1388 |
-
imagegif($this->im);
|
1389 |
-
break;
|
1390 |
-
default:
|
1391 |
-
if ($this->send_headers) header("Content-Type: image/png");
|
1392 |
-
imagepng($this->im);
|
1393 |
-
break;
|
1394 |
}
|
1395 |
-
} else {
|
1396 |
-
echo '<hr /><strong>'
|
1397 |
-
.'Failed to generate captcha image, content has already been '
|
1398 |
-
.'output.<br />This is most likely due to misconfiguration or '
|
1399 |
.'a PHP error was sent to the browser.</strong>';
|
1400 |
}
|
1401 |
|
@@ -1415,7 +1637,7 @@ class Securimage
|
|
1415 |
$letters = array();
|
1416 |
$code = $this->getCode(true, true);
|
1417 |
|
1418 |
-
if ($code['code'] == '') {
|
1419 |
if (strlen($this->display_value) > 0) {
|
1420 |
$code = array('code' => $this->display_value, 'display' => $this->display_value);
|
1421 |
} else {
|
@@ -1424,6 +1646,12 @@ class Securimage
|
|
1424 |
}
|
1425 |
}
|
1426 |
|
|
|
|
|
|
|
|
|
|
|
|
|
1427 |
if (preg_match('/(\d+) (\+|-|x) (\d+)/i', $code['display'], $eq)) {
|
1428 |
$math = true;
|
1429 |
|
@@ -1520,13 +1748,24 @@ class Securimage
|
|
1520 |
protected function validate()
|
1521 |
{
|
1522 |
if (!is_string($this->code) || strlen($this->code) == 0) {
|
1523 |
-
$code = $this->getCode();
|
1524 |
// returns stored code, or an empty string if no stored code was found
|
1525 |
// checks the session and database if enabled
|
1526 |
} else {
|
1527 |
$code = $this->code;
|
1528 |
}
|
1529 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1530 |
if ($this->case_sensitive == false && preg_match('/[A-Z]/', $code)) {
|
1531 |
// case sensitive was set from securimage_show.php but not in class
|
1532 |
// the code saved in the session has capitals so set case sensitive to true
|
@@ -1548,6 +1787,7 @@ class Securimage
|
|
1548 |
if ($code == $code_entered) {
|
1549 |
$this->correct_code = true;
|
1550 |
if ($this->no_session != true) {
|
|
|
1551 |
$_SESSION['securimage_code_value'][$this->namespace] = '';
|
1552 |
$_SESSION['securimage_code_ctime'][$this->namespace] = '';
|
1553 |
}
|
@@ -1609,8 +1849,16 @@ class Securimage
|
|
1609 |
$success = $stmt->execute(array($id, $code, $code_disp, $this->namespace, $time));
|
1610 |
|
1611 |
if (!$success) {
|
1612 |
-
$err
|
1613 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1614 |
}
|
1615 |
}
|
1616 |
|
@@ -1649,18 +1897,21 @@ class Securimage
|
|
1649 |
}
|
1650 |
}
|
1651 |
|
1652 |
-
$dsn = $this->getDsn();
|
1653 |
-
|
1654 |
try {
|
1655 |
-
$
|
|
|
|
|
1656 |
$this->pdo_conn = new PDO($dsn, $this->database_user, $this->database_pass, $options);
|
1657 |
} catch (PDOException $pdoex) {
|
1658 |
trigger_error("Database connection failed: " . $pdoex->getMessage(), E_USER_WARNING);
|
1659 |
return false;
|
|
|
|
|
|
|
1660 |
}
|
1661 |
|
1662 |
try {
|
1663 |
-
if (!$this->checkTablesExist()) {
|
1664 |
// create tables...
|
1665 |
$this->createDatabaseTables();
|
1666 |
}
|
@@ -1688,6 +1939,12 @@ class Securimage
|
|
1688 |
|
1689 |
case self::SI_DRIVER_MYSQL:
|
1690 |
case self::SI_DRIVER_PGSQL:
|
|
|
|
|
|
|
|
|
|
|
|
|
1691 |
$dsn .= sprintf('host=%s;dbname=%s',
|
1692 |
$this->database_host,
|
1693 |
$this->database_name);
|
@@ -1807,8 +2064,7 @@ class Securimage
|
|
1807 |
* Get a code from the sqlite database for ip address/captchaId.
|
1808 |
*
|
1809 |
* @return string|array Empty string if no code was found or has expired,
|
1810 |
-
* otherwise returns
|
1811 |
-
* returns an array with indices "code" and "code_disp"
|
1812 |
*/
|
1813 |
protected function getCodeFromDatabase()
|
1814 |
{
|
@@ -1835,13 +2091,11 @@ class Securimage
|
|
1835 |
} else {
|
1836 |
if ( ($row = $stmt->fetch()) !== false ) {
|
1837 |
if (false == $this->isCodeExpired($row['created'])) {
|
1838 |
-
|
1839 |
-
|
1840 |
-
|
1841 |
-
|
1842 |
-
|
1843 |
-
$code = $row['code'];
|
1844 |
-
}
|
1845 |
}
|
1846 |
}
|
1847 |
}
|
@@ -1922,11 +2176,30 @@ class Securimage
|
|
1922 |
$wavCaptcha = new WavFile();
|
1923 |
$first = true; // reading first wav file
|
1924 |
|
|
|
|
|
|
|
|
|
1925 |
foreach ($letters as $letter) {
|
1926 |
$letter = strtoupper($letter);
|
1927 |
|
1928 |
try {
|
1929 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1930 |
|
1931 |
if ($first) {
|
1932 |
// set sample rate, bits/sample, and # of channels for file based on first letter
|
@@ -1943,10 +2216,10 @@ class Securimage
|
|
1943 |
if ($this->audio_gap_max > 0 && $this->audio_gap_max > $this->audio_gap_min) {
|
1944 |
$wavCaptcha->insertSilence( mt_rand($this->audio_gap_min, $this->audio_gap_max) / 1000.0 );
|
1945 |
}
|
1946 |
-
} catch (Exception $ex) {
|
1947 |
// failed to open file, or the wav file is broken or not supported
|
1948 |
// 2 wav files were not compatible, different # channels, bits/sample, or sample rate
|
1949 |
-
throw $ex;
|
1950 |
}
|
1951 |
}
|
1952 |
|
@@ -1955,9 +2228,27 @@ class Securimage
|
|
1955 |
|
1956 |
if ($this->audio_use_noise == true) {
|
1957 |
// use background audio - find random file
|
1958 |
-
$
|
1959 |
-
|
1960 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1961 |
try {
|
1962 |
$wavNoise = new WavFile($noiseFile, false);
|
1963 |
} catch(Exception $ex) {
|
@@ -1966,7 +2257,9 @@ class Securimage
|
|
1966 |
|
1967 |
// start at a random offset from the beginning of the wavfile
|
1968 |
// in order to add more randomness
|
|
|
1969 |
$randOffset = 0;
|
|
|
1970 |
if ($wavNoise->getNumBlocks() > 2 * $wavCaptcha->getNumBlocks()) {
|
1971 |
$randBlock = mt_rand(0, $wavNoise->getNumBlocks() - $wavCaptcha->getNumBlocks());
|
1972 |
$wavNoise->readWavData($randBlock * $wavNoise->getBlockAlign(), $wavCaptcha->getNumBlocks() * $wavNoise->getBlockAlign());
|
@@ -1974,8 +2267,9 @@ class Securimage
|
|
1974 |
$wavNoise->readWavData();
|
1975 |
$randOffset = mt_rand(0, $wavNoise->getNumBlocks() - 1);
|
1976 |
}
|
|
|
1977 |
|
1978 |
-
|
1979 |
$mixOpts = array('wav' => $wavNoise,
|
1980 |
'loop' => true,
|
1981 |
'blockOffset' => $randOffset);
|
@@ -2017,12 +2311,136 @@ class Securimage
|
|
2017 |
if (sizeof($list) > 0) {
|
2018 |
$file = $list[array_rand($list, 1)];
|
2019 |
$return = $this->audio_noise_path . DIRECTORY_SEPARATOR . $file;
|
|
|
|
|
2020 |
}
|
2021 |
}
|
2022 |
|
2023 |
return $return;
|
2024 |
}
|
2025 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026 |
/**
|
2027 |
* Return a wav file saying there was an error generating file
|
2028 |
*
|
@@ -2038,18 +2456,18 @@ class Securimage
|
|
2038 |
*
|
2039 |
* @return bool true if headers haven't been sent and no output/errors will break audio/images, false if unsafe
|
2040 |
*/
|
2041 |
-
protected function canSendHeaders()
|
2042 |
-
{
|
2043 |
-
if (headers_sent()) {
|
2044 |
-
// output has been flushed and headers have already been sent
|
2045 |
-
return false;
|
2046 |
-
} else if (strlen((string)ob_get_contents()) > 0) {
|
2047 |
-
// headers haven't been sent, but there is data in the buffer that will break image and audio data
|
2048 |
-
return false;
|
2049 |
-
}
|
2050 |
-
|
2051 |
-
return true;
|
2052 |
-
}
|
2053 |
|
2054 |
/**
|
2055 |
* Return a random float between 0 and 0.9999
|
6 |
* Project: Securimage: A PHP class for creating and managing form CAPTCHA images<br />
|
7 |
* File: securimage.php<br />
|
8 |
*
|
9 |
+
* Copyright (c) 2014, Drew Phillips
|
10 |
* All rights reserved.
|
11 |
*
|
12 |
* Redistribution and use in source and binary forms, with or without modification,
|
39 |
* @link http://www.phpcaptcha.org Securimage PHP CAPTCHA
|
40 |
* @link http://www.phpcaptcha.org/latest.zip Download Latest Version
|
41 |
* @link http://www.phpcaptcha.org/Securimage_Docs/ Online Documentation
|
42 |
+
* @copyright 2014 Drew Phillips
|
43 |
* @author Drew Phillips <drew@drew-phillips.com>
|
44 |
+
* @version 3.5.2 (Feb 15, 2014)
|
45 |
* @package Securimage
|
46 |
*
|
47 |
*/
|
49 |
/**
|
50 |
ChangeLog
|
51 |
|
52 |
+
3.5.2
|
53 |
+
|
54 |
+
- Add Securimage::getCaptchaHtml() for getting automatically generated captcha html code
|
55 |
+
- Option for using SoX to add effects to captcha audio to make identification by neural networks more difficult
|
56 |
+
- Add setNamespace() method
|
57 |
+
- Add getTimeToSolve() method
|
58 |
+
- Add session_status() check so session still starts if one had previously been opened and closed
|
59 |
+
- Add .htaccess file to audio directory to deny access; update audio files
|
60 |
+
- Option to skip checking of database tables during connection
|
61 |
+
- Add composer.json to package, submit to packagist
|
62 |
+
- Add font_ration variable to determine size of font (github.com/wilkor)
|
63 |
+
- Add hint if sqlite3 database is not writeable. Improve database error handling, add example database options to securimage_play.php
|
64 |
+
- Fixed issue regarding database storage and math captcha breaking audio output (github.com/SoftwareAndOutsourcing)
|
65 |
+
|
66 |
3.5.1
|
67 |
- Fix XSS vulnerability in example_form.php (discovered by Gjoko Krstic - <gjoko@zeroscience.mk>)
|
68 |
|
170 |
/**
|
171 |
* Securimage CAPTCHA Class.
|
172 |
*
|
173 |
+
* @version 3.5.2
|
174 |
* @package Securimage
|
175 |
* @subpackage classes
|
176 |
* @author Drew Phillips <drew@drew-phillips.com>
|
248 |
* @var int
|
249 |
*/
|
250 |
public $image_height = 80;
|
251 |
+
|
252 |
+
/**
|
253 |
+
* Font size is calculated by image height and this ratio - leave blank for default ratio of 0.4.
|
254 |
+
* Valid range: 0.1 - 0.99.
|
255 |
+
* Depending on image_width, values > 0.6 are probably too large and values < 0.3 are too small.
|
256 |
+
*
|
257 |
+
* @var float
|
258 |
+
*/
|
259 |
+
public $font_ratio;
|
260 |
+
|
261 |
/**
|
262 |
* The type of the image, default = png
|
263 |
* @var int
|
313 |
public $charset = 'ABCDEFGHKLMNPRSTUVWYZabcdefghklmnprstuvwyz23456789';
|
314 |
/**
|
315 |
* How long in seconds a captcha remains valid, after this time it will not be accepted
|
316 |
+
* @var int
|
317 |
*/
|
318 |
public $expiry_time = 900;
|
319 |
|
381 |
*/
|
382 |
public $use_database = false;
|
383 |
|
384 |
+
/**
|
385 |
+
* Whether or not to skip checking if Securimage tables exist when using a database.
|
386 |
+
* Turn this to true once database functionality is working to improve performance.
|
387 |
+
*
|
388 |
+
* @var bool true to not check if captcha_codes tables are set up, false to check (and create if necessary)
|
389 |
+
*/
|
390 |
+
public $skip_table_check = false;
|
391 |
+
|
392 |
/**
|
393 |
* Database driver to use for database support.
|
394 |
* Allowable values: 'mysql', 'pgsql', 'sqlite'.
|
502 |
* </code>
|
503 |
*/
|
504 |
public $audio_path;
|
505 |
+
|
506 |
+
/**
|
507 |
+
* Use SoX (The Swiss Army knife of audio manipulation) for audio effects and processing
|
508 |
+
*
|
509 |
+
* @see Securimage::$sox_binary_path
|
510 |
+
* @var bool true to use SoX, false to use PHP
|
511 |
+
*/
|
512 |
+
public $audio_use_sox = false;
|
513 |
+
|
514 |
+
/**
|
515 |
+
* The path to the SoX binary on your system
|
516 |
+
*
|
517 |
+
* @var string
|
518 |
+
*/
|
519 |
+
public $sox_binary_path = '/usr/bin/sox';
|
520 |
+
|
521 |
/**
|
522 |
* The path to the directory containing audio files that will be selected
|
523 |
* randomly and mixed with the captcha audio.
|
556 |
* @since 3.0.4
|
557 |
* @var float
|
558 |
*/
|
559 |
+
public $audio_mix_normalization = 0.8;
|
560 |
/**
|
561 |
* Whether or not to degrade audio by introducing random noise (improves security of audio captcha)
|
562 |
* Default: true
|
578 |
* @since 3.0.3
|
579 |
* @var float
|
580 |
*/
|
581 |
+
public $audio_gap_max = 3000;
|
582 |
|
583 |
/**
|
584 |
* Captcha ID if using static captcha
|
624 |
*/
|
625 |
protected $captcha_code;
|
626 |
|
627 |
+
/**
|
628 |
+
* Time (in seconds) that the captcha was solved in (correctly or incorrectly). This is from the time of code creation, to when validation was attempted.
|
629 |
+
*
|
630 |
+
* @var int
|
631 |
+
*/
|
632 |
+
protected $_timeToSolve = 0;
|
633 |
+
|
634 |
/**
|
635 |
* Flag that can be specified telling securimage not to call exit after generating a captcha image or audio file
|
636 |
*
|
760 |
|
761 |
if ($this->no_session != true) {
|
762 |
// Initialize session or attach to existing
|
763 |
+
if ( session_id() == '' || (function_exists('session_status') && PHP_SESSION_NONE == session_status()) ) { // no session has been started yet (or it was previousy closed), which is needed for validation
|
764 |
if (!is_null($this->session_name) && trim($this->session_name) != '') {
|
765 |
session_name(trim($this->session_name)); // set session name if provided
|
766 |
}
|
890 |
return $this->correct_code;
|
891 |
}
|
892 |
|
893 |
+
/**
|
894 |
+
* Returns HTML for displaying the captcha image, audio button, and text input for forms
|
895 |
+
*
|
896 |
+
* @param array $options Array of options for modifying the HTML code. Accepted options are:
|
897 |
+
* 'securimage_path' => Optional: The URI to where securimage is installed (e.g. /securimage)
|
898 |
+
* 'image_id' => A string that sets the "id" attribute of the captcha image (default: captcha_image)
|
899 |
+
* 'image_alt_text' => The alt text of the captcha image (default: CAPTCHA Image)
|
900 |
+
* 'show_audio_button' => true/false Whether or not to show the audio button (default: true)
|
901 |
+
* 'show_refresh_button' => true/false Whether or not to show a button to refresh the image (default: true)
|
902 |
+
* 'show_text_input' => true/false Whether or not to show the text input for the captcha (default: true)
|
903 |
+
* 'refresh_alt_text' => Alt text for the refresh image (default: Refresh Image)
|
904 |
+
* 'refresh_title_text' => Title text for the refresh image link (default: Refresh Image)
|
905 |
+
* 'input_id' => A string that sets the "id" attribute of the captcha text input (default: captcha_code)
|
906 |
+
* 'input_name' => A string that sets the "name" attribute of the captcha text input (default: same as input_id)
|
907 |
+
* 'input_text' => A string that sets the text of the label for the captcha text input (default: Type the text:)
|
908 |
+
* 'input_attributes' => An array of additional HTML tag attributes to pass to the text input tag (default: empty)
|
909 |
+
* 'image_attributes' => An array of additional HTML tag attributes to pass to the captcha image tag (default: empty)
|
910 |
+
* 'namespace' => The optional captcha namespace to use for showing the image and playing back the audio. Namespaces are for using multiple captchas on the same page.
|
911 |
+
*
|
912 |
+
* @return string The generated HTML code for the captcha image
|
913 |
+
*/
|
914 |
+
public static function getCaptchaHtml($options = array())
|
915 |
+
{
|
916 |
+
if (!isset($options['securimage_path'])) {
|
917 |
+
$docroot = (isset($_SERVER['DOCUMENT_ROOT'])) ? $_SERVER['DOCUMENT_ROOT'] : substr($_SERVER['SCRIPT_FILENAME'], 0, -strlen($_SERVER['SCRIPT_NAME']));
|
918 |
+
$docroot = realpath($docroot);
|
919 |
+
$sipath = dirname(__FILE__);
|
920 |
+
$securimage_path = str_replace($docroot, '', $sipath);
|
921 |
+
} else {
|
922 |
+
$securimage_path = $options['securimage_path'];
|
923 |
+
}
|
924 |
+
|
925 |
+
$image_id = (isset($options['image_id'])) ? $options['image_id'] : 'captcha_image';
|
926 |
+
$image_alt = (isset($options['image_alt_text'])) ? $options['image_alt_text'] : 'CAPTCHA Image';
|
927 |
+
$show_audio_btn = (isset($options['show_audio_button'])) ? (bool)$options['show_audio_button'] : true;
|
928 |
+
$show_refresh_btn = (isset($options['show_refresh_button'])) ? (bool)$options['show_refresh_button'] : true;
|
929 |
+
$show_input = (isset($options['show_text_input'])) ? (bool)$options['show_text_input'] : true;
|
930 |
+
$refresh_alt = (isset($options['refresh_alt_text'])) ? $options['refresh_alt_text'] : 'Refresh Image';
|
931 |
+
$refresh_title = (isset($options['refresh_title_text'])) ? $options['refresh_title_text'] : 'Refresh Image';
|
932 |
+
$input_text = (isset($options['input_text'])) ? $options['input_text'] : 'Type the text:';
|
933 |
+
$input_id = (isset($options['input_id'])) ? $options['input_id'] : 'captcha_code';
|
934 |
+
$input_name = (isset($options['input_name'])) ? $options['input_name'] : $input_id;
|
935 |
+
$input_attrs = (isset($options['input_attributes'])) ? $options['input_attributes'] : array();
|
936 |
+
$image_attrs = (isset($options['image_attributes'])) ? $options['image_attributes'] : array();
|
937 |
+
$error_html = (isset($options['error_html'])) ? $options['error_html'] : null;
|
938 |
+
$namespace = (isset($options['namespace'])) ? $options['namespace'] : '';
|
939 |
+
|
940 |
+
$rand = md5(uniqid($_SERVER['REMOTE_PORT'], true));
|
941 |
+
$securimage_path = rtrim($securimage_path, '/\\');
|
942 |
+
|
943 |
+
$image_attr = '';
|
944 |
+
if (!is_array($image_attrs)) $image_attrs = array();
|
945 |
+
if (!isset($image_attrs['align'])) $image_attrs['align'] = 'left';
|
946 |
+
$image_attrs['id'] = $image_id;
|
947 |
+
|
948 |
+
$show_path = $securimage_path . '/securimage_show.php?';
|
949 |
+
if (!empty($namespace)) {
|
950 |
+
$show_path .= sprintf('namespace=%s&', $namespace);
|
951 |
+
}
|
952 |
+
$image_attrs['src'] = $show_path . $rand;
|
953 |
+
|
954 |
+
$image_attrs['alt'] = $image_alt;
|
955 |
+
|
956 |
+
foreach($image_attrs as $name => $val) {
|
957 |
+
$image_attr .= sprintf('%s="%s" ', $name, htmlspecialchars($val));
|
958 |
+
}
|
959 |
+
|
960 |
+
$html = sprintf('<img %s/>', $image_attr);
|
961 |
+
|
962 |
+
if ($show_audio_btn) {
|
963 |
+
$swf_path = $securimage_path . '/securimage_play.swf';
|
964 |
+
$play_path = $securimage_path . '/securimage_play.php';
|
965 |
+
$icon_path = $securimage_path . '/images/audio_icon.png';
|
966 |
+
|
967 |
+
$html .= sprintf('<object type="application/x-shockwave-flash" data="%s?bgcol=%s&icon_file=%s&audio_file=%s" height="32" width="32">',
|
968 |
+
htmlspecialchars($swf_path),
|
969 |
+
'#ffffff',
|
970 |
+
htmlspecialchars($icon_path),
|
971 |
+
htmlspecialchars($play_path)
|
972 |
+
);
|
973 |
+
|
974 |
+
$html .= sprintf('<param name="movie" value="%s?bgcol=%s&icon_file=%s&audio_file=%s" />',
|
975 |
+
htmlspecialchars($swf_path),
|
976 |
+
'#ffffff',
|
977 |
+
htmlspecialchars($icon_path),
|
978 |
+
$play_path
|
979 |
+
);
|
980 |
+
|
981 |
+
$html .= '</object><br />';
|
982 |
+
}
|
983 |
+
|
984 |
+
if ($show_refresh_btn) {
|
985 |
+
$icon_path = $securimage_path . '/images/refresh.png';
|
986 |
+
$img_tag = sprintf('<img height="32" width="32" src="%s" alt="%s" onclick="this.blur()" align="bottom" border="0" />',
|
987 |
+
htmlspecialchars($icon_path), htmlspecialchars($refresh_alt));
|
988 |
+
|
989 |
+
$html .= sprintf('<a tabindex="-1" style="border: 0" href="#" title="%s" onclick="document.getElementById(\'%s\').src = \'%s\' + Math.random(); this.blur(); return false">%s</a><br />',
|
990 |
+
htmlspecialchars($refresh_title),
|
991 |
+
$image_id,
|
992 |
+
$show_path,
|
993 |
+
$img_tag
|
994 |
+
);
|
995 |
+
}
|
996 |
+
|
997 |
+
$html .= '<div style="clear: both"></div>';
|
998 |
+
|
999 |
+
$html .= sprintf('<label for="%s">%s</label> ',
|
1000 |
+
htmlspecialchars($input_id),
|
1001 |
+
htmlspecialchars($input_text));
|
1002 |
+
|
1003 |
+
if (!empty($error_html)) {
|
1004 |
+
$html .= $error_html;
|
1005 |
+
}
|
1006 |
+
|
1007 |
+
$input_attr = '';
|
1008 |
+
if (!is_array($input_attrs)) $input_attrs = array();
|
1009 |
+
$input_attrs['type'] = 'text';
|
1010 |
+
$input_attrs['name'] = $input_name;
|
1011 |
+
$input_attrs['id'] = $input_id;
|
1012 |
+
|
1013 |
+
foreach($input_attrs as $name => $val) {
|
1014 |
+
$input_attr .= sprintf('%s="%s" ', $name, htmlspecialchars($val));
|
1015 |
+
}
|
1016 |
+
|
1017 |
+
$html .= sprintf('<input %s/>', $input_attr);
|
1018 |
+
|
1019 |
+
return $html;
|
1020 |
+
}
|
1021 |
+
|
1022 |
+
/**
|
1023 |
+
* Get the time in seconds that it took to solve the captcha.
|
1024 |
+
*
|
1025 |
+
* @return int The time in seconds from when the code was created, to when it was solved
|
1026 |
+
*/
|
1027 |
+
public function getTimeToSolve()
|
1028 |
+
{
|
1029 |
+
return $this->_timeToSolve;
|
1030 |
+
}
|
1031 |
+
|
1032 |
+
/**
|
1033 |
+
* Set the namespace for the captcha being stored in the session or database.
|
1034 |
+
*
|
1035 |
+
* @param string $namespace Namespace value, String consisting of characters "a-zA-Z0-9_-"
|
1036 |
+
*/
|
1037 |
+
public function setNamespace($namespace)
|
1038 |
+
{
|
1039 |
+
$namespace = preg_replace('/[^a-z0-9-_]/i', '', $namespace);
|
1040 |
+
$namespace = substr($namespace, 0, 64);
|
1041 |
+
|
1042 |
+
if (!empty($namespace)) {
|
1043 |
+
$this->namespace = $namespace;
|
1044 |
+
} else {
|
1045 |
+
$this->namespace = 'default';
|
1046 |
+
}
|
1047 |
+
}
|
1048 |
+
|
1049 |
/**
|
1050 |
* Output a wav file of the captcha code to the browser
|
1051 |
*
|
1064 |
try {
|
1065 |
$audio = $this->getAudibleCode();
|
1066 |
} catch (Exception $ex) {
|
1067 |
+
if (($fp = @fopen(dirname(__FILE__) . '/si.error_log', 'a+')) !== false) {
|
1068 |
+
fwrite($fp, date('Y-m-d H:i:s') . ': Securimage audio error "' . $ex->getMessage() . '"' . "\n");
|
1069 |
+
fclose($fp);
|
1070 |
}
|
1071 |
|
1072 |
$audio = $this->audioError();
|
1073 |
+
}
|
1074 |
|
1075 |
if ($this->canSendHeaders() || $this->send_headers == false) {
|
1076 |
if ($this->send_headers) {
|
1101 |
if (!$this->no_exit) exit;
|
1102 |
}
|
1103 |
|
1104 |
+
/**
|
1105 |
+
* Return the code from the session or sqlite database if used. If none exists yet, an empty string is returned
|
1106 |
+
*
|
1107 |
+
* @param $array bool True to receive an array containing the code and properties
|
1108 |
+
* @return array|string Array if $array = true, otherwise a string containing the code
|
1109 |
+
*/
|
1110 |
+
public function getCode($array = false, $returnExisting = false)
|
1111 |
+
{
|
1112 |
+
$code = array();
|
1113 |
$time = 0;
|
1114 |
$disp = 'error';
|
1115 |
|
1116 |
if ($returnExisting && strlen($this->code) > 0) {
|
1117 |
if ($array) {
|
1118 |
+
return array(
|
1119 |
+
'code' => $this->code,
|
1120 |
+
'display' => $this->code_display,
|
1121 |
+
'code_display' => $this->code_display,
|
1122 |
+
'time' => 0);
|
1123 |
} else {
|
1124 |
return $this->code;
|
1125 |
}
|
1126 |
+
}
|
1127 |
+
|
1128 |
+
if ($this->no_session != true) {
|
1129 |
+
if (isset($_SESSION['securimage_code_value'][$this->namespace]) &&
|
1130 |
+
trim($_SESSION['securimage_code_value'][$this->namespace]) != '') {
|
1131 |
+
if ($this->isCodeExpired(
|
1132 |
+
$_SESSION['securimage_code_ctime'][$this->namespace]) == false) {
|
1133 |
+
$code['code'] = $_SESSION['securimage_code_value'][$this->namespace];
|
1134 |
+
$code['time'] = $_SESSION['securimage_code_ctime'][$this->namespace];
|
1135 |
+
$code['display'] = $_SESSION['securimage_code_disp'] [$this->namespace];
|
1136 |
+
}
|
1137 |
}
|
1138 |
}
|
1139 |
|
1140 |
+
if (empty($code) && $this->use_database) {
|
1141 |
+
// no code in session - may mean user has cookies turned off
|
1142 |
+
$this->openDatabase();
|
1143 |
+
$code = $this->getCodeFromDatabase();
|
1144 |
+
|
1145 |
+
if (!empty($code)) {
|
1146 |
+
$code['display'] = $code['code_disp'];
|
1147 |
+
unset($code['code_disp']);
|
1148 |
+
}
|
1149 |
+
} else { /* no code stored in session or sqlite database, validation will fail */ }
|
1150 |
+
|
1151 |
+
if ($array == true) {
|
1152 |
+
return $code;
|
1153 |
+
} else {
|
1154 |
+
return $code['code'];
|
1155 |
+
}
|
1156 |
}
|
1157 |
|
1158 |
/**
|
1406 |
{
|
1407 |
$width2 = $this->image_width * $this->iscale;
|
1408 |
$height2 = $this->image_height * $this->iscale;
|
1409 |
+
$ratio = ($this->font_ratio) ? $this->font_ratio : 0.4;
|
1410 |
+
|
1411 |
+
if ((float)$ratio < 0.1 || (float)$ratio >= 1) {
|
1412 |
+
$ratio = 0.4;
|
1413 |
+
}
|
1414 |
|
1415 |
if (!is_readable($this->ttf_file)) {
|
1416 |
imagestring($this->im, 4, 10, ($this->image_height / 2) - 5, 'Failed to load TTF font file!', $this->gdtextcolor);
|
1417 |
} else {
|
1418 |
if ($this->perturbation > 0) {
|
1419 |
+
$font_size = $height2 * $ratio;
|
1420 |
$bb = imageftbbox($font_size, 0, $this->ttf_file, $this->code_display);
|
1421 |
$tx = $bb[4] - $bb[0];
|
1422 |
$ty = $bb[5] - $bb[1];
|
1425 |
|
1426 |
imagettftext($this->tmpimg, $font_size, 0, $x, $y, $this->gdtextcolor, $this->ttf_file, $this->code_display);
|
1427 |
} else {
|
1428 |
+
$font_size = $this->image_height * $ratio;
|
1429 |
$bb = imageftbbox($font_size, 0, $this->ttf_file, $this->code_display);
|
1430 |
$tx = $bb[4] - $bb[0];
|
1431 |
$ty = $bb[5] - $bb[1];
|
1600 |
header("Pragma: no-cache");
|
1601 |
}
|
1602 |
|
1603 |
+
switch ($this->image_type) {
|
1604 |
+
case self::SI_IMAGE_JPEG:
|
1605 |
+
if ($this->send_headers) header("Content-Type: image/jpeg");
|
1606 |
+
imagejpeg($this->im, null, 90);
|
1607 |
+
break;
|
1608 |
+
case self::SI_IMAGE_GIF:
|
1609 |
+
if ($this->send_headers) header("Content-Type: image/gif");
|
1610 |
+
imagegif($this->im);
|
1611 |
+
break;
|
1612 |
+
default:
|
1613 |
+
if ($this->send_headers) header("Content-Type: image/png");
|
1614 |
+
imagepng($this->im);
|
1615 |
+
break;
|
1616 |
}
|
1617 |
+
} else {
|
1618 |
+
echo '<hr /><strong>'
|
1619 |
+
.'Failed to generate captcha image, content has already been '
|
1620 |
+
.'output.<br />This is most likely due to misconfiguration or '
|
1621 |
.'a PHP error was sent to the browser.</strong>';
|
1622 |
}
|
1623 |
|
1637 |
$letters = array();
|
1638 |
$code = $this->getCode(true, true);
|
1639 |
|
1640 |
+
if (empty($code) || $code['code'] == '') {
|
1641 |
if (strlen($this->display_value) > 0) {
|
1642 |
$code = array('code' => $this->display_value, 'display' => $this->display_value);
|
1643 |
} else {
|
1646 |
}
|
1647 |
}
|
1648 |
|
1649 |
+
if (empty($code)) {
|
1650 |
+
$error = 'Failed to get audible code (are database settings correct?). Check the error log for details';
|
1651 |
+
trigger_error($error, E_USER_WARNING);
|
1652 |
+
throw new Exception($error);
|
1653 |
+
}
|
1654 |
+
|
1655 |
if (preg_match('/(\d+) (\+|-|x) (\d+)/i', $code['display'], $eq)) {
|
1656 |
$math = true;
|
1657 |
|
1748 |
protected function validate()
|
1749 |
{
|
1750 |
if (!is_string($this->code) || strlen($this->code) == 0) {
|
1751 |
+
$code = $this->getCode(true);
|
1752 |
// returns stored code, or an empty string if no stored code was found
|
1753 |
// checks the session and database if enabled
|
1754 |
} else {
|
1755 |
$code = $this->code;
|
1756 |
}
|
1757 |
|
1758 |
+
if (is_array($code)) {
|
1759 |
+
if (!empty($code)) {
|
1760 |
+
$ctime = $code['time'];
|
1761 |
+
$code = $code['code'];
|
1762 |
+
|
1763 |
+
$this->_timeToSolve = time() - $ctime;
|
1764 |
+
} else {
|
1765 |
+
$code = '';
|
1766 |
+
}
|
1767 |
+
}
|
1768 |
+
|
1769 |
if ($this->case_sensitive == false && preg_match('/[A-Z]/', $code)) {
|
1770 |
// case sensitive was set from securimage_show.php but not in class
|
1771 |
// the code saved in the session has capitals so set case sensitive to true
|
1787 |
if ($code == $code_entered) {
|
1788 |
$this->correct_code = true;
|
1789 |
if ($this->no_session != true) {
|
1790 |
+
$_SESSION['securimage_code_disp'] [$this->namespace] = '';
|
1791 |
$_SESSION['securimage_code_value'][$this->namespace] = '';
|
1792 |
$_SESSION['securimage_code_ctime'][$this->namespace] = '';
|
1793 |
}
|
1849 |
$success = $stmt->execute(array($id, $code, $code_disp, $this->namespace, $time));
|
1850 |
|
1851 |
if (!$success) {
|
1852 |
+
$err = $stmt->errorInfo();
|
1853 |
+
$error = "Failed to insert code into database. {$err[1]}: {$err[2]}.";
|
1854 |
+
|
1855 |
+
if ($this->database_driver == self::SI_DRIVER_SQLITE3) {
|
1856 |
+
$err14 = ($err[1] == 14);
|
1857 |
+
if ($err14) $error .= sprintf(" Ensure database directory and file are writeable by user '%s' (%d).",
|
1858 |
+
get_current_user(), getmyuid());
|
1859 |
+
}
|
1860 |
+
|
1861 |
+
trigger_error($error, E_USER_WARNING);
|
1862 |
}
|
1863 |
}
|
1864 |
|
1897 |
}
|
1898 |
}
|
1899 |
|
|
|
|
|
1900 |
try {
|
1901 |
+
$dsn = $this->getDsn();
|
1902 |
+
|
1903 |
+
$options = array();
|
1904 |
$this->pdo_conn = new PDO($dsn, $this->database_user, $this->database_pass, $options);
|
1905 |
} catch (PDOException $pdoex) {
|
1906 |
trigger_error("Database connection failed: " . $pdoex->getMessage(), E_USER_WARNING);
|
1907 |
return false;
|
1908 |
+
} catch (Exception $ex) {
|
1909 |
+
trigger_error($ex->getMessage(), E_USER_WARNING);
|
1910 |
+
return false;
|
1911 |
}
|
1912 |
|
1913 |
try {
|
1914 |
+
if (!$this->skip_table_check && !$this->checkTablesExist()) {
|
1915 |
// create tables...
|
1916 |
$this->createDatabaseTables();
|
1917 |
}
|
1939 |
|
1940 |
case self::SI_DRIVER_MYSQL:
|
1941 |
case self::SI_DRIVER_PGSQL:
|
1942 |
+
if (empty($this->database_host)) {
|
1943 |
+
throw new Exception('Securimage::database_host is not set');
|
1944 |
+
} else if (empty($this->database_name)) {
|
1945 |
+
throw new Exception('Securimage::database_name is not set');
|
1946 |
+
}
|
1947 |
+
|
1948 |
$dsn .= sprintf('host=%s;dbname=%s',
|
1949 |
$this->database_host,
|
1950 |
$this->database_name);
|
2064 |
* Get a code from the sqlite database for ip address/captchaId.
|
2065 |
*
|
2066 |
* @return string|array Empty string if no code was found or has expired,
|
2067 |
+
* otherwise returns array of code information.
|
|
|
2068 |
*/
|
2069 |
protected function getCodeFromDatabase()
|
2070 |
{
|
2091 |
} else {
|
2092 |
if ( ($row = $stmt->fetch()) !== false ) {
|
2093 |
if (false == $this->isCodeExpired($row['created'])) {
|
2094 |
+
$code = array(
|
2095 |
+
'code' => $row['code'],
|
2096 |
+
'code_disp' => $row['code_display'],
|
2097 |
+
'time' => $row['created'],
|
2098 |
+
);
|
|
|
|
|
2099 |
}
|
2100 |
}
|
2101 |
}
|
2176 |
$wavCaptcha = new WavFile();
|
2177 |
$first = true; // reading first wav file
|
2178 |
|
2179 |
+
if ($this->audio_use_sox && !is_executable($this->sox_binary_path)) {
|
2180 |
+
throw new Exception("Path to SoX binary is incorrect or not executable");
|
2181 |
+
}
|
2182 |
+
|
2183 |
foreach ($letters as $letter) {
|
2184 |
$letter = strtoupper($letter);
|
2185 |
|
2186 |
try {
|
2187 |
+
$letter_file = realpath($this->audio_path) . DIRECTORY_SEPARATOR . $letter . '.wav';
|
2188 |
+
|
2189 |
+
if ($this->audio_use_sox) {
|
2190 |
+
$sox_cmd = sprintf("%s %s -t wav - %s",
|
2191 |
+
$this->sox_binary_path,
|
2192 |
+
$letter_file,
|
2193 |
+
$this->getSoxEffectChain());
|
2194 |
+
|
2195 |
+
$data = `$sox_cmd`;
|
2196 |
+
|
2197 |
+
$l = new WavFile();
|
2198 |
+
$l->setIgnoreChunkSizes(true);
|
2199 |
+
$l->setWavData($data);
|
2200 |
+
} else {
|
2201 |
+
$l = new WavFile($letter_file);
|
2202 |
+
}
|
2203 |
|
2204 |
if ($first) {
|
2205 |
// set sample rate, bits/sample, and # of channels for file based on first letter
|
2216 |
if ($this->audio_gap_max > 0 && $this->audio_gap_max > $this->audio_gap_min) {
|
2217 |
$wavCaptcha->insertSilence( mt_rand($this->audio_gap_min, $this->audio_gap_max) / 1000.0 );
|
2218 |
}
|
2219 |
+
} catch (Exception $ex) {
|
2220 |
// failed to open file, or the wav file is broken or not supported
|
2221 |
// 2 wav files were not compatible, different # channels, bits/sample, or sample rate
|
2222 |
+
throw new Exception("Error generating audio captcha on letter '$letter': " . $ex->getMessage());
|
2223 |
}
|
2224 |
}
|
2225 |
|
2228 |
|
2229 |
if ($this->audio_use_noise == true) {
|
2230 |
// use background audio - find random file
|
2231 |
+
$wavNoise = false;
|
2232 |
+
$randOffset = 0;
|
2233 |
+
|
2234 |
+
/*
|
2235 |
+
// uncomment to try experimental SoX noise generation.
|
2236 |
+
// warning: sounds may be considered annoying
|
2237 |
+
if ($this->audio_use_sox) {
|
2238 |
+
$duration = $wavCaptcha->getDataSize() / ($wavCaptcha->getBitsPerSample() / 8) /
|
2239 |
+
$wavCaptcha->getNumChannels() / $wavCaptcha->getSampleRate();
|
2240 |
+
$duration = round($duration, 2);
|
2241 |
+
$wavNoise = new WavFile();
|
2242 |
+
$wavNoise->setIgnoreChunkSizes(true);
|
2243 |
+
$noiseData = $this->getSoxNoiseData($duration,
|
2244 |
+
$wavCaptcha->getNumChannels(),
|
2245 |
+
$wavCaptcha->getSampleRate(),
|
2246 |
+
$wavCaptcha->getBitsPerSample());
|
2247 |
+
$wavNoise->setWavData($noiseData, true);
|
2248 |
+
|
2249 |
+
} else
|
2250 |
+
*/
|
2251 |
+
if ( ($noiseFile = $this->getRandomNoiseFile()) !== false) {
|
2252 |
try {
|
2253 |
$wavNoise = new WavFile($noiseFile, false);
|
2254 |
} catch(Exception $ex) {
|
2257 |
|
2258 |
// start at a random offset from the beginning of the wavfile
|
2259 |
// in order to add more randomness
|
2260 |
+
|
2261 |
$randOffset = 0;
|
2262 |
+
|
2263 |
if ($wavNoise->getNumBlocks() > 2 * $wavCaptcha->getNumBlocks()) {
|
2264 |
$randBlock = mt_rand(0, $wavNoise->getNumBlocks() - $wavCaptcha->getNumBlocks());
|
2265 |
$wavNoise->readWavData($randBlock * $wavNoise->getBlockAlign(), $wavCaptcha->getNumBlocks() * $wavNoise->getBlockAlign());
|
2267 |
$wavNoise->readWavData();
|
2268 |
$randOffset = mt_rand(0, $wavNoise->getNumBlocks() - 1);
|
2269 |
}
|
2270 |
+
}
|
2271 |
|
2272 |
+
if ($wavNoise !== false) {
|
2273 |
$mixOpts = array('wav' => $wavNoise,
|
2274 |
'loop' => true,
|
2275 |
'blockOffset' => $randOffset);
|
2311 |
if (sizeof($list) > 0) {
|
2312 |
$file = $list[array_rand($list, 1)];
|
2313 |
$return = $this->audio_noise_path . DIRECTORY_SEPARATOR . $file;
|
2314 |
+
|
2315 |
+
if (!is_readable($return)) $return = false;
|
2316 |
}
|
2317 |
}
|
2318 |
|
2319 |
return $return;
|
2320 |
}
|
2321 |
|
2322 |
+
protected function getSoxEffectChain($numEffects = 2)
|
2323 |
+
{
|
2324 |
+
$effectsList = array('bend', 'chorus', 'overdrive', 'pitch', 'reverb', 'tempo', 'tremolo');
|
2325 |
+
$effects = array_rand($effectsList, $numEffects);
|
2326 |
+
$outEffects = array();
|
2327 |
+
|
2328 |
+
if (!is_array($effects)) $effects = array($effects);
|
2329 |
+
|
2330 |
+
foreach($effects as $effect) {
|
2331 |
+
$effect = $effectsList[$effect];
|
2332 |
+
|
2333 |
+
switch($effect)
|
2334 |
+
{
|
2335 |
+
case 'bend':
|
2336 |
+
$delay = mt_rand(0, 15) / 100.0;
|
2337 |
+
$cents = mt_rand(-120, 120);
|
2338 |
+
$dur = mt_rand(75, 400) / 100.0;
|
2339 |
+
$outEffects[] = "$effect $delay,$cents,$dur";
|
2340 |
+
break;
|
2341 |
+
|
2342 |
+
case 'chorus':
|
2343 |
+
$gainIn = mt_rand(75, 90) / 100.0;
|
2344 |
+
$gainOut = mt_rand(70, 95) / 100.0;
|
2345 |
+
$chorStr = "$effect $gainIn $gainOut";
|
2346 |
+
|
2347 |
+
for ($i = 0; $i < mt_rand(2, 3); ++$i) {
|
2348 |
+
$delay = mt_rand(20, 100);
|
2349 |
+
$decay = mt_rand(10, 100) / 100.0;
|
2350 |
+
$speed = mt_rand(20, 50) / 100.0;
|
2351 |
+
$depth = mt_rand(150, 250) / 100.0;
|
2352 |
+
|
2353 |
+
$chorStr .= " $delay $decay $speed $depth -s";
|
2354 |
+
}
|
2355 |
+
|
2356 |
+
$outEffects[] = $chorStr;
|
2357 |
+
break;
|
2358 |
+
|
2359 |
+
case 'overdrive':
|
2360 |
+
|