1: | <?php
|
2: |
|
3: | use Xmf\Request;
|
4: |
|
5: | |
6: | |
7: | |
8: | |
9: | |
10: | |
11: | |
12: | |
13: | |
14: | |
15: | |
16: | |
17: | |
18: | |
19: | |
20: | |
21: | |
22: | |
23: |
|
24: | defined('XOOPS_ROOT_PATH') || exit('Restricted access');
|
25: |
|
26: | |
27: | |
28: |
|
29: | class XoopsCaptcha
|
30: | {
|
31: | public $active;
|
32: | public $handler;
|
33: | public $path_basic;
|
34: | public $path_config;
|
35: | public $path_plugin;
|
36: | public $name;
|
37: | public $config = array();
|
38: | public $message = array();
|
39: |
|
40: | |
41: | |
42: |
|
43: | protected function __construct()
|
44: | {
|
45: | xoops_loadLanguage('captcha');
|
46: |
|
47: | $this->path_basic = XOOPS_ROOT_PATH . '/class/captcha';
|
48: | $this->path_config = XOOPS_VAR_PATH . '/configs/captcha';
|
49: | $this->path_plugin = XOOPS_ROOT_PATH . '/Frameworks/captcha';
|
50: | $this->config = $this->loadConfig();
|
51: | $this->name = $this->config['name'];
|
52: | }
|
53: |
|
54: | |
55: | |
56: | |
57: | |
58: |
|
59: | public static function getInstance()
|
60: | {
|
61: | static $instance;
|
62: | if (null === $instance) {
|
63: | $instance = new static();
|
64: | }
|
65: |
|
66: | return $instance;
|
67: | }
|
68: |
|
69: | |
70: | |
71: | |
72: | |
73: | |
74: | |
75: |
|
76: | public function loadConfig($methodname = null)
|
77: | {
|
78: | $basic_config = array();
|
79: | $plugin_config = array();
|
80: | $filename = empty($methodname) ? 'config.php' : 'config.' . $methodname . '.php';
|
81: | $distfilename = empty($methodname) ? 'config.dist.php' : 'config.' . $methodname . '.dist.php';
|
82: | if (file_exists($file = $this->path_config . '/' . $filename)) {
|
83: | $basic_config = include $file;
|
84: | } elseif (file_exists($distfile = $this->path_basic . '/' . $distfilename)) {
|
85: | $basic_config = include $distfile;
|
86: | if (false===copy($distfile, $file)) {
|
87: | trigger_error('Could not create captcha config file ' . $filename);
|
88: | }
|
89: | }
|
90: |
|
91: | if (file_exists($file = $this->path_plugin . '/' . $filename)) {
|
92: | $plugin_config = include $file;
|
93: | }
|
94: |
|
95: | $config = array_merge($basic_config, $plugin_config);
|
96: | foreach ($config as $key => $val) {
|
97: | $this->config[$key] = $val;
|
98: | }
|
99: |
|
100: | return $config;
|
101: | }
|
102: |
|
103: | |
104: | |
105: | |
106: | |
107: |
|
108: | public function isActive()
|
109: | {
|
110: | if (null !== $this->active) {
|
111: | return $this->active;
|
112: | }
|
113: | if (!empty($this->config['disabled'])) {
|
114: | $this->active = false;
|
115: |
|
116: | return $this->active;
|
117: | }
|
118: | if (!empty($this->config['skipmember']) && is_object($GLOBALS['xoopsUser'])) {
|
119: | $this->active = false;
|
120: |
|
121: | return $this->active;
|
122: | }
|
123: | if (null === $this->handler) {
|
124: | $this->loadHandler();
|
125: | }
|
126: | $this->active = isset($this->handler);
|
127: |
|
128: | return $this->active;
|
129: | }
|
130: |
|
131: | |
132: | |
133: | |
134: | |
135: | |
136: |
|
137: | public function loadHandler($name = null)
|
138: | {
|
139: | $name = !empty($name) ? $name : (empty($this->config['mode']) ? 'text' : $this->config['mode']);
|
140: | $class = 'XoopsCaptcha' . ucfirst($name);
|
141: | if (!empty($this->handler) && get_class($this->handler) == $class) {
|
142: | return $this->handler;
|
143: | }
|
144: | $this->handler = null;
|
145: | if (file_exists($file = $this->path_basic . '/' . $name . '.php')) {
|
146: | require_once $file;
|
147: | } else {
|
148: | if (file_exists($file = $this->path_plugin . '/' . $name . '.php')) {
|
149: | require_once $file;
|
150: | }
|
151: | }
|
152: |
|
153: | if (!class_exists($class)) {
|
154: | $class = 'XoopsCaptchaText';
|
155: | require_once $this->path_basic . '/text.php';
|
156: | }
|
157: | $handler = new $class($this);
|
158: | if ($handler->isActive()) {
|
159: | $this->handler = $handler;
|
160: | $this->handler->loadConfig($name);
|
161: | }
|
162: |
|
163: | return $this->handler;
|
164: | }
|
165: |
|
166: | |
167: | |
168: | |
169: | |
170: | |
171: |
|
172: | public function setConfigs($configs)
|
173: | {
|
174: | foreach ($configs as $key => $val) {
|
175: | $this->setConfig($key, $val);
|
176: | }
|
177: |
|
178: | return true;
|
179: | }
|
180: |
|
181: | |
182: | |
183: | |
184: | |
185: | |
186: | |
187: |
|
188: | public function setConfig($name, $val)
|
189: | {
|
190: | if (isset($this->$name)) {
|
191: | $this->$name = $val;
|
192: | } else {
|
193: | $this->config[$name] = $val;
|
194: | }
|
195: |
|
196: | return true;
|
197: | }
|
198: |
|
199: | |
200: | |
201: |
|
202: | |
203: | |
204: | |
205: | |
206: | |
207: | |
208: |
|
209: | public function verify($skipMember = null, $name = null)
|
210: | {
|
211: | $sessionName = empty($name) ? $this->name : $name;
|
212: | $skipMember = ($skipMember === null) && isset($_SESSION["{$sessionName}_skipmember"]) ? $_SESSION["{$sessionName}_skipmember"] : $skipMember;
|
213: | $maxAttempts = isset($_SESSION["{$sessionName}_maxattempts"]) ? $_SESSION["{$sessionName}_maxattempts"] : $this->config['maxattempts'];
|
214: | $attempt = isset($_SESSION["{$sessionName}_attempt"]) ? $_SESSION["{$sessionName}_attempt"] : 0;
|
215: | $is_valid = false;
|
216: |
|
217: | if (!$this->isActive()) {
|
218: | $is_valid = true;
|
219: |
|
220: | } elseif (!empty($skipMember) && is_object($GLOBALS['xoopsUser'])) {
|
221: | $is_valid = true;
|
222: |
|
223: | } elseif (!empty($maxAttempts) && $attempt > $maxAttempts) {
|
224: | $this->message[] = _CAPTCHA_TOOMANYATTEMPTS;
|
225: |
|
226: | } else {
|
227: | $is_valid = $this->handler->verify($sessionName);
|
228: | $xoopsPreload = XoopsPreload::getInstance();
|
229: | $xoopsPreload->triggerEvent('core.behavior.captcha.result', $is_valid);
|
230: | }
|
231: |
|
232: | if (!$is_valid) {
|
233: |
|
234: | $_SESSION["{$sessionName}_attempt"]++;
|
235: |
|
236: | $this->message[] = _CAPTCHA_INVALID_CODE;
|
237: | } else {
|
238: |
|
239: | $_SESSION["{$sessionName}_attempt"] = null;
|
240: | }
|
241: | $this->destroyGarbage(true);
|
242: |
|
243: | return $is_valid;
|
244: | }
|
245: |
|
246: | |
247: | |
248: | |
249: | |
250: |
|
251: | public function getCaption()
|
252: | {
|
253: | return defined('_CAPTCHA_CAPTION') ? constant('_CAPTCHA_CAPTION') : '';
|
254: | }
|
255: |
|
256: | |
257: | |
258: | |
259: | |
260: |
|
261: | public function getMessage()
|
262: | {
|
263: | return implode('<br>', $this->message);
|
264: | }
|
265: |
|
266: | |
267: | |
268: | |
269: | |
270: |
|
271: | public function destroyGarbage($clearSession = false)
|
272: | {
|
273: | $this->loadHandler();
|
274: | if (is_callable($this->handler, 'destroyGarbage')) {
|
275: | $this->handler->destroyGarbage();
|
276: | }
|
277: | if ($clearSession) {
|
278: | $_SESSION[$this->name . '_name'] = null;
|
279: | $_SESSION[$this->name . '_skipmember'] = null;
|
280: | $_SESSION[$this->name . '_code'] = null;
|
281: | $_SESSION[$this->name . '_maxattempts'] = null;
|
282: | }
|
283: |
|
284: | return true;
|
285: | }
|
286: |
|
287: | |
288: | |
289: | |
290: | |
291: |
|
292: | public function render()
|
293: | {
|
294: | $_SESSION[$this->name . '_name'] = $this->name;
|
295: | $_SESSION[$this->name . '_skipmember'] = $this->config['skipmember'];
|
296: | $form = '';
|
297: | if (!$this->active || empty($this->config['name'])) {
|
298: | return $form;
|
299: | }
|
300: |
|
301: | $maxAttempts = $this->config['maxattempts'];
|
302: | $_SESSION[$this->name . '_maxattempts'] = $maxAttempts;
|
303: | $attempt = isset($_SESSION[$this->name . '_attempt']) ? $_SESSION[$this->name . '_attempt'] : 0;
|
304: | $_SESSION[$this->name . '_attempt'] = $attempt;
|
305: |
|
306: |
|
307: | if (!empty($maxAttempts) && $attempt > $maxAttempts) {
|
308: | $form = _CAPTCHA_TOOMANYATTEMPTS;
|
309: |
|
310: | } else {
|
311: | $form = $this->loadForm();
|
312: | }
|
313: |
|
314: | return $form;
|
315: | }
|
316: |
|
317: | |
318: | |
319: | |
320: | |
321: |
|
322: | public function renderValidationJS()
|
323: | {
|
324: | if (!$this->active || empty($this->config['name'])) {
|
325: | return '';
|
326: | }
|
327: |
|
328: | return $this->handler->renderValidationJS();
|
329: | }
|
330: |
|
331: | |
332: | |
333: | |
334: | |
335: | |
336: |
|
337: | public function setCode($code = null)
|
338: | {
|
339: | $code = ($code === null) ? $this->handler->getCode() : $code;
|
340: | if (!empty($code)) {
|
341: | $_SESSION[$this->name . '_code'] = $code;
|
342: |
|
343: | return true;
|
344: | }
|
345: |
|
346: | return false;
|
347: | }
|
348: |
|
349: | |
350: | |
351: | |
352: | |
353: |
|
354: | public function loadForm()
|
355: | {
|
356: | $form = $this->handler->render();
|
357: | $this->setCode();
|
358: |
|
359: | return $form;
|
360: | }
|
361: | }
|
362: |
|
363: | |
364: | |
365: | |
366: | |
367: | |
368: | |
369: | |
370: | |
371: |
|
372: | class XoopsCaptchaMethod
|
373: | {
|
374: | public $handler;
|
375: | public $config;
|
376: | public $code;
|
377: |
|
378: | |
379: | |
380: | |
381: | |
382: |
|
383: | public function __construct($handler = null)
|
384: | {
|
385: | $this->handler = $handler;
|
386: | }
|
387: |
|
388: | |
389: | |
390: | |
391: | |
392: |
|
393: | public function isActive()
|
394: | {
|
395: | return true;
|
396: | }
|
397: |
|
398: | |
399: | |
400: | |
401: | |
402: | |
403: |
|
404: | public function loadConfig($name = '')
|
405: | {
|
406: | $this->config = empty($name) ? $this->handler->config : array_merge($this->handler->config, $this->handler->loadConfig($name));
|
407: | }
|
408: |
|
409: | |
410: | |
411: | |
412: | |
413: |
|
414: | public function getCode()
|
415: | {
|
416: | return (string)$this->code;
|
417: | }
|
418: |
|
419: | |
420: | |
421: | |
422: | |
423: |
|
424: | public function render()
|
425: | {
|
426: | }
|
427: |
|
428: | |
429: | |
430: |
|
431: | public function renderValidationJS()
|
432: | {
|
433: | return '';
|
434: | }
|
435: |
|
436: | |
437: | |
438: | |
439: | |
440: | |
441: |
|
442: | public function verify($sessionName = null)
|
443: | {
|
444: | $is_valid = false;
|
445: | if (!empty($_SESSION["{$sessionName}_code"])) {
|
446: | $func = !empty($this->config['casesensitive']) ? 'strcmp' : 'strcasecmp';
|
447: | $is_valid = !$func(trim(Request::getString($sessionName, '', 'POST')), $_SESSION["{$sessionName}_code"]);
|
448: | }
|
449: |
|
450: | return $is_valid;
|
451: | }
|
452: | }
|
453: | |