XoopsCaptchaImageHandler   F
last analyzed

Complexity

Total Complexity 60

Size/Duplication

Total Lines 387
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 178
c 0
b 0
f 0
dl 0
loc 387
rs 3.6
wmc 60

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A loadImage() 0 4 1
A generateCode() 0 24 5
A getList() 0 19 5
A createImage() 0 13 3
A createImageBmp() 0 11 2
A drawBorder() 0 5 1
A drawEllipses() 0 5 2
B createFromFile() 0 25 7
A drawCode() 0 23 3
A loadFont() 0 4 1
B createImageGd() 0 54 10
A setImageSize() 0 25 5
A drawPolygons() 0 10 3
A loadBackground() 0 8 2
A drawRectangles() 0 5 2
A drawCircles() 0 5 2
A drawLines() 0 5 2
A drawBars() 0 11 3

How to fix   Complexity   

Complex Class

Complex classes like XoopsCaptchaImageHandler often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use XoopsCaptchaImageHandler, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * CAPTCHA class For XOOPS
4
 *
5
 * You may not change or alter any portion of this comment or credits
6
 * of supporting developers from this source code or any supporting source code
7
 * which is considered copyrighted (c) material of the original comment or credit authors.
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * @copyright       (c) 2000-2021 XOOPS Project (https://xoops.org)
13
 * @license             GNU GPL 2 (https://www.gnu.org/licenses/gpl-2.0.html)
14
 * @since               2.3.0
15
 * @author              Taiwen Jiang <[email protected]>
16
 * @package             class
17
 * @subpackage          CAPTCHA
18
 */
19
20
include __DIR__  . '/../../../../mainfile.php';
21
22
error_reporting(0);
23
$xoopsLogger->activated = false;
24
25
/**
26
 * Class XoopsCaptchaImageHandler
27
 */
28
class XoopsCaptchaImageHandler
29
{
30
    public $config  = array();
31
    public $code;
32
    public $mode    = 'gd';
33
    public $invalid = false;
34
35
    public $oImage;
36
    public $font;
37
    public $spacing;
38
    public $width;
39
    public $height;
40
41
    public $captchaHandler;
42
43
    /**
44
     *
45
     */
46
    public function __construct()
47
    {
48
        xoops_load('XoopsCaptcha');
49
        $this->captchaHandler = XoopsCaptcha::getInstance();
50
        $this->config          = $this->captchaHandler->loadConfig('image');
51
    }
52
53
    public function loadImage()
54
    {
55
        $this->generateCode();
56
        $this->createImage();
57
    }
58
59
    /**
60
     * Create Code
61
     */
62
    public function generateCode()
63
    {
64
        if ($this->invalid) {
65
            return false;
66
        }
67
68
        if ($this->mode === 'bmp') {
69
            $this->config['num_chars'] = 4;
70
            $this->code                = mt_rand(pow(10, $this->config['num_chars'] - 1), (int)str_pad('9', $this->config['num_chars'], '9'));
71
        } else {
72
            $raw_code = md5(uniqid(mt_rand(), true));
73
            if (!empty($this->config['skip_characters'])) {
74
                $valid_code = str_replace($this->config['skip_characters'], '', $raw_code);
75
                $this->code = substr($valid_code, 0, $this->config['num_chars']);
76
            } else {
77
                $this->code = substr($raw_code, 0, $this->config['num_chars']);
78
            }
79
            if (!$this->config['casesensitive']) {
80
                $this->code = strtoupper($this->code);
81
            }
82
        }
83
        $this->captchaHandler->setCode($this->code);
84
85
        return true;
86
    }
87
88
    /**
89
     * @return string|bool
90
     */
91
    public function createImage()
92
    {
93
        if ($this->invalid) {
94
            header('Content-type: image/gif');
95
            readfile(XOOPS_ROOT_PATH . '/images/subject/icon2.gif');
96
97
            return null;
98
        }
99
100
        if ($this->mode === 'bmp') {
101
            return $this->createImageBmp();
102
        } else {
103
            return $this->createImageGd();
104
        }
105
    }
106
107
    /**
108
     * @param string $name
109
     * @param string $extension
110
     *
111
     * @return array|mixed
112
     */
113
    public function getList($name, $extension = '')
114
    {
115
        xoops_load('XoopsCache');
116
        if ($items = XoopsCache::read("captcha_captcha_{$name}")) {
117
            return $items;
118
        }
119
120
        require_once XOOPS_ROOT_PATH . '/class/xoopslists.php';
121
        $file_path = XOOPS_ROOT_PATH . "/class/captcha/image/{$name}";
122
        $files     = XoopsLists::getFileListAsArray($file_path);
123
        $items = array();
124
        foreach ($files as $item) {
125
            if (empty($extension) || preg_match("/(\.{$extension})$/i", $item)) {
126
                $items[] = $item;
127
            }
128
        }
129
        XoopsCache::write("captcha_captcha_{$name}", $items);
130
131
        return $items;
132
    }
133
134
    /**
135
     *  Create CAPTCHA iamge with GD
136
     *  Originated by DuGris' SecurityImage
137
     *  --------------------------------------------------------------------------- //
138
     *  Class : SecurityImage 1.5                                                    //
139
     *  Author: DuGris aka L. Jen <http://www.dugris.info>                            //
140
     *  Email : [email protected]                                                    //
141
     *  Licence: GNU                                                                    //
142
     *  Project: The XOOPS Project                                                    //
143
     *  --------------------------------------------------------------------------- //
144
     */
145
    public function createImageGd()
146
    {
147
        $this->loadFont();
148
        $this->setImageSize();
149
150
        $this->oImage = imagecreatetruecolor((int)$this->width, (int)$this->height);
151
        $background   = imagecolorallocate($this->oImage, 255, 255, 255);
152
        imagefilledrectangle($this->oImage, 0, 0, (int)$this->width, (int)$this->height, $background);
153
154
        switch ($this->config['background_type']) {
155
            default:
156
            case 0:
157
                $this->drawBars();
158
                break;
159
160
            case 1:
161
                $this->drawCircles();
162
                break;
163
164
            case 2:
165
                $this->drawLines();
166
                break;
167
168
            case 3:
169
                $this->drawRectangles();
170
                break;
171
172
            case 4:
173
                $this->drawEllipses();
174
                break;
175
176
            case 5:
177
                $this->drawPolygons();
178
                break;
179
180
            case 100:
181
                $this->createFromFile();
182
                break;
183
        }
184
        $this->drawBorder();
185
        $this->drawCode();
186
187
        header('Content-type: image/jpeg');
188
        if (!imagejpeg($this->oImage)) {
189
            // Log or handle the error as you see fit
190
            return false;
191
        }
192
193
        if (!imagedestroy($this->oImage)) {
194
            // Log or handle the error as you see fit
195
            return false;
196
        }
197
198
        return true;
199
    }
200
201
    public function loadFont()
202
    {
203
        $fonts      = $this->getList('fonts', 'ttf');
204
        $this->font = XOOPS_ROOT_PATH . '/class/captcha/image/fonts/' . $fonts[array_rand($fonts)];
205
    }
206
207
    public function setImageSize()
208
    {
209
        $MaxCharWidth  = 0;
210
        $MaxCharHeight = 0;
211
        $oImage        = imagecreatetruecolor(100, 100);
212
        $text_color    = imagecolorallocate($oImage, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100));
0 ignored issues
show
Unused Code introduced by
The assignment to $text_color is dead and can be removed.
Loading history...
213
        $FontSize      = $this->config['fontsize_max'];
214
        for ($Angle = -30; $Angle <= 30; ++$Angle) {
215
            for ($i = 65; $i <= 90; ++$i) {
216
                $CharDetails   = imageftbbox($FontSize, $Angle, $this->font, chr($i), array());
217
                $_MaxCharWidth = abs($CharDetails[0] + $CharDetails[2]);
218
                if ($_MaxCharWidth > $MaxCharWidth) {
219
                    $MaxCharWidth = $_MaxCharWidth;
220
                }
221
                $_MaxCharHeight = abs($CharDetails[1] + $CharDetails[5]);
222
                if ($_MaxCharHeight > $MaxCharHeight) {
223
                    $MaxCharHeight = $_MaxCharHeight;
224
                }
225
            }
226
        }
227
        imagedestroy($oImage);
228
229
        $this->height  = $MaxCharHeight + 2;
230
        $this->spacing = (int)(($this->config['num_chars'] * $MaxCharWidth) / $this->config['num_chars']);
231
        $this->width   = ($this->config['num_chars'] * $MaxCharWidth) + ($this->spacing / 2);
232
    }
233
234
    /**
235
     * Return random background
236
     *
237
     * @return string|null
238
     */
239
    public function loadBackground()
240
    {
241
        $RandBackground = null;
242
        if ($backgrounds = $this->getList('backgrounds', '(gif|jpg|png)')) {
243
            $RandBackground = XOOPS_ROOT_PATH . '/class/captcha/image/backgrounds/' . $backgrounds[array_rand($backgrounds)];
244
        }
245
246
        return $RandBackground;
247
    }
248
249
    /**
250
     * Draw Image background
251
     */
252
    public function createFromFile()
253
    {
254
        if ($RandImage = $this->loadBackground()) {
255
            $ImageType = @getimagesize($RandImage);
256
            if (isset($ImageType[2])) {
257
                switch ($ImageType[2]) {
258
                    case 1:
259
                        $BackgroundImage = imagecreatefromgif($RandImage);
260
                        break;
261
262
                    case 2:
263
                        $BackgroundImage = imagecreatefromjpeg($RandImage);
264
                        break;
265
266
                    case 3:
267
                        $BackgroundImage = imagecreatefrompng($RandImage);
268
                        break;
269
                }
270
            }
271
        }
272
        if (!empty($BackgroundImage)) {
273
            imagecopyresized($this->oImage, $BackgroundImage, 0, 0, 0, 0, imagesx($this->oImage), imagesy($this->oImage), imagesx($BackgroundImage), imagesy($BackgroundImage));
274
            imagedestroy($BackgroundImage);
275
        } else {
276
            $this->drawBars();
277
        }
278
    }
279
280
    /**
281
     * Draw Code
282
     */
283
    public function drawCode()
284
    {
285
        for ($i = 0; $i < $this->config['num_chars']; ++$i) {
286
            // select random greyscale colour
287
            $text_color = imagecolorallocate($this->oImage, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100));
288
289
            // write text to image
290
            $Angle = mt_rand(10, 30);
291
            if ($i % 2) {
292
                $Angle = mt_rand(-30, -10);
293
            }
294
295
            // select random font size
296
            $FontSize = mt_rand($this->config['fontsize_min'], $this->config['fontsize_max']);
297
298
            $CharDetails = imageftbbox($FontSize, $Angle, $this->font, $this->code[$i], array());
299
            $CharHeight  = abs($CharDetails[1] + $CharDetails[5]);
300
301
            // calculate character starting coordinates
302
            $posX = ($this->spacing / 2) + ($i * $this->spacing);
303
            $posY = 2 + ($this->height / 2) + ($CharHeight / 4);
304
305
            imagefttext($this->oImage, $FontSize, $Angle, (int)$posX, (int)$posY, $text_color, $this->font, $this->code[$i], array());
306
        }
307
    }
308
309
    /**
310
     * Draw Border
311
     */
312
    public function drawBorder()
313
    {
314
        $rgb          = mt_rand(50, 150);
315
        $border_color = imagecolorallocate($this->oImage, $rgb, $rgb, $rgb);
316
        imagerectangle($this->oImage, 0, 0, $this->width - 1, $this->height - 1, $border_color);
317
    }
318
319
    /**
320
     * Draw Circles background
321
     */
322
    public function drawCircles()
323
    {
324
        for ($i = 1; $i <= $this->config['background_num']; ++$i) {
325
            $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
326
            imagefilledellipse($this->oImage, mt_rand(0, $this->width - 10), mt_rand(0, $this->height - 3), mt_rand(10, 20), mt_rand(20, 30), $randomcolor);
327
        }
328
    }
329
330
    /**
331
     * Draw Lines background
332
     */
333
    public function drawLines()
334
    {
335
        for ($i = 0; $i < $this->config['background_num']; ++$i) {
336
            $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
337
            imageline($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor);
338
        }
339
    }
340
341
    /**
342
     * Draw Rectangles background
343
     */
344
    public function drawRectangles()
345
    {
346
        for ($i = 1; $i <= $this->config['background_num']; ++$i) {
347
            $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
348
            imagefilledrectangle($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor);
349
        }
350
    }
351
352
    /**
353
     * Draw Bars background
354
     */
355
    public function drawBars()
356
    {
357
        for ($i = 0; $i <= $this->height;) {
358
            $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
359
            imageline($this->oImage, 0, (int)$i, (int)$this->width, (int)$i, (int)$randomcolor);
360
            $i += 2.5;
361
        }
362
        for ($i = 0; $i <= $this->width;) {
363
            $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
364
            imageline($this->oImage, (int)$i, 0, (int)$i, (int)$this->height, (int)$randomcolor);
365
            $i += 2.5;
366
        }
367
    }
368
369
    /**
370
     * Draw Ellipses background
371
     */
372
    public function drawEllipses()
373
    {
374
        for ($i = 1; $i <= $this->config['background_num']; ++$i) {
375
            $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
376
            imageellipse($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor);
377
        }
378
    }
379
380
    /**
381
     * Draw polygons background
382
     */
383
    public function drawPolygons()
384
    {
385
        for ($i = 1; $i <= $this->config['background_num']; ++$i) {
386
            $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
387
            $coords      = array();
388
            for ($j = 1; $j <= $this->config['polygon_point']; ++$j) {
389
                $coords[] = mt_rand(0, $this->width);
390
                $coords[] = mt_rand(0, $this->height);
391
            }
392
            imagefilledpolygon($this->oImage, $coords, $this->config['polygon_point'], $randomcolor);
393
        }
394
    }
395
    /**#@-*/
396
397
    /**
398
     *  Create CAPTCHA image with BMP
399
     *
400
     *  TODO
401
     * @param  string $file
402
     * @return string
403
     */
404
    public function createImageBmp($file = '')
405
    {
406
        $image = '';
407
408
        if (empty($file)) {
409
            header('Content-type: image/bmp');
410
            echo $image;
411
        } else {
412
            return $image;
413
        }
414
        return null;
415
    }
416
}
417
418
$imageHandler = new XoopsCaptchaImageHandler();
419
$imageHandler->loadImage();
420