XoopsCaptcha::init()   B
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 6
nop 7
dl 0
loc 22
rs 8.9457
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * CAPTCHA class For XOOPS
5
 *
6
 * Currently there are two types of CAPTCHA forms, text and image
7
 * The default mode is "text", it can be changed in the priority:
8
 * 1 If mode is set through XoopsFormCaptcha::setConfig("mode", $mode), take it
9
 * 2 Elseif mode is set though captcha/config.php, take it
10
 * 3 Else, take "text"
11
 *
12
 * D.J.
13
 */
14
class XoopsCaptcha
15
{
16
    public $active = true;
17
    public $mode   = 'text';    // potential values: image, text
18
    public $config = [];
19
20
    public $message = []; // Logging error messages
21
22
    /**
23
     * XoopsCaptcha constructor.
24
     */
25
    public function __construct()
26
    {
27
        // Loading default preferences
28
        $this->config = @include __DIR__ . '/config.php';
29
30
        $this->setMode($this->config['mode']);
31
    }
32
33
    /**
34
     * @return XoopsCaptcha
35
     */
36
    public static function getInstance()
37
    {
38
        static $instance;
39
        if (null === $instance) {
40
            $instance = new static();
41
        }
42
43
        return $instance;
44
    }
45
46
    /**
47
     * @param $name
48
     * @param $val
49
     * @return bool
50
     */
51
    public function setConfig($name, $val)
52
    {
53
        if ('mode' === $name) {
54
            $this->setMode($val);
55
        } elseif (isset($this->$name)) {
56
            $this->$name = $val;
57
        } else {
58
            $this->config[$name] = $val;
59
        }
60
61
        return true;
62
    }
63
64
    /**
65
     * Set CAPTCHA mode
66
     *
67
     * For future possible modes, right now force to use text or image
68
     *
69
     * @param string $mode if no mode is set, just verify current mode
70
     */
71
    public function setMode($mode = null)
72
    {
73
        if (!empty($mode) && in_array($mode, ['text', 'image'])) {
74
            $this->mode = $mode;
75
76
            if ('image' !== $this->mode) {
77
                return;
78
            }
79
        }
80
81
        // Disable image mode
82 View Code Duplication
        if (!extension_loaded('gd')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
83
            $this->mode = 'text';
84
        } else {
85
            $required_functions = [
86
                'imagecreatetruecolor',
87
                'imagecolorallocate',
88
                'imagefilledrectangle',
89
                'imagejpeg',
90
                'imagedestroy',
91
                'imageftbbox'
92
            ];
93
            foreach ($required_functions as $func) {
94
                if (!function_exists($func)) {
95
                    $this->mode = 'text';
96
                    break;
97
                }
98
            }
99
        }
100
    }
101
102
    /**
103
     * Initializing the CAPTCHA class
104
     * @param string $name
105
     * @param null   $skipmember
106
     * @param null   $num_chars
107
     * @param null   $fontsize_min
108
     * @param null   $fontsize_max
109
     * @param null   $background_type
110
     * @param null   $background_num
111
     */
112
    public function init(
113
        $name = 'xoopscaptcha',
114
        $skipmember = null,
115
        $num_chars = null,
116
        $fontsize_min = null,
117
        $fontsize_max = null,
118
        $background_type = null,
119
        $background_num = null
120
    ) {
121
        // Loading RUN-TIME settings
122
        foreach (array_keys($this->config) as $key) {
123
            if (isset(${$key}) && null !== ${$key}) {
124
                $this->config[$key] = ${$key};
125
            }
126
        }
127
        $this->config['name'] = $name;
128
129
        // Skip CAPTCHA for member if set
130
        if ($this->config['skipmember'] && is_object($GLOBALS['xoopsUser'])) {
131
            $this->active = false;
132
        }
133
    }
134
135
    /**
136
     * Verify user submission
137
     * @param  null $skipMember
138
     * @return bool
139
     */
140
    public function verify($skipMember = null)
141
    {
142
        $sessionName = @$_SESSION['XoopsCaptcha_name'];
143
        $skipMember  = (null === $skipMember) ? @$_SESSION['XoopsCaptcha_skipmember'] : $skipMember;
144
        $maxAttempts = (int)(@$_SESSION['XoopsCaptcha_maxattempts']);
145
146
        $is_valid = false;
147
148
        // Skip CAPTCHA for member if set
149
        if (is_object($GLOBALS['xoopsUser']) && !empty($skipMember)) {
150
            $is_valid = true;
151
        // Kill too many attempts
152
        } elseif (!empty($maxAttempts) && $_SESSION['XoopsCaptcha_attempt_' . $sessionName] > $maxAttempts) {
153
            $this->message[] = XOOPS_CAPTCHA_TOOMANYATTEMPTS;
154
155
        // Verify the code
156
        } elseif (!empty($_SESSION['XoopsCaptcha_sessioncode'])) {
157
            $func     = $this->config['casesensitive'] ? 'strcmp' : 'strcasecmp';
158
            $is_valid = !$func(trim(@$_POST[$sessionName]), $_SESSION['XoopsCaptcha_sessioncode']);
159
        }
160
161
        if (!empty($maxAttempts)) {
162
            if (!$is_valid) {
163
                // Increase the attempt records on failure
164
                $_SESSION['XoopsCaptcha_attempt_' . $sessionName]++;
165
                // Log the error message
166
                $this->message[] = XOOPS_CAPTCHA_INVALID_CODE;
167
            } else {
168
169
                // reset attempt records on success
170
                $_SESSION['XoopsCaptcha_attempt_' . $sessionName] = null;
171
            }
172
        }
173
        $this->destroyGarbage(true);
174
175
        return $is_valid;
176
    }
177
178
    /**
179
     * @return mixed|string
180
     */
181
    public function getCaption()
182
    {
183
        return defined('XOOPS_CAPTCHA_CAPTION') ? constant('XOOPS_CAPTCHA_CAPTION') : '';
184
    }
185
186
    /**
187
     * @return string
188
     */
189
    public function getMessage()
190
    {
191
        return implode('<br>', $this->message);
192
    }
193
194
    /**
195
     * Destory historical stuff
196
     * @param  bool $clearSession
197
     * @return bool
198
     */
199
    public function destroyGarbage($clearSession = false)
200
    {
201
        require_once __DIR__ . '/' . $this->mode . '.php';
202
        $class          = 'XoopsCaptcha' . ucfirst($this->mode);
203
        $captchaHandler = new $class();
204
        if (method_exists($captchaHandler, 'destroyGarbage')) {
205
            $captchaHandler->loadConfig($this->config);
206
            $captchaHandler->destroyGarbage();
207
        }
208
209
        if ($clearSession) {
210
            $_SESSION['XoopsCaptcha_name']        = null;
211
            $_SESSION['XoopsCaptcha_skipmember']  = null;
212
            $_SESSION['XoopsCaptcha_sessioncode'] = null;
213
            $_SESSION['XoopsCaptcha_maxattempts'] = null;
214
        }
215
216
        return true;
217
    }
218
219
    /**
220
     * @return mixed|string
221
     */
222
    public function render()
223
    {
224
        $form = '';
225
226
        if (!$this->active || empty($this->config['name'])) {
227
            return $form;
228
        }
229
230
        $_SESSION['XoopsCaptcha_name']        = $this->config['name'];
231
        $_SESSION['XoopsCaptcha_skipmember']  = $this->config['skipmember'];
232
        $maxAttempts                          = $this->config['maxattempt'];
233
        $_SESSION['XoopsCaptcha_maxattempts'] = $maxAttempts;
234
        /*
235
         if (!empty($maxAttempts)) {
236
         $_SESSION['XoopsCaptcha_maxattempts_'.$_SESSION['XoopsCaptcha_name']] = $maxAttempts;
237
         }
238
         */
239
240
        // Fail on too many attempts
241
        if (!empty($maxAttempts) && @$_SESSION['XoopsCaptcha_attempt_' . $this->config['name']] > $maxAttempts) {
242
            $form = XOOPS_CAPTCHA_TOOMANYATTEMPTS;
243
        // Load the form element
244
        } else {
245
            $form = $this->loadForm();
246
        }
247
248
        return $form;
249
    }
250
251
    /**
252
     * @return mixed
253
     */
254
    public function loadForm()
255
    {
256
        require_once __DIR__ . '/' . $this->mode . '.php';
257
        $class          = 'XoopsCaptcha' . ucfirst($this->mode);
258
        $captchaHandler = new $class();
259
        $captchaHandler->loadConfig($this->config);
260
261
        $form = $captchaHandler->render();
262
263
        return $form;
264
    }
265
}
266