1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Image Creation script |
4
|
|
|
* |
5
|
|
|
* D.J. |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
include dirname(dirname(dirname(dirname(dirname(__DIR__))))) . '/mainfile.php'; |
9
|
|
|
error_reporting(0); |
10
|
|
|
$xoopsLogger->activated = false; |
11
|
|
|
|
12
|
|
|
if (empty(Request::getString('HTTP_REFERER', '', 'SERVER')) || !preg_match('/^' . preg_quote(XOOPS_URL, '/') . '/', Request::getString('HTTP_REFERER', '', 'SERVER'))) { |
13
|
|
|
exit(); |
14
|
|
|
} |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Class XoopsCaptchaImageHandler |
18
|
|
|
*/ |
19
|
|
|
class XoopsCaptchaImageHandler |
20
|
|
|
{ |
21
|
|
|
public $config = []; |
22
|
|
|
//var $mode = "gd"; // GD or bmp |
23
|
|
|
public $code; |
24
|
|
|
public $invalid = false; |
25
|
|
|
|
26
|
|
|
public $font; |
27
|
|
|
public $spacing; |
28
|
|
|
public $width; |
29
|
|
|
public $height; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* XoopsCaptchaImageHandler constructor. |
33
|
|
|
*/ |
34
|
|
|
public function __construct() |
35
|
|
|
{ |
36
|
|
|
if (empty($_SESSION['XoopsCaptcha_name'])) { |
37
|
|
|
$this->invalid = true; |
38
|
|
|
} |
39
|
|
|
|
40
|
|
View Code Duplication |
if (!extension_loaded('gd')) { |
|
|
|
|
41
|
|
|
$this->mode = 'bmp'; |
|
|
|
|
42
|
|
|
} else { |
43
|
|
|
$required_functions = [ |
44
|
|
|
'imagecreatetruecolor', |
45
|
|
|
'imagecolorallocate', |
46
|
|
|
'imagefilledrectangle', |
47
|
|
|
'imagejpeg', |
48
|
|
|
'imagedestroy', |
49
|
|
|
'imageftbbox' |
50
|
|
|
]; |
51
|
|
|
foreach ($required_functions as $func) { |
52
|
|
|
if (!function_exists($func)) { |
53
|
|
|
$this->mode = 'bmp'; |
54
|
|
|
break; |
55
|
|
|
} |
56
|
|
|
} |
57
|
|
|
} |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Loading configs from CAPTCHA class |
62
|
|
|
* @param array $config |
63
|
|
|
*/ |
64
|
|
|
public function setConfig($config = []) |
65
|
|
|
{ |
66
|
|
|
// Loading default preferences |
67
|
|
|
$this->config = $config; |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
public function loadImage() |
71
|
|
|
{ |
72
|
|
|
$this->createCode(); |
73
|
|
|
$this->setCode(); |
74
|
|
|
$this->createImage(); |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* Create Code |
79
|
|
|
*/ |
80
|
|
|
public function createCode() |
81
|
|
|
{ |
82
|
|
|
if ($this->invalid) { |
83
|
|
|
return; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
if ('bmp' === $this->mode) { |
87
|
|
|
$this->config['num_chars'] = 4; |
88
|
|
|
$this->code = mt_rand(pow(10, $this->config['num_chars'] - 1), (int)str_pad('9', $this->config['num_chars'], '9')); |
89
|
|
|
} else { |
90
|
|
|
$this->code = substr(md5(uniqid(mt_rand(), 1)), 0, $this->config['num_chars']); |
91
|
|
|
if (!$this->config['casesensitive']) { |
92
|
|
|
$this->code = strtoupper($this->code); |
93
|
|
|
} |
94
|
|
|
} |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
public function setCode() |
98
|
|
|
{ |
99
|
|
|
if ($this->invalid) { |
100
|
|
|
return; |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
$_SESSION['XoopsCaptcha_sessioncode'] = (string)$this->code; |
104
|
|
|
$maxAttempts = (int)(@$_SESSION['XoopsCaptcha_maxattempts']); |
105
|
|
|
|
106
|
|
|
// Increase the attempt records on refresh |
107
|
|
|
if (!empty($maxAttempts)) { |
108
|
|
|
$_SESSION['XoopsCaptcha_attempt_' . $_SESSION['XoopsCaptcha_name']]++; |
109
|
|
|
if ($_SESSION['XoopsCaptcha_attempt_' . $_SESSION['XoopsCaptcha_name']] > $maxAttempts) { |
110
|
|
|
$this->invalid = true; |
111
|
|
|
} |
112
|
|
|
} |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* @param string $file |
117
|
|
|
* @return string|void |
118
|
|
|
*/ |
119
|
|
|
public function createImage($file = '') |
|
|
|
|
120
|
|
|
{ |
121
|
|
|
if ($this->invalid) { |
122
|
|
|
header('Content-type: image/gif'); |
123
|
|
|
readfile(XOOPS_ROOT_PATH . '/images/subject/icon2.gif'); |
124
|
|
|
|
125
|
|
|
return; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
if ('bmp' === $this->mode) { |
129
|
|
|
return $this->createImageBmp(); |
130
|
|
|
} else { |
131
|
|
|
return $this->createImageGd(); |
132
|
|
|
} |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* Create CAPTCHA iamge with GD |
137
|
|
|
* Originated from DuGris' SecurityImage |
138
|
|
|
* @param string $file |
139
|
|
|
*/ |
140
|
|
|
// --------------------------------------------------------------------------- // |
141
|
|
|
// Class: SecurityImage 1.5 // |
142
|
|
|
// Author: DuGris aka L. Jen <http://www.dugris.info> // |
143
|
|
|
// Email: [email protected] // |
144
|
|
|
// Licence: GNU // |
145
|
|
|
// Project: XOOPS Project // |
146
|
|
|
// --------------------------------------------------------------------------- // |
147
|
|
|
public function createImageGd($file = '') |
148
|
|
|
{ |
149
|
|
|
$this->loadFont(); |
150
|
|
|
$this->setImageSize(); |
151
|
|
|
|
152
|
|
|
$this->oImage = imagecreatetruecolor($this->width, $this->height); |
|
|
|
|
153
|
|
|
$background = imagecolorallocate($this->oImage, 255, 255, 255); |
154
|
|
|
imagefilledrectangle($this->oImage, 0, 0, $this->width, $this->height, $background); |
155
|
|
|
|
156
|
|
|
switch ($this->config['background_type']) { |
157
|
|
|
default: |
158
|
|
|
case 0: |
159
|
|
|
$this->drawBars(); |
160
|
|
|
break; |
161
|
|
|
|
162
|
|
|
case 1: |
163
|
|
|
$this->drawCircles(); |
164
|
|
|
break; |
165
|
|
|
|
166
|
|
|
case 2: |
167
|
|
|
$this->drawLines(); |
168
|
|
|
break; |
169
|
|
|
|
170
|
|
|
case 3: |
171
|
|
|
$this->drawRectangles(); |
172
|
|
|
break; |
173
|
|
|
|
174
|
|
|
case 4: |
175
|
|
|
$this->drawEllipses(); |
176
|
|
|
break; |
177
|
|
|
|
178
|
|
|
case 5: |
179
|
|
|
$this->drawPolygons(); |
180
|
|
|
break; |
181
|
|
|
|
182
|
|
|
case 100: |
183
|
|
|
$this->createFromFile(); |
184
|
|
|
break; |
185
|
|
|
} |
186
|
|
|
$this->drawBorder(); |
187
|
|
|
$this->drawCode(); |
188
|
|
|
|
189
|
|
|
if (empty($file)) { |
190
|
|
|
header('Content-type: image/jpeg'); |
191
|
|
|
imagejpeg($this->oImage); |
192
|
|
|
} else { |
193
|
|
|
imagejpeg($this->oImage, XOOPS_ROOT_PATH . '/' . $this->config['imagepath'] . '/' . $file . '.jpg'); |
194
|
|
|
} |
195
|
|
|
imagedestroy($this->oImage); |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* @param $name |
200
|
|
|
* @param string $extension |
201
|
|
|
* @return array |
202
|
|
|
*/ |
203
|
|
|
public function _getList($name, $extension = '') |
204
|
|
|
{ |
205
|
|
|
$items = []; |
206
|
|
|
/* |
207
|
|
|
if (@ require_once XOOPS_ROOT_PATH."/Frameworks/art/functions.ini.php") { |
208
|
|
|
load_functions("cache"); |
209
|
|
|
if ($items = mod_loadCacheFile("captcha_{$name}", "captcha")) { |
210
|
|
|
return $items; |
211
|
|
|
} |
212
|
|
|
} |
213
|
|
|
*/ |
214
|
|
|
require_once XOOPS_ROOT_PATH . '/class/xoopslists.php'; |
215
|
|
|
$file_path = $this->config['rootpath'] . "/{$name}"; |
216
|
|
|
$files = XoopsLists::getFileListAsArray($file_path); |
217
|
|
|
foreach ($files as $item) { |
218
|
|
|
if (empty($extension) || preg_match("/(\.{$extension})$/i", $item)) { |
219
|
|
|
$items[] = $item; |
220
|
|
|
} |
221
|
|
|
} |
222
|
|
|
if (function_exists('mod_createCacheFile')) { |
223
|
|
|
mod_createCacheFile($items, "captcha_{$name}", 'captcha'); |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
return $items; |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
public function loadFont() |
230
|
|
|
{ |
231
|
|
|
$fonts = $this->_getList('fonts', 'ttf'); |
232
|
|
|
$this->font = $this->config['rootpath'] . '/fonts/' . $fonts[array_rand($fonts)]; |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
public function setImageSize() |
236
|
|
|
{ |
237
|
|
|
$MaxCharWidth = 0; |
238
|
|
|
$MaxCharHeight = 0; |
239
|
|
|
$oImage = imagecreatetruecolor(100, 100); |
240
|
|
|
$text_color = imagecolorallocate($oImage, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100)); |
|
|
|
|
241
|
|
|
$FontSize = $this->config['fontsize_max']; |
242
|
|
|
for ($Angle = -30; $Angle <= 30; ++$Angle) { |
243
|
|
|
for ($i = 65; $i <= 90; ++$i) { |
244
|
|
|
$CharDetails = imageftbbox($FontSize, $Angle, $this->font, chr($i), []); |
245
|
|
|
$_MaxCharWidth = abs($CharDetails[0] + $CharDetails[2]); |
246
|
|
|
if ($_MaxCharWidth > $MaxCharWidth) { |
247
|
|
|
$MaxCharWidth = $_MaxCharWidth; |
248
|
|
|
} |
249
|
|
|
$_MaxCharHeight = abs($CharDetails[1] + $CharDetails[5]); |
250
|
|
|
if ($_MaxCharHeight > $MaxCharHeight) { |
251
|
|
|
$MaxCharHeight = $_MaxCharHeight; |
252
|
|
|
} |
253
|
|
|
} |
254
|
|
|
} |
255
|
|
|
imagedestroy($oImage); |
256
|
|
|
|
257
|
|
|
$this->height = $MaxCharHeight + 2; |
258
|
|
|
$this->spacing = (int)(($this->config['num_chars'] * $MaxCharWidth) / $this->config['num_chars']); |
259
|
|
|
$this->width = ($this->config['num_chars'] * $MaxCharWidth) + ($this->spacing / 2); |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* Return random background |
264
|
|
|
* |
265
|
|
|
* @return null|string |
266
|
|
|
*/ |
267
|
|
|
public function loadBackground() |
268
|
|
|
{ |
269
|
|
|
$RandBackground = null; |
270
|
|
|
if ($backgrounds = $this->_getList('backgrounds', '(gif|jpg|png)')) { |
271
|
|
|
$RandBackground = $this->config['rootpath'] . '/backgrounds/' . $backgrounds[array_rand($backgrounds)]; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
return $RandBackground; |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
/** |
278
|
|
|
* Draw Image background |
279
|
|
|
*/ |
280
|
|
|
public function createFromFile() |
281
|
|
|
{ |
282
|
|
|
if ($RandImage = $this->loadBackground()) { |
283
|
|
|
$ImageType = @getimagesize($RandImage); |
284
|
|
|
switch (@$ImageType[2]) { |
285
|
|
|
case 1: |
286
|
|
|
$BackgroundImage = imagecreatefromgif($RandImage); |
287
|
|
|
break; |
288
|
|
|
|
289
|
|
|
case 2: |
290
|
|
|
$BackgroundImage = imagecreatefromjpeg($RandImage); |
291
|
|
|
break; |
292
|
|
|
|
293
|
|
|
case 3: |
294
|
|
|
$BackgroundImage = imagecreatefrompng($RandImage); |
295
|
|
|
break; |
296
|
|
|
} |
297
|
|
|
} |
298
|
|
|
if (!empty($BackgroundImage)) { |
299
|
|
|
imagecopyresized($this->oImage, $BackgroundImage, 0, 0, 0, 0, imagesx($this->oImage), imagesy($this->oImage), imagesx($BackgroundImage), imagesy($BackgroundImage)); |
300
|
|
|
imagedestroy($BackgroundImage); |
301
|
|
|
} else { |
302
|
|
|
$this->drawBars(); |
303
|
|
|
} |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
/** |
307
|
|
|
* Draw Code |
308
|
|
|
*/ |
309
|
|
|
public function drawCode() |
310
|
|
|
{ |
311
|
|
|
for ($i = 0; $i < $this->config['num_chars']; ++$i) { |
312
|
|
|
// select random greyscale colour |
313
|
|
|
$text_color = imagecolorallocate($this->oImage, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100)); |
314
|
|
|
|
315
|
|
|
// write text to image |
316
|
|
|
$Angle = mt_rand(10, 30); |
317
|
|
|
if ($i % 2) { |
318
|
|
|
$Angle = mt_rand(-10, -30); |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
// select random font size |
322
|
|
|
$FontSize = mt_rand($this->config['fontsize_min'], $this->config['fontsize_max']); |
323
|
|
|
|
324
|
|
|
$CharDetails = imageftbbox($FontSize, $Angle, $this->font, $this->code[$i], []); |
325
|
|
|
$CharHeight = abs($CharDetails[1] + $CharDetails[5]); |
326
|
|
|
|
327
|
|
|
// calculate character starting coordinates |
328
|
|
|
$posX = ($this->spacing / 2) + ($i * $this->spacing); |
329
|
|
|
$posY = 2 + ($this->height / 2) + ($CharHeight / 4); |
330
|
|
|
|
331
|
|
|
imagefttext($this->oImage, $FontSize, $Angle, $posX, $posY, $text_color, $this->font, $this->code[$i], []); |
332
|
|
|
} |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
/** |
336
|
|
|
* Draw Border |
337
|
|
|
*/ |
338
|
|
|
public function drawBorder() |
339
|
|
|
{ |
340
|
|
|
$rgb = mt_rand(50, 150); |
341
|
|
|
$border_color = imagecolorallocate($this->oImage, $rgb, $rgb, $rgb); |
342
|
|
|
imagerectangle($this->oImage, 0, 0, $this->width - 1, $this->height - 1, $border_color); |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
/** |
346
|
|
|
* Draw Circles background |
347
|
|
|
*/ |
348
|
|
|
public function drawCircles() |
349
|
|
|
{ |
350
|
|
|
for ($i = 1; $i <= $this->config['background_num']; ++$i) { |
351
|
|
|
$randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255)); |
352
|
|
|
imagefilledellipse($this->oImage, mt_rand(0, $this->width - 10), mt_rand(0, $this->height - 3), mt_rand(10, 20), mt_rand(20, 30), $randomcolor); |
353
|
|
|
} |
354
|
|
|
} |
355
|
|
|
|
356
|
|
|
/** |
357
|
|
|
* Draw Lines background |
358
|
|
|
*/ |
359
|
|
View Code Duplication |
public function drawLines() |
|
|
|
|
360
|
|
|
{ |
361
|
|
|
for ($i = 0; $i < $this->config['background_num']; ++$i) { |
362
|
|
|
$randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255)); |
363
|
|
|
imageline($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor); |
364
|
|
|
} |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
/** |
368
|
|
|
* Draw Rectangles background |
369
|
|
|
*/ |
370
|
|
View Code Duplication |
public function drawRectangles() |
|
|
|
|
371
|
|
|
{ |
372
|
|
|
for ($i = 1; $i <= $this->config['background_num']; ++$i) { |
373
|
|
|
$randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255)); |
374
|
|
|
imagefilledrectangle($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor); |
375
|
|
|
} |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
/** |
379
|
|
|
* Draw Bars background |
380
|
|
|
*/ |
381
|
|
|
public function drawBars() |
382
|
|
|
{ |
383
|
|
View Code Duplication |
for ($i = 0; $i <= $this->height;) { |
|
|
|
|
384
|
|
|
$randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255)); |
385
|
|
|
imageline($this->oImage, 0, $i, $this->width, $i, $randomcolor); |
386
|
|
|
$i += 2.5; |
387
|
|
|
} |
388
|
|
View Code Duplication |
for ($i = 0; $i <= $this->width;) { |
|
|
|
|
389
|
|
|
$randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255)); |
390
|
|
|
imageline($this->oImage, $i, 0, $i, $this->height, $randomcolor); |
391
|
|
|
$i += 2.5; |
392
|
|
|
} |
393
|
|
|
} |
394
|
|
|
|
395
|
|
|
/** |
396
|
|
|
* Draw Ellipses background |
397
|
|
|
*/ |
398
|
|
View Code Duplication |
public function drawEllipses() |
|
|
|
|
399
|
|
|
{ |
400
|
|
|
for ($i = 1; $i <= $this->config['background_num']; ++$i) { |
401
|
|
|
$randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255)); |
402
|
|
|
imageellipse($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor); |
403
|
|
|
} |
404
|
|
|
} |
405
|
|
|
|
406
|
|
|
/** |
407
|
|
|
* Draw polygons background |
408
|
|
|
*/ |
409
|
|
|
public function drawPolygons() |
410
|
|
|
{ |
411
|
|
|
for ($i = 1; $i <= $this->config['background_num']; ++$i) { |
412
|
|
|
$randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255)); |
413
|
|
|
$coords = []; |
414
|
|
|
for ($j = 1; $j <= $this->config['polygon_point']; ++$j) { |
415
|
|
|
$coords[] = mt_rand(0, $this->width); |
416
|
|
|
$coords[] = mt_rand(0, $this->height); |
417
|
|
|
} |
418
|
|
|
imagefilledpolygon($this->oImage, $coords, $this->config['polygon_point'], $randomcolor); |
419
|
|
|
} |
420
|
|
|
} |
421
|
|
|
|
422
|
|
|
/** |
423
|
|
|
* Create CAPTCHA iamge with BMP |
424
|
|
|
* TODO |
425
|
|
|
* @param string $file |
426
|
|
|
* @return string |
427
|
|
|
*/ |
428
|
|
|
public function createImageBmp($file = '') |
429
|
|
|
{ |
430
|
|
|
$image = ''; |
431
|
|
|
|
432
|
|
|
if (empty($file)) { |
433
|
|
|
header('Content-type: image/bmp'); |
434
|
|
|
echo $image; |
435
|
|
|
} else { |
436
|
|
|
return $image; |
437
|
|
|
} |
438
|
|
|
} |
439
|
|
|
} |
440
|
|
|
|
441
|
|
|
$config = @include __DIR__ . '/../config.php'; |
442
|
|
|
$imageHandler = new \XoopsCaptchaImageHandler(); |
443
|
|
|
$imageHandler->setConfig($config); |
444
|
|
|
$imageHandler->loadImage(); |
445
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.