XpressEngine Core  1.11.2
 All Classes Namespaces Files Functions Variables Pages
captcha_member.addon.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) NAVER <http://www.navercorp.com> */
3 
4 if(!defined("__XE__")) exit();
5 
12 if(!class_exists('AddonMemberCaptcha', false))
13 {
14  class AddonMemberCaptcha
15  {
16  var $addon_info;
17  var $target_acts = NULL;
18 
19  function setInfo(&$addon_info)
20  {
21  $this->addon_info = $addon_info;
22  }
23 
24  function before_module_proc()
25  {
26  // if($_SESSION['member_captcha_authed'])
27  // {
28  unset($_SESSION['member_captcha_authed']);
29  // }
30  }
31 
32  function before_module_init(&$ModuleHandler)
33  {
34  $logged_info = Context::get('logged_info');
35  if($logged_info->is_admin == 'Y' || $logged_info->is_site_admin)
36  {
37  return false;
38  }
39  // if($this->addon_info->target != 'all' && Context::get('is_logged'))
40  // {
41  // return false;
42  // }
43  if($_SESSION['XE_VALIDATOR_ERROR'] == -1)
44  {
45  $_SESSION['member_captcha_authed'] = false;
46  }
47  if($_SESSION['member_captcha_authed'])
48  {
49  return false;
50  }
51 
52  $type = Context::get('captchaType');
53 
54  $this->target_acts = array();
55  if($this->addon_info->apply_find_account == 'apply')
56  {
57  $this->target_acts[] = 'procMemberFindAccount';
58  }
59  if($this->addon_info->apply_resend_auth_mail == 'apply')
60  {
61  $this->target_acts[] = 'procMemberResendAuthMail';
62  }
63  if($this->addon_info->apply_signup == 'apply')
64  {
65  $this->target_acts[] = 'procMemberInsert';
66  }
67 
68  if(Context::getRequestMethod() != 'XMLRPC' && Context::getRequestMethod() !== 'JSON')
69  {
70  if($type == 'inline')
71  {
72  if(!$this->compareCaptcha())
73  {
74  Context::loadLang(_XE_PATH_ . 'addons/captcha_member/lang');
75  $_SESSION['XE_VALIDATOR_ERROR'] = -1;
76  $_SESSION['XE_VALIDATOR_MESSAGE'] = Context::getLang('captcha_denied');
77  $_SESSION['XE_VALIDATOR_MESSAGE_TYPE'] = 'error';
78  $_SESSION['XE_VALIDATOR_RETURN_URL'] = Context::get('error_return_url');
79  $ModuleHandler->_setInputValueToSession();
80  }
81  }
82  else
83  {
84  Context::addHtmlHeader('<script>
85  if(!captchaTargetAct) {var captchaTargetAct = [];}
86  captchaTargetAct.push("' . implode('","', $this->target_acts) . '");
87  </script>');
88  Context::loadFile(array('./addons/captcha/captcha.min.js', 'body', '', null), true);
89  }
90  }
91 
92  // compare session when calling actions such as writing a post or a comment on the board/issue tracker module
93  if(!$_SESSION['member_captcha_authed'] && in_array(Context::get('act'), $this->target_acts))
94  {
95  Context::loadLang(_XE_PATH_ . 'addons/captcha_member/lang');
96  $ModuleHandler->error = "captcha_denied";
97  }
98 
99  return true;
100  }
101 
102  function createKeyword()
103  {
104  $type = Context::get('captchaType');
105  if($type == 'inline' && $_SESSION['captcha_keyword'])
106  {
107  return;
108  }
109 
110  $arr = range('A', 'Y');
111  shuffle($arr);
112  $arr = array_slice($arr, 0, 6);
113  $_SESSION['captcha_keyword'] = join('', $arr);
114  }
115 
116  function before_module_init_setCaptchaSession()
117  {
118  if($_SESSION['member_captcha_authed'])
119  {
120  return false;
121  }
122  // Load language files
123  Context::loadLang(_XE_PATH_ . 'addons/captcha_member/lang');
124  // Generate keywords
125  $this->createKeyword();
126 
127  $target = Context::getLang('target_captcha');
128  header("Content-Type: text/xml; charset=UTF-8");
129  header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
130  header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
131  header("Cache-Control: no-store, no-cache, must-revalidate");
132  header("Cache-Control: post-check=0, pre-check=0", false);
133  header("Pragma: no-cache");
134  printf("<response>\r\n <error>0</error>\r\n <message>success</message>\r\n <about_captcha><![CDATA[%s]]></about_captcha>\r\n <captcha_reload><![CDATA[%s]]></captcha_reload>\r\n <captcha_play><![CDATA[%s]]></captcha_play>\r\n <cmd_input><![CDATA[%s]]></cmd_input>\r\n <cmd_cancel><![CDATA[%s]]></cmd_cancel>\r\n </response>"
135  , Context::getLang('about_captcha')
136  , Context::getLang('captcha_reload')
137  , Context::getLang('captcha_play')
138  , Context::getLang('cmd_input')
139  , Context::getLang('cmd_cancel')
140  );
141  Context::close();
142  exit();
143  }
144 
145  function before_module_init_captchaImage()
146  {
147  if($_SESSION['member_captcha_authed'])
148  {
149  return false;
150  }
151  if(Context::get('renew'))
152  {
153  $this->createKeyword();
154  }
155 
156  $keyword = $_SESSION['captcha_keyword'];
157  $im = $this->createCaptchaImage($keyword);
158 
159  header("Cache-Control: ");
160  header("Pragma: ");
161  header("Content-Type: image/png");
162 
163  imagepng($im);
164  imagedestroy($im);
165 
166  Context::close();
167  exit();
168  }
169 
170  function createCaptchaImage($string)
171  {
172  $arr = array();
173  for($i = 0, $c = strlen($string); $i < $c; $i++)
174  {
175  $arr[] = $string{$i};
176  }
177 
178  // Font site
179  $w = 18;
180  $h = 25;
181 
182  // Character length
183  $c = count($arr);
184 
185  // Character image
186  $im = array();
187 
188  // Create an image by total size
189  $im[] = imagecreate(($w + 2) * count($arr), $h);
190 
191  $deg = range(-30, 30);
192  shuffle($deg);
193 
194  // Create an image for each letter
195  foreach($arr as $i => $str)
196  {
197  $im[$i + 1] = @imagecreate($w, $h);
198  $background_color = imagecolorallocate($im[$i + 1], 255, 255, 255);
199  $text_color = imagecolorallocate($im[$i + 1], 0, 0, 0);
200 
201  // Control font size
202  $ran = range(1, 20);
203  shuffle($ran);
204 
205  if(function_exists('imagerotate'))
206  {
207  imagestring($im[$i + 1], (array_pop($ran) % 3) + 3, 2, (array_pop($ran) % 8), $str, $text_color);
208  $im[$i + 1] = imagerotate($im[$i + 1], array_pop($deg), 0);
209 
210  $background_color = imagecolorallocate($im[$i + 1], 255, 255, 255);
211  imagecolortransparent($im[$i + 1], $background_color);
212  }
213  else
214  {
215  imagestring($im[$i + 1], (array_pop($ran) % 3) + 3, 2, (array_pop($ran) % 4), $str, $text_color);
216  }
217  }
218 
219  // Combine images of each character
220  for($i = 1; $i < count($im); $i++)
221  {
222  imagecopy($im[0], $im[$i], (($w + 2) * ($i - 1)), 0, 0, 0, $w, $h);
223  imagedestroy($im[$i]);
224  }
225 
226  // Larger image
227  $big_count = 2;
228  $big = imagecreatetruecolor(($w + 2) * $big_count * $c, $h * $big_count);
229  imagecopyresized($big, $im[0], 0, 0, 0, 0, ($w + 2) * $big_count * $c, $h * $big_count, ($w + 2) * $c, $h);
230  imagedestroy($im[0]);
231 
232  if(function_exists('imageantialias'))
233  {
234  imageantialias($big, true);
235  }
236 
237  // Background line
238  $line_color = imagecolorallocate($big, 0, 0, 0);
239 
240  $w = ($w + 2) * $big_count * $c;
241  $h = $h * $big_count;
242  $d = array_pop($deg);
243 
244  for($i = -abs($d); $i < $h + abs($d); $i = $i + 7)
245  {
246  imageline($big, 0, $i + $d, $w, $i, $line_color);
247  }
248 
249  $x = range(0, ($w - 10));
250  shuffle($x);
251 
252  for($i = 0; $i < 200; $i++)
253  {
254  imagesetpixel($big, $x[$i] % $w, $x[$i + 1] % $h, $line_color);
255  }
256 
257  return $big;
258  }
259 
260  function before_module_init_captchaAudio()
261  {
262  if($_SESSION['member_captcha_authed'])
263  {
264  return false;
265  }
266 
267  $keyword = strtoupper($_SESSION['captcha_keyword']);
268  $data = $this->createCaptchaAudio($keyword);
269 
270  header('Content-type: audio/mpeg');
271  header("Content-Disposition: attachment; filename=\"captcha_audio.mp3\"");
272  header('Cache-Control: no-store, no-cache, must-revalidate');
273  header('Expires: Sun, 1 Jan 2000 12:00:00 GMT');
274  header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT');
275  header('Content-Length: ' . strlen($data));
276 
277  echo $data;
278  Context::close();
279  exit();
280  }
281 
282  function createCaptchaAudio($string)
283  {
284  $data = '';
285  $_audio = './addons/captcha/audio/F_%s.mp3';
286  for($i = 0, $c = strlen($string); $i < $c; $i++)
287  {
288  $_data = FileHandler::readFile(sprintf($_audio, $string{$i}));
289 
290  $start = rand(5, 68); // Random start in 4-byte header and 64 byte data
291  $datalen = strlen($_data) - $start - 256; // Last unchanged 256 bytes
292 
293  for($j = $start; $j < $datalen; $j+=64)
294  {
295  $ch = ord($_data{$j});
296  if($ch < 9 || $ch > 119)
297  {
298  continue;
299  }
300  $_data{$j} = chr($ch + rand(-8, 8));
301  }
302 
303  $data .= $_data;
304  }
305 
306  return $data;
307  }
308 
309  function compareCaptcha()
310  {
311  if(!in_array(Context::get('act'), $this->target_acts)) return true;
312 
313  if($_SESSION['member_captcha_authed'])
314  {
315  return true;
316  }
317 
318  if(strtoupper($_SESSION['captcha_keyword']) == strtoupper(Context::get('secret_text')))
319  {
320  $_SESSION['member_captcha_authed'] = true;
321  return true;
322  }
323 
324  unset($_SESSION['member_captcha_authed']);
325 
326  return false;
327  }
328 
329  function before_module_init_captchaCompare()
330  {
331  if(!$this->compareCaptcha())
332  {
333  return false;
334  }
335 
336  header("Content-Type: text/xml; charset=UTF-8");
337  header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
338  header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
339  header("Cache-Control: no-store, no-cache, must-revalidate");
340  header("Cache-Control: post-check=0, pre-check=0", false);
341  header("Pragma: no-cache");
342  print("<response>\r\n<error>0</error>\r\n<message>success</message>\r\n</response>");
343 
344  Context::close();
345  exit();
346  }
347 
348  function inlineDisplay()
349  {
350  unset($_SESSION['member_captcha_authed']);
351  $this->createKeyword();
352 
353  $swfURL = getUrl() . 'addons/captcha/swf/play.swf';
354  Context::unloadFile('./addons/captcha/captcha.min.js');
355  Context::loadFile(array('./addons/captcha/inline_captcha.js', 'body'));
356 
357  global $lang;
358 
359  $tags = <<<EOD
360 <img src="%s" id="captcha_image" alt="CAPTCHA" width="240" height="50" style="width:240px; height:50px; border:1px solid #b0b0b0" />
361 <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" width="0" height="0" id="captcha_audio" align="middle">
362 <param name="allowScriptAccess" value="always" />
363 <param name="quality" value="high" />
364 <param name="movie" value="%s" />
365 <param name="wmode" value="window" />
366 <param name="allowFullScreen" value="false">
367 <param name="bgcolor" value="#fffff" />
368 <embed src="%s" quality="high" wmode="window" allowFullScreen="false" bgcolor="#ffffff" width="0" height="0" name="captcha_audio" align="middle" allowScriptAccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
369 </object>
370 <button type="button" class="captchaReload text">%s</button>
371 <button type="button" class="captchaPlay text">%s</button><br />
372 <input type="hidden" name="captchaType" value="inline" />
373 <input name="secret_text" type="text" id="secret_text" />
374 EOD;
375  $tags = sprintf($tags, getUrl('captcha_action', 'captchaImage', 'rand', mt_rand(10000, 99999))
376  , $swfURL
377  , $swfURL
378  , $lang->reload
379  , $lang->play);
380  return $tags;
381  }
382 
383  }
384  $GLOBALS['__AddonMemberCaptcha__'] = new AddonMemberCaptcha;
385  $GLOBALS['__AddonMemberCaptcha__']->setInfo($addon_info);
386  Context::set('oMemberCaptcha', $GLOBALS['__AddonMemberCaptcha__']);
387 }
388 
389 $oAddonMemberCaptcha = &$GLOBALS['__AddonMemberCaptcha__'];
390 
391 if(method_exists($oAddonMemberCaptcha, $called_position))
392 {
393  if(!call_user_func_array(array(&$oAddonMemberCaptcha, $called_position), array(&$this)))
394  {
395  return false;
396  }
397 }
398 
399 $addon_act = Context::get('captcha_action');
400 if($addon_act && method_exists($oAddonMemberCaptcha, $called_position . '_' . $addon_act))
401 {
402  if(!call_user_func_array(array(&$oAddonMemberCaptcha, $called_position . '_' . $addon_act), array(&$this)))
403  {
404  return false;
405  }
406 }
407 /* End of file captcha_member.addon.php */
408 /* Location: ./addons/captcha_member/captcha_member.addon.php */
unloadFile($file, $targetIe= '', $media= 'all')
loadFile($args)
loadLang($path)
if(file_exists(_XE_PATH_. 'config/config.user.inc.php')) if(!defined('__DEBUG__')) if(!defined('__DEBUG_OUTPUT__')) if(!defined('__DEBUG_PROTECT__')) if(!defined('__DEBUG_PROTECT_IP__')) if(!defined('__DEBUG_DB_OUTPUT__')) if(!defined('__LOG_SLOW_QUERY__')) if(!defined('__LOG_SLOW_TRIGGER__')) if(!defined('__LOG_SLOW_ADDON__')) if(!defined('__LOG_SLOW_WIDGET__')) if(!defined('__DEBUG_QUERY__')) if(!defined('__OB_GZHANDLER_ENABLE__')) if(!defined('__ENABLE_PHPUNIT_TEST__')) if(!defined('__PROXY_SERVER__')) if(!defined('__ERROR_LOG__')) if(!defined('__DISABLE_DEFAULT_CSS__')) if(!defined('__AUTO_OPCACHE_INVALIDATE__')) if((__DEBUG_OUTPUT__==2)&&version_compare(PHP_VERSION, '6.0.0')===-1) if(version_compare(PHP_VERSION, '5.3.0') >=0) $GLOBALS['__xe_autoload_file_map']
Definition: config.inc.php:324
addHtmlHeader($header)
set($key, $val, $set_to_get_vars=0)
if(method_exists($oAddonCaptcha, $called_position)) $addon_act
getLang($code)
const _XE_PATH_
Definition: config.inc.php:49
readFile($filename)
if(!class_exists('AddonMemberCaptcha', false)) $oAddonMemberCaptcha
getUrl()
Definition: func.inc.php:297
if(isset($_REQUEST['encode'])) if(isset($_REQUEST['decode'])) $lang
Definition: example.php:23