Passed
Pull Request — master (#1323)
by Michael
04:59
created

XoopsCaptchaImageHandler::loadFont()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
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(), 1));
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|void
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();
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->createImageGd() targeting XoopsCaptchaImageHandler::createImageGd() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
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
        $items = array();
0 ignored issues
show
Unused Code introduced by
The assignment to $items is dead and can be removed.
Loading history...
116
        xoops_load('XoopsCache');
117
        if ($items = XoopsCache::read("captcha_captcha_{$name}")) {
118
            return $items;
119
        }
120
121
        require_once XOOPS_ROOT_PATH . '/class/xoopslists.php';
122
        $file_path = XOOPS_ROOT_PATH . "/class/captcha/image/{$name}";
123
        $files     = XoopsLists::getFileListAsArray($file_path);
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($this->width, $this->height);
0 ignored issues
show
Bug introduced by
$this->height of type double is incompatible with the type integer expected by parameter $height of imagecreatetruecolor(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

150
        $this->oImage = imagecreatetruecolor($this->width, /** @scrutinizer ignore-type */ $this->height);
Loading history...
Bug introduced by
$this->width of type double is incompatible with the type integer expected by parameter $width of imagecreatetruecolor(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

150
        $this->oImage = imagecreatetruecolor(/** @scrutinizer ignore-type */ $this->width, $this->height);
Loading history...
151
        $background   = imagecolorallocate($this->oImage, 255, 255, 255);
152
        imagefilledrectangle($this->oImage, 0, 0, $this->width, $this->height, $background);
0 ignored issues
show
Bug introduced by
$this->height of type double is incompatible with the type integer expected by parameter $y2 of imagefilledrectangle(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

152
        imagefilledrectangle($this->oImage, 0, 0, $this->width, /** @scrutinizer ignore-type */ $this->height, $background);
Loading history...
Bug introduced by
$this->width of type double is incompatible with the type integer expected by parameter $x2 of imagefilledrectangle(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

152
        imagefilledrectangle($this->oImage, 0, 0, /** @scrutinizer ignore-type */ $this->width, $this->height, $background);
Loading history...
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
        imagejpeg($this->oImage);
189
        imagedestroy($this->oImage);
190
    }
191
192
    public function loadFont()
193
    {
194
        $fonts      = $this->getList('fonts', 'ttf');
195
        $this->font = XOOPS_ROOT_PATH . '/class/captcha/image/fonts/' . $fonts[array_rand($fonts)];
196
    }
197
198
    public function setImageSize()
199
    {
200
        $MaxCharWidth  = 0;
201
        $MaxCharHeight = 0;
202
        $oImage        = imagecreatetruecolor(100, 100);
203
        $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...
204
        $FontSize      = $this->config['fontsize_max'];
205
        for ($Angle = -30; $Angle <= 30; ++$Angle) {
206
            for ($i = 65; $i <= 90; ++$i) {
207
                $CharDetails   = imageftbbox($FontSize, $Angle, $this->font, chr($i), array());
208
                $_MaxCharWidth = abs($CharDetails[0] + $CharDetails[2]);
209
                if ($_MaxCharWidth > $MaxCharWidth) {
210
                    $MaxCharWidth = $_MaxCharWidth;
211
                }
212
                $_MaxCharHeight = abs($CharDetails[1] + $CharDetails[5]);
213
                if ($_MaxCharHeight > $MaxCharHeight) {
214
                    $MaxCharHeight = $_MaxCharHeight;
215
                }
216
            }
217
        }
218
        imagedestroy($oImage);
219
220
        $this->height  = $MaxCharHeight + 2;
221
        $this->spacing = (int)(($this->config['num_chars'] * $MaxCharWidth) / $this->config['num_chars']);
222
        $this->width   = ($this->config['num_chars'] * $MaxCharWidth) + ($this->spacing / 2);
223
    }
224
225
    /**
226
     * Return random background
227
     *
228
     * @return string|null
229
     */
230
    public function loadBackground()
231
    {
232
        $RandBackground = null;
233
        if ($backgrounds = $this->getList('backgrounds', '(gif|jpg|png)')) {
234
            $RandBackground = XOOPS_ROOT_PATH . '/class/captcha/image/backgrounds/' . $backgrounds[array_rand($backgrounds)];
235
        }
236
237
        return $RandBackground;
238
    }
239
240
    /**
241
     * Draw Image background
242
     */
243
    public function createFromFile()
244
    {
245
        if ($RandImage = $this->loadBackground()) {
246
            $ImageType = @getimagesize($RandImage);
247
            if (isset($ImageType[2])) {
248
                switch ($ImageType[2]) {
249
                    case 1:
250
                        $BackgroundImage = imagecreatefromgif($RandImage);
251
                        break;
252
253
                    case 2:
254
                        $BackgroundImage = imagecreatefromjpeg($RandImage);
255
                        break;
256
257
                    case 3:
258
                        $BackgroundImage = imagecreatefrompng($RandImage);
259
                        break;
260
                }
261
            }
262
        }
263
        if (!empty($BackgroundImage)) {
264
            imagecopyresized($this->oImage, $BackgroundImage, 0, 0, 0, 0, imagesx($this->oImage), imagesy($this->oImage), imagesx($BackgroundImage), imagesy($BackgroundImage));
265
            imagedestroy($BackgroundImage);
266
        } else {
267
            $this->drawBars();
268
        }
269
    }
270
271
    /**
272
     * Draw Code
273
     */
274
    public function drawCode()
275
    {
276
        for ($i = 0; $i < $this->config['num_chars']; ++$i) {
277
            // select random greyscale colour
278
            $text_color = imagecolorallocate($this->oImage, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100));
279
280
            // write text to image
281
            $Angle = mt_rand(10, 30);
282
            if ($i % 2) {
283
                $Angle = mt_rand(-30, -10);
284
            }
285
286
            // select random font size
287
            $FontSize = mt_rand($this->config['fontsize_min'], $this->config['fontsize_max']);
288
289
            $CharDetails = imageftbbox($FontSize, $Angle, $this->font, $this->code[$i], array());
290
            $CharHeight  = abs($CharDetails[1] + $CharDetails[5]);
291
292
            // calculate character starting coordinates
293
            $posX = ($this->spacing / 2) + ($i * $this->spacing);
294
            $posY = 2 + ($this->height / 2) + ($CharHeight / 4);
295
296
            imagefttext($this->oImage, $FontSize, $Angle, $posX, $posY, $text_color, $this->font, $this->code[$i], array());
0 ignored issues
show
Bug introduced by
$posY of type double is incompatible with the type integer expected by parameter $y of imagefttext(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

296
            imagefttext($this->oImage, $FontSize, $Angle, $posX, /** @scrutinizer ignore-type */ $posY, $text_color, $this->font, $this->code[$i], array());
Loading history...
297
        }
298
    }
299
300
    /**
301
     * Draw Border
302
     */
303
    public function drawBorder()
304
    {
305
        $rgb          = mt_rand(50, 150);
306
        $border_color = imagecolorallocate($this->oImage, $rgb, $rgb, $rgb);
307
        imagerectangle($this->oImage, 0, 0, $this->width - 1, $this->height - 1, $border_color);
308
    }
309
310
    /**
311
     * Draw Circles background
312
     */
313
    public function drawCircles()
314
    {
315
        for ($i = 1; $i <= $this->config['background_num']; ++$i) {
316
            $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
317
            imagefilledellipse($this->oImage, mt_rand(0, $this->width - 10), mt_rand(0, $this->height - 3), mt_rand(10, 20), mt_rand(20, 30), $randomcolor);
318
        }
319
    }
320
321
    /**
322
     * Draw Lines background
323
     */
324
    public function drawLines()
325
    {
326
        for ($i = 0; $i < $this->config['background_num']; ++$i) {
327
            $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
328
            imageline($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor);
329
        }
330
    }
331
332
    /**
333
     * Draw Rectangles background
334
     */
335
    public function drawRectangles()
336
    {
337
        for ($i = 1; $i <= $this->config['background_num']; ++$i) {
338
            $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
339
            imagefilledrectangle($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor);
340
        }
341
    }
342
343
    /**
344
     * Draw Bars background
345
     */
346
    public function drawBars()
347
    {
348
        for ($i = 0; $i <= $this->height;) {
349
            $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
350
            imageline($this->oImage, 0, $i, $this->width, $i, $randomcolor);
0 ignored issues
show
Bug introduced by
It seems like $i can also be of type double; however, parameter $y2 of imageline() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

350
            imageline($this->oImage, 0, $i, $this->width, /** @scrutinizer ignore-type */ $i, $randomcolor);
Loading history...
Bug introduced by
It seems like $i can also be of type double; however, parameter $y1 of imageline() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

350
            imageline($this->oImage, 0, /** @scrutinizer ignore-type */ $i, $this->width, $i, $randomcolor);
Loading history...
351
            $i += 2.5;
352
        }
353
        for ($i = 0; $i <= $this->width;) {
354
            $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
355
            imageline($this->oImage, $i, 0, $i, $this->height, $randomcolor);
0 ignored issues
show
Bug introduced by
It seems like $i can also be of type double; however, parameter $x1 of imageline() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

355
            imageline($this->oImage, /** @scrutinizer ignore-type */ $i, 0, $i, $this->height, $randomcolor);
Loading history...
Bug introduced by
It seems like $i can also be of type double; however, parameter $x2 of imageline() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

355
            imageline($this->oImage, $i, 0, /** @scrutinizer ignore-type */ $i, $this->height, $randomcolor);
Loading history...
356
            $i += 2.5;
357
        }
358
    }
359
360
    /**
361
     * Draw Ellipses background
362
     */
363
    public function drawEllipses()
364
    {
365
        for ($i = 1; $i <= $this->config['background_num']; ++$i) {
366
            $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
367
            imageellipse($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor);
368
        }
369
    }
370
371
    /**
372
     * Draw polygons background
373
     */
374
    public function drawPolygons()
375
    {
376
        for ($i = 1; $i <= $this->config['background_num']; ++$i) {
377
            $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
378
            $coords      = array();
379
            for ($j = 1; $j <= $this->config['polygon_point']; ++$j) {
380
                $coords[] = mt_rand(0, $this->width);
381
                $coords[] = mt_rand(0, $this->height);
382
            }
383
            imagefilledpolygon($this->oImage, $coords, $this->config['polygon_point'], $randomcolor);
384
        }
385
    }
386
    /**#@-*/
387
388
    /**
389
     *  Create CAPTCHA image with BMP
390
     *
391
     *  TODO
392
     * @param  string $file
393
     * @return string
394
     */
395
    public function createImageBmp($file = '')
396
    {
397
        $image = '';
398
399
        if (empty($file)) {
400
            header('Content-type: image/bmp');
401
            echo $image;
402
        } else {
403
            return $image;
404
        }
405
        return null;
406
    }
407
}
408
409
$imageHandler = new XoopsCaptchaImageHandler();
410
$imageHandler->loadImage();
411