PageRenderTime 27ms CodeModel.GetById 11ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/class/captcha/xoopscaptcha.php

https://gitlab.com/VoyaTrax/vtCMS2
PHP | 440 lines | 233 code | 45 blank | 162 comment | 36 complexity | f4b8710222712c46f5cdb30641d2f808 MD5 | raw file
  1<?php
  2/**
  3 * CAPTCHA configurations for Image mode
  4 *
  5 * Based on DuGris' SecurityImage
  6 *
  7 * You may not change or alter any portion of this comment or credits
  8 * of supporting developers from this source code or any supporting source code
  9 * which is considered copyrighted (c) material of the original comment or credit authors.
 10 * This program is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 13 *
 14 * @copyright       (c) 2000-2016 XOOPS Project (www.xoops.org)
 15 * @license             GNU GPL 2 (http://www.gnu.org/licenses/gpl-2.0.html)
 16 * @package             class
 17 * @subpackage          CAPTCHA
 18 * @since               2.3.0
 19 * @author              Taiwen Jiang <phppp@users.sourceforge.net>
 20 */
 21defined('XOOPS_ROOT_PATH') || exit('Restricted access');
 22
 23/**
 24 * Class XoopsCaptcha
 25 */
 26class XoopsCaptcha
 27{
 28    // static $instance;
 29    public $active;
 30    public $handler;
 31    public $path_basic;
 32    public $path_plugin;
 33    public $name;
 34    public $config  = array();
 35    public $message = array(); // Logging error messages
 36
 37    /**
 38     * construct
 39     */
 40    public function __construct()
 41    {
 42        xoops_loadLanguage('captcha');
 43        // Load static configurations
 44        $this->path_basic  = XOOPS_ROOT_PATH . '/class/captcha';
 45        $this->path_plugin = XOOPS_ROOT_PATH . '/Frameworks/captcha';
 46        $this->config      = $this->loadConfig();
 47        $this->name        = $this->config['name'];
 48    }
 49
 50    /**
 51     * Get Instance
 52     *
 53     * @return Instance
 54     */
 55    public static function getInstance()
 56    {
 57        static $instance;
 58        if (!isset($instance)) {
 59            $class    = __CLASS__;
 60            $instance = new $class();
 61        }
 62
 63        return $instance;
 64    }
 65
 66    /**
 67     * XoopsCaptcha::loadConfig()
 68     *
 69     * @param mixed $filename
 70     *
 71     * @return array
 72     */
 73    public function loadConfig($filename = null)
 74    {
 75        $basic_config  = array();
 76        $plugin_config = array();
 77        $filename      = empty($filename) ? 'config.php' : 'config.' . $filename . '.php';
 78        if (file_exists($file = $this->path_basic . '/' . $filename)) {
 79            $basic_config = include $file;
 80        }
 81        if (file_exists($file = $this->path_plugin . '/' . $filename)) {
 82            $plugin_config = include $file;
 83        }
 84
 85        $config = array_merge($basic_config, $plugin_config);
 86        foreach ($config as $key => $val) {
 87            $config[$key] = $val;
 88        }
 89
 90        return $config;
 91    }
 92
 93    /**
 94     * XoopsCaptcha::isActive()
 95     *
 96     * @return bool
 97     */
 98    public function isActive()
 99    {
100        if (isset($this->active)) {
101            return $this->active;
102        }
103        if (!empty($this->config['disabled'])) {
104            $this->active = false;
105
106            return $this->active;
107        }
108        if (!empty($this->config['skipmember']) && is_object($GLOBALS['xoopsUser'])) {
109            $this->active = false;
110
111            return $this->active;
112        }
113        if (!isset($this->handler)) {
114            $this->loadHandler();
115        }
116        $this->active = isset($this->handler);
117
118        return $this->active;
119    }
120
121    /**
122     * XoopsCaptcha::loadHandler()
123     *
124     * @param mixed $name
125     * @return
126     */
127    public function loadHandler($name = null)
128    {
129        $name  = !empty($name) ? $name : (empty($this->config['mode']) ? 'text' : $this->config['mode']);
130        $class = 'XoopsCaptcha' . ucfirst($name);
131        if (!empty($this->handler) && get_class($this->handler) == $class) {
132            return $this->handler;
133        }
134        $this->handler = null;
135        if (file_exists($file = $this->path_basic . '/' . $name . '.php')) {
136            require_once $file;
137        } else {
138            if (file_exists($file = $this->path_plugin . '/' . $name . '.php')) {
139                require_once $file;
140            }
141        }
142
143        if (!class_exists($class)) {
144            $class = 'XoopsCaptchaText';
145            require_once $this->path_basic . '/text.php';
146        }
147        $handler = new $class($this);
148        if ($handler->isActive()) {
149            $this->handler = $handler;
150            $this->handler->loadConfig($name);
151        }
152
153        return $this->handler;
154    }
155
156    /**
157     * XoopsCaptcha::setConfigs()
158     *
159     * @param  mixed $configs
160     * @return bool
161     */
162    public function setConfigs($configs)
163    {
164        foreach ($configs as $key => $val) {
165            $this->setConfig($key, $val);
166        }
167
168        return true;
169    }
170
171    /**
172     * XoopsCaptcha::setConfig()
173     *
174     * @param  mixed $name
175     * @param  mixed $val
176     * @return bool
177     */
178    public function setConfig($name, $val)
179    {
180        if (isset($this->$name)) {
181            $this->$name = $val;
182        } else {
183            $this->config[$name] = $val;
184        }
185
186        return true;
187    }
188
189    /**
190     * Verify user submission
191     */
192    /**
193     * XoopsCaptcha::verify()
194     *
195     * @param  mixed $skipMember
196     * @param  mixed $name
197     * @return bool
198     */
199    public function verify($skipMember = null, $name = null)
200    {
201        $sessionName = empty($name) ? $this->name : $name;
202        $skipMember  = ($skipMember === null) ? $_SESSION["{$sessionName}_skipmember"] : $skipMember;
203        $maxAttempts = $_SESSION["{$sessionName}_maxattempts"];
204        $attempt     = $_SESSION["{$sessionName}_attempt"];
205        $is_valid    = false;
206        // Skip CAPTCHA verification if disabled
207        if (!$this->isActive()) {
208            $is_valid = true;
209            // Skip CAPTCHA for member if set
210        } elseif (is_object($GLOBALS['xoopsUser']) && !empty($skipMember)) {
211            $is_valid = true;
212            // Kill too many attempts
213        } elseif (!empty($maxAttempts) && $attempt > $maxAttempts) {
214            $this->message[] = _CAPTCHA_TOOMANYATTEMPTS;
215            // Verify the code
216        } else {
217            $is_valid = $this->handler->verify($sessionName);
218        }
219
220        if (!$is_valid) {
221            // Increase the attempt records on failure
222            $_SESSION["{$sessionName}_attempt"]++;
223            // Log the error message
224            $this->message[] = _CAPTCHA_INVALID_CODE;
225        } else {
226            // reset attempt records on success
227            $_SESSION["{$sessionName}_attempt"] = null;
228        }
229        $this->destroyGarbage(true);
230
231        return $is_valid;
232    }
233
234    /**
235     * XoopsCaptcha::getCaption()
236     *
237     * @return mixed|string
238     */
239    public function getCaption()
240    {
241        return defined('_CAPTCHA_CAPTION') ? constant('_CAPTCHA_CAPTION') : '';
242    }
243
244    /**
245     * XoopsCaptcha::getMessage()
246     *
247     * @return string
248     */
249    public function getMessage()
250    {
251        return implode('<br />', $this->message);
252    }
253
254    /**
255     * Destroy historical stuff
256     * @param bool $clearSession
257     * @return bool
258     */
259    public function destroyGarbage($clearSession = false)
260    {
261        $this->loadHandler();
262        if (is_callable($this->handler, 'destroyGarbage')) {
263            $this->handler->destroyGarbage();
264        }
265        if ($clearSession) {
266            $_SESSION[$this->name . '_name']        = null;
267            $_SESSION[$this->name . '_skipmember']  = null;
268            $_SESSION[$this->name . '_code']        = null;
269            $_SESSION[$this->name . '_maxattempts'] = null;
270        }
271
272        return true;
273    }
274
275    /**
276     * XoopsCaptcha::render()
277     *
278     * @return string
279     */
280    public function render()
281    {
282        $_SESSION[$this->name . '_name']       = $this->name;
283        $_SESSION[$this->name . '_skipmember'] = $this->config['skipmember'];
284        $form                                  = '';
285        if (!$this->active || empty($this->config['name'])) {
286            return $form;
287        }
288
289        $maxAttempts                            = $this->config['maxattempts'];
290        $_SESSION[$this->name . '_maxattempts'] = $maxAttempts;
291        $attempt                                = isset($_SESSION[$this->name . '_attempt']) ? $_SESSION[$this->name . '_attempt'] : 0;
292        $_SESSION[$this->name . '_attempt']     = $attempt;
293
294        // Failure on too many attempts
295        if (!empty($maxAttempts) && $attempt > $maxAttempts) {
296            $form = _CAPTCHA_TOOMANYATTEMPTS;
297            // Load the form element
298        } else {
299            $form = $this->loadForm();
300        }
301
302        return $form;
303    }
304
305    /**
306     * XoopsCaptcha::renderValidationJS()
307     *
308     * @return string
309     */
310    public function renderValidationJS()
311    {
312        if (!$this->active || empty($this->config['name'])) {
313            return '';
314        }
315
316        return $this->handler->renderValidationJS();
317    }
318
319    /**
320     * XoopsCaptcha::setCode()
321     *
322     * @param  mixed $code
323     * @return bool
324     */
325    public function setCode($code = null)
326    {
327        $code = ($code === null) ? $this->handler->getCode() : $code;
328        if (!empty($code)) {
329            $_SESSION[$this->name . '_code'] = $code;
330
331            return true;
332        }
333
334        return false;
335    }
336
337    /**
338     * XoopsCaptcha::loadForm()
339     *
340     * @return
341     */
342    public function loadForm()
343    {
344        $form = $this->handler->render();
345        $this->setCode();
346
347        return $form;
348    }
349}
350
351/**
352 * Abstract class for CAPTCHA method
353 *
354 * Currently there are two types of CAPTCHA forms, text and image
355 * The default mode is "text", it can be changed in the priority:
356 * 1 If mode is set through XoopsFormCaptcha::setConfig("mode", $mode), take it
357 * 2 Elseif mode is set though captcha/config.php, take it
358 * 3 Else, take "text"
359 */
360class XoopsCaptchaMethod
361{
362    public $handler;
363    public $config;
364    public $code;
365
366    /**
367     * XoopsCaptchaMethod::__construct()
368     *
369     * @param mixed $handler
370     */
371    public function __construct($handler = null)
372    {
373        $this->handler = $handler;
374    }
375
376    /**
377     * XoopsCaptchaMethod::isActive()
378     *
379     * @return bool
380     */
381    public function isActive()
382    {
383        return true;
384    }
385
386    /**
387     * XoopsCaptchaMethod::loadConfig()
388     *
389     * @param  string $name
390     * @return void
391     */
392    public function loadConfig($name = '')
393    {
394        $this->config = empty($name) ? $this->handler->config : array_merge($this->handler->config, $this->handler->loadConfig($name));
395    }
396
397    /**
398     * XoopsCaptchaMethod::getCode()
399     *
400     * @return string
401     */
402    public function getCode()
403    {
404        return (string)$this->code;
405    }
406
407    /**
408     * XoopsCaptchaMethod::render()
409     *
410     * @return void
411     */
412    public function render()
413    {
414    }
415
416    /**
417     * @return string
418     */
419    public function renderValidationJS()
420    {
421        return '';
422    }
423
424    /**
425     * XoopsCaptchaMethod::verify()
426     *
427     * @param  mixed $sessionName
428     * @return bool
429     */
430    public function verify($sessionName = null)
431    {
432        $is_valid = false;
433        if (!empty($_SESSION["{$sessionName}_code"])) {
434            $func     = !empty($this->config['casesensitive']) ? 'strcmp' : 'strcasecmp';
435            $is_valid = !$func(trim(@$_POST[$sessionName]), $_SESSION["{$sessionName}_code"]);
436        }
437
438        return $is_valid;
439    }
440}