1 | <?php
|
---|
2 |
|
---|
3 | /*
|
---|
4 | * This class is taken in part from the Code of
|
---|
5 | * PhpCaptcha CAPTCHA generation library from Edward Eliot.
|
---|
6 | * class defaults - change to effect globally
|
---|
7 | */
|
---|
8 | session_start();
|
---|
9 | define('CAPCC_WIDTH', 120); // max 500
|
---|
10 | define('CAPCC_HEIGHT', 50); // max 200
|
---|
11 | define('CAPCC_NUM_CHARS', 4);
|
---|
12 | define('CAPCC_NUM_LINES', 20);
|
---|
13 | define('CAPCC_CHAR_SHADOW', false);
|
---|
14 | define('CAPCC_CHAR_SET', ''); // defaults to A-Z
|
---|
15 | define('CAPCC_CASE_INSENSITIVE', true);
|
---|
16 | define('CAPCC_BACKGROUND_IMAGES', '');
|
---|
17 | define('CAPCC_MIN_FONT_SIZE', 12);
|
---|
18 | define('CAPCC_MAX_FONT_SIZE', 20);
|
---|
19 | define('CAPCC_USE_COLOUR', true);
|
---|
20 | define('CAPCC_FILE_TYPE', 'png');
|
---|
21 |
|
---|
22 | /************************ End Default Options **********************/
|
---|
23 |
|
---|
24 | // don't edit below this line (unless you want to change the class!)
|
---|
25 |
|
---|
26 | class _odl_captcha {
|
---|
27 | var $oImage;
|
---|
28 | var $iWidth = CAPCC_WIDTH;
|
---|
29 | var $iHeight = CAPCC_HEIGHT;
|
---|
30 | var $aFonts;
|
---|
31 | var $iNumChars;
|
---|
32 | var $iNumLines;
|
---|
33 | var $iSpacing;
|
---|
34 | var $bCharShadow;
|
---|
35 | var $aCharSet;
|
---|
36 | var $bCaseInsensitive;
|
---|
37 | var $vBackgroundImages;
|
---|
38 | var $iMinFontSize;
|
---|
39 | var $iMaxFontSize;
|
---|
40 | var $bUseColour;
|
---|
41 | var $sFileType;
|
---|
42 | var $sCode = '';
|
---|
43 |
|
---|
44 |
|
---|
45 | function _odl_captcha($aFonts) {
|
---|
46 | // get parameters
|
---|
47 | $this->aFonts = $aFonts;
|
---|
48 | $this->SetNumChars(CAPCC_NUM_CHARS);
|
---|
49 | $this->SetNumLines(CAPCC_NUM_LINES);
|
---|
50 | $this->DisplayShadow(CAPCC_CHAR_SHADOW);
|
---|
51 | $this->SetCharSet(CAPCC_CHAR_SET);
|
---|
52 | $this->CaseInsensitive(CAPCC_CASE_INSENSITIVE);
|
---|
53 | $this->SetBackgroundImages(CAPCC_BACKGROUND_IMAGES);
|
---|
54 | $this->SetMinFontSize(CAPCC_MIN_FONT_SIZE);
|
---|
55 | $this->SetMaxFontSize(CAPCC_MAX_FONT_SIZE);
|
---|
56 | $this->UseColour(CAPCC_USE_COLOUR);
|
---|
57 | $this->SetFileType(CAPCC_FILE_TYPE);
|
---|
58 | $this->SetWidth(CAPCC_WIDTH);
|
---|
59 | $this->SetHeight(CAPCC_HEIGHT);
|
---|
60 | }
|
---|
61 |
|
---|
62 | function CalculateSpacing() {
|
---|
63 | $this->iSpacing = (int)($this->iWidth / $this->iNumChars);
|
---|
64 | }
|
---|
65 |
|
---|
66 | function SetWidth($iWidth) {
|
---|
67 | $this->iWidth = $iWidth;
|
---|
68 | if ($this->iWidth > 500) $this->iWidth = 500; // to prevent perfomance impact
|
---|
69 | $this->CalculateSpacing();
|
---|
70 | }
|
---|
71 |
|
---|
72 | function SetHeight($iHeight) {
|
---|
73 | $this->iHeight = $iHeight;
|
---|
74 | if ($this->iHeight > 200) $this->iHeight = 200; // to prevent performance impact
|
---|
75 | }
|
---|
76 |
|
---|
77 | function SetNumChars($iNumChars) {
|
---|
78 | $this->iNumChars = $iNumChars;
|
---|
79 | $this->CalculateSpacing();
|
---|
80 | }
|
---|
81 |
|
---|
82 | function SetNumLines($iNumLines) {
|
---|
83 | $this->iNumLines = $iNumLines;
|
---|
84 | }
|
---|
85 |
|
---|
86 | function DisplayShadow($bCharShadow) {
|
---|
87 | $this->bCharShadow = $bCharShadow;
|
---|
88 | }
|
---|
89 |
|
---|
90 |
|
---|
91 | function SetCharSet($vCharSet) {
|
---|
92 | // check for input type
|
---|
93 | if (is_array($vCharSet)) {
|
---|
94 | $this->aCharSet = $vCharSet;
|
---|
95 | } else {
|
---|
96 | if ($vCharSet != '') {
|
---|
97 | // split items on commas
|
---|
98 | $aCharSet = explode(',', $vCharSet);
|
---|
99 | // initialise array
|
---|
100 | $this->aCharSet = array();
|
---|
101 | // loop through items
|
---|
102 | foreach ($aCharSet as $sCurrentItem) {
|
---|
103 | // a range should have 3 characters, otherwise is normal character
|
---|
104 | if (strlen($sCurrentItem) == 3) {
|
---|
105 | // split on range character
|
---|
106 | $aRange = explode('-', $sCurrentItem);
|
---|
107 | // check for valid range
|
---|
108 | if (count($aRange) == 2 && $aRange[0] < $aRange[1]) {
|
---|
109 | // create array of characters from range
|
---|
110 | $aRange = range($aRange[0], $aRange[1]);
|
---|
111 | // add to charset array
|
---|
112 | $this->aCharSet = array_merge($this->aCharSet, $aRange);
|
---|
113 | }
|
---|
114 | } else {
|
---|
115 | $this->aCharSet[] = $sCurrentItem;
|
---|
116 | }
|
---|
117 | }
|
---|
118 | }
|
---|
119 | }
|
---|
120 | }
|
---|
121 |
|
---|
122 | function CaseInsensitive($bCaseInsensitive) {
|
---|
123 | $this->bCaseInsensitive = $bCaseInsensitive;
|
---|
124 | }
|
---|
125 |
|
---|
126 | function SetBackgroundImages($vBackgroundImages) {
|
---|
127 | $this->vBackgroundImages = $vBackgroundImages;
|
---|
128 | }
|
---|
129 |
|
---|
130 | function SetMinFontSize($iMinFontSize) {
|
---|
131 | $this->iMinFontSize = $iMinFontSize;
|
---|
132 | }
|
---|
133 |
|
---|
134 | function SetMaxFontSize($iMaxFontSize) {
|
---|
135 | $this->iMaxFontSize = $iMaxFontSize;
|
---|
136 | }
|
---|
137 |
|
---|
138 | function UseColour($bUseColour) {
|
---|
139 | $this->bUseColour = $bUseColour;
|
---|
140 | }
|
---|
141 |
|
---|
142 | function SetFileType($sFileType) {
|
---|
143 | // check for valid file type
|
---|
144 | if (in_array($sFileType, array('gif', 'png', 'jpeg'))) {
|
---|
145 | $this->sFileType = $sFileType;
|
---|
146 | } else {
|
---|
147 | $this->sFileType = 'jpeg';
|
---|
148 | }
|
---|
149 | }
|
---|
150 |
|
---|
151 | function DrawLines() {
|
---|
152 | for ($i = 0; $i < $this->iNumLines; $i++) {
|
---|
153 | // allocate colour
|
---|
154 | if ($this->bUseColour) {
|
---|
155 | $iLineColour = imagecolorallocate($this->oImage, rand(100, 250), rand(100, 250), rand(100, 250));
|
---|
156 | } else {
|
---|
157 | $iRandColour = rand(100, 250);
|
---|
158 | $iLineColour = imagecolorallocate($this->oImage, $iRandColour, $iRandColour, $iRandColour);
|
---|
159 | }
|
---|
160 | // draw line
|
---|
161 | imageline($this->oImage, rand(0, $this->iWidth), rand(0, $this->iHeight), rand(0, $this->iWidth), rand(0, $this->iHeight), $iLineColour);
|
---|
162 | }
|
---|
163 | }
|
---|
164 |
|
---|
165 | function GenerateCode() {
|
---|
166 | // reset code
|
---|
167 | $this->sCode = '';
|
---|
168 | // loop through and generate the code letter by letter
|
---|
169 | for ($i = 0; $i < $this->iNumChars; $i++) {
|
---|
170 | if (count($this->aCharSet) > 0) {
|
---|
171 | // select random character and add to code string
|
---|
172 | $this->sCode .= $this->aCharSet[array_rand($this->aCharSet)];
|
---|
173 | } else {
|
---|
174 | // select random character and add to code string
|
---|
175 | $this->sCode .= chr(rand(65, 90));
|
---|
176 | }
|
---|
177 | }
|
---|
178 | // save code in session variable
|
---|
179 | if ($this->bCaseInsensitive) {
|
---|
180 | $_SESSION[CAPCC_SESSION_ID] = strtoupper($this->sCode);
|
---|
181 | } else {
|
---|
182 | $_SESSION[CAPCC_SESSION_ID] = $this->sCode;
|
---|
183 | }
|
---|
184 | }
|
---|
185 |
|
---|
186 | function DrawCharacters() {
|
---|
187 | // loop through and write out selected number of characters
|
---|
188 | for ($i = 0; $i < strlen($this->sCode); $i++) {
|
---|
189 | // select random font
|
---|
190 | $sCurrentFont = $this->aFonts[array_rand($this->aFonts)];
|
---|
191 | // select random colour
|
---|
192 | if ($this->bUseColour) {
|
---|
193 | $iTextColour = imagecolorallocate($this->oImage, rand(0, 100), rand(0, 100), rand(0, 100));
|
---|
194 | if ($this->bCharShadow) {
|
---|
195 | // shadow colour
|
---|
196 | $iShadowColour = imagecolorallocate($this->oImage, rand(0, 100), rand(0, 100), rand(0, 100));
|
---|
197 | }
|
---|
198 | } else {
|
---|
199 | $iRandColour = rand(0, 100);
|
---|
200 | $iTextColour = imagecolorallocate($this->oImage, $iRandColour, $iRandColour, $iRandColour);
|
---|
201 | if ($this->bCharShadow) {
|
---|
202 | // shadow colour
|
---|
203 | $iRandColour = rand(0, 100);
|
---|
204 | $iShadowColour = imagecolorallocate($this->oImage, $iRandColour, $iRandColour, $iRandColour);
|
---|
205 | }
|
---|
206 | }
|
---|
207 | // select random font size
|
---|
208 | $iFontSize = rand($this->iMinFontSize, $this->iMaxFontSize);
|
---|
209 | // select random angle
|
---|
210 | $iAngle = rand(-30, 30);
|
---|
211 | // get dimensions of character in selected font and text size
|
---|
212 | $aCharDetails = imageftbbox($iFontSize, $iAngle, $sCurrentFont, $this->sCode[$i], array());
|
---|
213 | // calculate character starting coordinates
|
---|
214 | $iX = $this->iSpacing / 4 + $i * $this->iSpacing;
|
---|
215 | $iCharHeight = $aCharDetails[2] - $aCharDetails[5];
|
---|
216 | $iY = $this->iHeight / 2 + $iCharHeight / 4;
|
---|
217 | // write text to image
|
---|
218 | imagefttext($this->oImage, $iFontSize, $iAngle, $iX, $iY, $iTextColour, $sCurrentFont, $this->sCode[$i], array());
|
---|
219 | if ($this->bCharShadow) {
|
---|
220 | $iOffsetAngle = rand(-30, 30);
|
---|
221 | $iRandOffsetX = rand(-5, 5);
|
---|
222 | $iRandOffsetY = rand(-5, 5);
|
---|
223 | imagefttext($this->oImage, $iFontSize, $iOffsetAngle, $iX + $iRandOffsetX, $iY + $iRandOffsetY, $iShadowColour, $sCurrentFont, $this->sCode[$i], array());
|
---|
224 | }
|
---|
225 | }
|
---|
226 | }
|
---|
227 |
|
---|
228 | function create($sFilename = '') {
|
---|
229 | // check for required gd functions
|
---|
230 | if (!function_exists('imagecreate') ||
|
---|
231 | !function_exists("image$this->sFileType") || ($this->vBackgroundImages != '' && !function_exists('imagecreatetruecolor'))) {
|
---|
232 | return false;
|
---|
233 | }
|
---|
234 | // get background image if specified and copy to CAPTCHA
|
---|
235 | if (is_array($this->vBackgroundImages) || $this->vBackgroundImages != '') {
|
---|
236 | // create new image
|
---|
237 | $this->oImage = imagecreatetruecolor($this->iWidth, $this->iHeight);
|
---|
238 | // create background image
|
---|
239 | if (is_array($this->vBackgroundImages)) {
|
---|
240 | $iRandImage = array_rand($this->vBackgroundImages);
|
---|
241 | $oBackgroundImage = imagecreatefromjpeg($this->vBackgroundImages[$iRandImage]);
|
---|
242 | } else {
|
---|
243 | $oBackgroundImage = imagecreatefromjpeg($this->vBackgroundImages);
|
---|
244 | }
|
---|
245 | // copy background image
|
---|
246 | imagecopy($this->oImage, $oBackgroundImage, 0, 0, 0, 0, $this->iWidth, $this->iHeight);
|
---|
247 | // free memory used to create background image
|
---|
248 | imagedestroy($oBackgroundImage);
|
---|
249 | } else {
|
---|
250 | // create new image
|
---|
251 | $this->oImage = imagecreate($this->iWidth, $this->iHeight);
|
---|
252 | //$this->oImage = imagecreatetruecolor($this->iWidth, $this->iHeight);
|
---|
253 | }
|
---|
254 | // allocate white background colour
|
---|
255 | imagecolorallocate($this->oImage, 255, 255, 255);
|
---|
256 | // check for background image before drawing lines
|
---|
257 | if (!is_array($this->vBackgroundImages) && $this->vBackgroundImages == '') {
|
---|
258 | $this->DrawLines();
|
---|
259 | }
|
---|
260 | $this->GenerateCode();
|
---|
261 | $this->DrawCharacters();
|
---|
262 | // write out image to file or browser
|
---|
263 | $this->WriteFile($sFilename);
|
---|
264 | // free memory used in creating image
|
---|
265 | imagedestroy($this->oImage);
|
---|
266 | return true;
|
---|
267 | }
|
---|
268 |
|
---|
269 | function WriteFile($sFilename) {
|
---|
270 | if ($sFilename == '') {
|
---|
271 | // tell browser that data is jpeg
|
---|
272 | header("Content-type: image/" . $this->sFileType );
|
---|
273 | }
|
---|
274 | switch ($this->sFileType) {
|
---|
275 | case 'gif':
|
---|
276 | $sFilename != '' ? imagegif($this->oImage, $sFilename) : imagegif($this->oImage);
|
---|
277 | break;
|
---|
278 | case 'png':
|
---|
279 | $sFilename != '' ? imagepng($this->oImage, $sFilename) : imagepng($this->oImage);
|
---|
280 | break;
|
---|
281 | default:
|
---|
282 | $sFilename != '' ? imagejpeg($this->oImage, $sFilename) : imagejpeg($this->oImage);
|
---|
283 | }
|
---|
284 | }
|
---|
285 |
|
---|
286 | // call this method statically
|
---|
287 | function Validate($sUserCode, $bCaseInsensitive = true) {
|
---|
288 | if ($bCaseInsensitive) {
|
---|
289 | $sUserCode = strtoupper($sUserCode);
|
---|
290 | }
|
---|
291 | if (!empty($_SESSION[CAPCC_SESSION_ID]) && $sUserCode == $_SESSION[CAPCC_SESSION_ID]) {
|
---|
292 | // clear to prevent re-use
|
---|
293 | unset($_SESSION[CAPCC_SESSION_ID]);
|
---|
294 | return true;
|
---|
295 | }
|
---|
296 | return false;
|
---|
297 | }
|
---|
298 | }
|
---|
299 |
|
---|
300 | // example sub class
|
---|
301 | class _odl_captchaColour extends _odl_captcha {
|
---|
302 | function _odl_captchaColour($aFonts) {
|
---|
303 | // call parent constructor
|
---|
304 | parent::_odl_captcha($aFonts);
|
---|
305 |
|
---|
306 | // set options
|
---|
307 | $this->UseColour(true);
|
---|
308 | }
|
---|
309 | }
|
---|
310 | ?>
|
---|