update plugin/kcaptcha

This commit is contained in:
Amberstone 2024-09-19 20:42:01 +09:00
parent c33663d056
commit 73ef7de539
Signed by: amber
GPG key ID: 094B0E55F98D8BF1
9 changed files with 295 additions and 270 deletions

View file

@ -1,3 +1,2 @@
<?php <?php
include_once('../../common.php'); include_once('../../common.php');
?>

View file

@ -1,3 +1,2 @@
<?php <?php
require(dirname(__FILE__).'/kcaptcha.lib.php'); require(dirname(__FILE__).'/kcaptcha.lib.php');
?>

View file

@ -1,107 +1,107 @@
$(function(){ $(function(){
var mp3_url = ""; var mp3_url = "";
$(document).on( "click", "#captcha_reload", function(){ $(document).on( "click", "#captcha_reload", function(){
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: g5_captcha_url+'/kcaptcha_session.php', url: g5_captcha_url+'/kcaptcha_session.php',
cache: false, cache: false,
async: false, async: false,
success: function(text) { success: function(text) {
$('#captcha_img').attr('src', g5_captcha_url+'/kcaptcha_image.php?t=' + (new Date).getTime()); $('#captcha_img').attr('src', g5_captcha_url+'/kcaptcha_image.php?t=' + (new Date).getTime());
} }
}); });
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: g5_captcha_url+'/kcaptcha_mp3.php', url: g5_captcha_url+'/kcaptcha_mp3.php',
cache: false, cache: false,
async: false, async: false,
success: function(url) { success: function(url) {
if (url) { if (url) {
mp3_url = url + "?t="+new Date().getTime(); mp3_url = url + "?t="+new Date().getTime();
$("#captcha_audio").attr("src", mp3_url); $("#captcha_audio").attr("src", mp3_url);
} }
} }
}); });
}); });
$(document).on( "click", "#captcha_mp3", function(){ $(document).on( "click", "#captcha_mp3", function(){
$("body").css("cursor", "wait"); $("body").css("cursor", "wait");
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: g5_captcha_url+'/kcaptcha_mp3.php', url: g5_captcha_url+'/kcaptcha_mp3.php',
cache: false, cache: false,
async: false, async: false,
success: function(url) { success: function(url) {
if (url) { if (url) {
mp3_url = url + "?t="+new Date().getTime(); mp3_url = url + "?t="+new Date().getTime();
} }
} }
}); });
var html5use = false; var html5use = false;
var html5audio = document.createElement("audio"); var html5audio = document.createElement("audio");
if (html5audio.canPlayType && html5audio.canPlayType("audio/mpeg")) { if (html5audio.canPlayType && html5audio.canPlayType("audio/mpeg")) {
var wav = new Audio(mp3_url); var wav = new Audio(mp3_url);
wav.id = "mp3_audio"; wav.id = "mp3_audio";
wav.autoplay = true; wav.autoplay = true;
wav.controls = false; wav.controls = false;
wav.autobuffer = false; wav.autobuffer = false;
wav.loop = false; wav.loop = false;
if ($("#mp3_audio").length) $("#mp3_audio").remove(); if ($("#mp3_audio").length) $("#mp3_audio").remove();
$("#captcha_mp3").after(wav); $("#captcha_mp3").after(wav);
html5use = true; html5use = true;
} }
if (!html5use) { if (!html5use) {
var object = '<object id="mp3_object" classid="clsid:22d6f312-b0f6-11d0-94ab-0080c74c7e95" height="0" width="0" style="width:0; height:0;">'; var object = '<object id="mp3_object" classid="clsid:22d6f312-b0f6-11d0-94ab-0080c74c7e95" height="0" width="0" style="width:0; height:0;">';
object += '<param name="AutoStart" value="1" />'; object += '<param name="AutoStart" value="1" />';
object += '<param name="Volume" value="0" />'; object += '<param name="Volume" value="0" />';
object += '<param name="PlayCount" value="1" />'; object += '<param name="PlayCount" value="1" />';
object += '<param name="FileName" value="' + mp3_url + '" />'; object += '<param name="FileName" value="' + mp3_url + '" />';
object += '<embed id="mp3_embed" src="' + mp3_url + '" autoplay="true" hidden="true" volume="100" type="audio/x-wav" style="display:inline;" />'; object += '<embed id="mp3_embed" src="' + mp3_url + '" autoplay="true" hidden="true" volume="100" type="audio/x-wav" style="display:inline;" />';
object += '</object>'; object += '</object>';
if ($("#mp3_object").length) if ($("#mp3_object").length)
$("#mp3_object").remove(); $("#mp3_object").remove();
$("#captcha_mp3").after(object); $("#captcha_mp3").after(object);
} }
$("body").css("cursor", "default"); $("body").css("cursor", "default");
return false; return false;
}).css('cursor', 'pointer'); }).css('cursor', 'pointer');
$("#captcha_reload").trigger("click"); $("#captcha_reload").trigger("click");
}); });
// 출력된 캡챠이미지의 키값과 입력한 키값이 같은지 비교한다. // 출력된 캡챠이미지의 키값과 입력한 키값이 같은지 비교한다.
function chk_captcha() function chk_captcha()
{ {
var captcha_result = false; var captcha_result = false;
var captcha_key = document.getElementById('captcha_key'); var captcha_key = document.getElementById('captcha_key');
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: g5_captcha_url+'/kcaptcha_result.php', url: g5_captcha_url+'/kcaptcha_result.php',
data: { data: {
'captcha_key': captcha_key.value 'captcha_key': captcha_key.value
}, },
cache: false, cache: false,
async: false, async: false,
success: function(text) { success: function(text) {
captcha_result = text; captcha_result = text;
} }
}); });
if (!captcha_result) { if (!captcha_result) {
alert('자동등록방지 입력 글자가 틀렸거나 입력 횟수가 넘었습니다.\n\n새로고침을 클릭하여 다시 입력해 주십시오.'); alert('자동등록방지 입력 글자가 틀렸거나 입력 횟수가 넘었습니다.\n\n새로고침을 클릭하여 다시 입력해 주십시오.');
captcha_key.select(); captcha_key.select();
captcha_key.focus(); captcha_key.focus();
return false; return false;
} }
return true; return true;
} }

View file

@ -18,6 +18,8 @@
class KCAPTCHA{ class KCAPTCHA{
private $keystring;
// generates keystring and image // generates keystring and image
function image(){ function image(){
require(dirname(__FILE__).'/kcaptcha_config.php'); require(dirname(__FILE__).'/kcaptcha_config.php');
@ -50,13 +52,13 @@ class KCAPTCHA{
$transparent = (imagecolorat($font, $i, 0) >> 24) == 127; $transparent = (imagecolorat($font, $i, 0) >> 24) == 127;
if(!$reading_symbol && !$transparent){ if(!$reading_symbol && !$transparent){
$font_metrics[$alphabet{$symbol}]=array('start'=>$i); $font_metrics[$alphabet[$symbol]]=array('start'=>$i);
$reading_symbol=true; $reading_symbol=true;
continue; continue;
} }
if($reading_symbol && $transparent){ if($reading_symbol && $transparent){
$font_metrics[$alphabet{$symbol}]['end']=$i; $font_metrics[$alphabet[$symbol]]['end']=$i;
$reading_symbol=false; $reading_symbol=false;
$symbol++; $symbol++;
continue; continue;
@ -75,7 +77,9 @@ class KCAPTCHA{
$odd=mt_rand(0,1); $odd=mt_rand(0,1);
if($odd==0) $odd=-1; if($odd==0) $odd=-1;
for($i=0;$i<$length;$i++){ for($i=0;$i<$length;$i++){
$m=$font_metrics[$this->keystring{$i}];
if( ! isset($this->keystring[$i]) ) continue;
$m=$font_metrics[$this->keystring[$i]];
$y=(($i%2)*$fluctuation_amplitude - $fluctuation_amplitude/2)*$odd $y=(($i%2)*$fluctuation_amplitude - $fluctuation_amplitude/2)*$odd
+ mt_rand(-round($fluctuation_amplitude/3), round($fluctuation_amplitude/3)) + mt_rand(-round($fluctuation_amplitude/3), round($fluctuation_amplitude/3))
@ -169,10 +173,10 @@ class KCAPTCHA{
if($sx<0 || $sy<0 || $sx>=$width-1 || $sy>=$height-1){ if($sx<0 || $sy<0 || $sx>=$width-1 || $sy>=$height-1){
continue; continue;
}else{ }else{
$color=imagecolorat($img, $sx, $sy) & 0xFF; $color=imagecolorat($img, (int)$sx, (int)$sy) & 0xFF;
$color_x=imagecolorat($img, $sx+1, $sy) & 0xFF; $color_x=imagecolorat($img, (int)$sx+1, (int)$sy) & 0xFF;
$color_y=imagecolorat($img, $sx, $sy+1) & 0xFF; $color_y=imagecolorat($img, (int)$sx, (int)$sy+1) & 0xFF;
$color_xy=imagecolorat($img, $sx+1, $sy+1) & 0xFF; $color_xy=imagecolorat($img, (int)$sx+1, (int)$sy+1) & 0xFF;
} }
if($color==255 && $color_x==255 && $color_y==255 && $color_xy==255){ if($color==255 && $color_x==255 && $color_y==255 && $color_xy==255){
@ -202,7 +206,7 @@ class KCAPTCHA{
$newblue=$newcolor0*$foreground_color[2]+$newcolor*$background_color[2]; $newblue=$newcolor0*$foreground_color[2]+$newcolor*$background_color[2];
} }
imagesetpixel($img2, $x, $y, imagecolorallocate($img2, $newred, $newgreen, $newblue)); imagesetpixel($img2, (int)$x, (int)$y, imagecolorallocate($img2, (int)$newred, (int)$newgreen, (int)$newblue));
} }
} }
@ -240,17 +244,17 @@ function captcha_html($class="captcha")
if(is_mobile()) if(is_mobile())
$class .= ' m_captcha'; $class .= ' m_captcha';
$html .= "\n".'<script>var g5_captcha_url = "'.G5_CAPTCHA_URL.'";</script>'; $html = "\n".'<script>var g5_captcha_url = "'.G5_CAPTCHA_URL.'";</script>';
//$html .= "\n".'<script>var g5_captcha_path = "'.G5_CAPTCHA_PATH.'";</script>'; //$html .= "\n".'<script>var g5_captcha_path = "'.G5_CAPTCHA_PATH.'";</script>';
$html .= "\n".'<script src="'.G5_CAPTCHA_URL.'/kcaptcha.js"></script>'; $html .= "\n".'<script src="'.G5_CAPTCHA_URL.'/kcaptcha.js"></script>';
$html .= "\n".'<fieldset id="captcha" class="'.$class.'">'; $html .= "\n".'<fieldset id="captcha" class="'.$class.'">';
$html .= "\n".'<legend><label for="captcha_key">자동등록방지</label></legend>'; $html .= "\n".'<legend><label for="captcha_key">자동등록방지</label></legend>';
if (is_mobile()) $html .= '<audio src="#" id="captcha_audio" controls></audio>'; if (is_mobile()) $html .= '<audio id="captcha_audio" controls></audio>';
//$html .= "\n".'<img src="#" alt="" id="captcha_img">'; //$html .= "\n".'<img src="#" alt="" id="captcha_img">';
$html .= "\n".'<img src="javascript:void(0);" alt="" id="captcha_img">'; $html .= "\n".'<img src="'.G5_CAPTCHA_URL.'/img/dot.gif" alt="" id="captcha_img">';
$html .= '<input type="text" name="captcha_key" id="captcha_key" required class="captcha_box required" size="6" maxlength="6">';
if (!is_mobile()) $html .= "\n".'<button type="button" id="captcha_mp3"><span></span>숫자음성듣기</button>'; if (!is_mobile()) $html .= "\n".'<button type="button" id="captcha_mp3"><span></span>숫자음성듣기</button>';
$html .= "\n".'<button type="button" id="captcha_reload"><span></span>새로고침</button>'; $html .= "\n".'<button type="button" id="captcha_reload"><span></span>새로고침</button>';
$html .= '<input type="text" name="captcha_key" id="captcha_key" required class="captcha_box required" size="6" maxlength="6">';
$html .= "\n".'<span id="captcha_info">자동등록방지 숫자를 순서대로 입력하세요.</span>'; $html .= "\n".'<span id="captcha_info">자동등록방지 숫자를 순서대로 입력하세요.</span>';
$html .= "\n".'</fieldset>'; $html .= "\n".'</fieldset>';
return $html; return $html;
@ -260,26 +264,29 @@ function captcha_html($class="captcha")
// 캡챠 사용시 자바스크립트에서 입력된 캡챠를 검사함 // 캡챠 사용시 자바스크립트에서 입력된 캡챠를 검사함
function chk_captcha_js() function chk_captcha_js()
{ {
// return "if (!chk_captcha()) return false;\n"; return "if (!chk_captcha()) return false;\n";
} }
// 세션에 저장된 캡챠값과 $_POST 로 넘어온 캡챠값을 비교 // 세션에 저장된 캡챠값과 $_POST 로 넘어온 캡챠값을 비교
function chk_captcha() function chk_captcha()
{ {
/*$captcha_count = (int)get_session('ss_captcha_count'); $captcha_count = (int)get_session('ss_captcha_count');
if ($captcha_count > 5) { if ($captcha_count > 5) {
return false; return false;
} }
if (!isset($_POST['captcha_key'])) return false; $post_captcha_key = (isset($_POST['captcha_key']) && $_POST['captcha_key']) ? trim($_POST['captcha_key']) : '';
if (!trim($_POST['captcha_key'])) return false; if (!trim($post_captcha_key)) return false;
if ($_POST['captcha_key'] != get_session('ss_captcha_key')) {
if( $post_captcha_key && function_exists('get_string_encrypt') ){
$ip = md5(sha1($_SERVER['REMOTE_ADDR']));
$post_captcha_key = get_string_encrypt($ip.$post_captcha_key);
}
if ($post_captcha_key != get_session('ss_captcha_key')) {
$_SESSION['ss_captcha_count'] = $captcha_count + 1; $_SESSION['ss_captcha_count'] = $captcha_count + 1;
return false; return false;
} }
return true;*/ return true;
return true; }
}
?>

View file

@ -1,52 +1,51 @@
<?php <?php
# KCAPTCHA configuration file # KCAPTCHA configuration file
$alphabet = "0123456789abcdefghijklmnopqrstuvwxyz"; # do not change without changing font files! $alphabet = "0123456789abcdefghijklmnopqrstuvwxyz"; # do not change without changing font files!
# symbols used to draw CAPTCHA # symbols used to draw CAPTCHA
$allowed_symbols = "0123456789"; #digits $allowed_symbols = "0123456789"; #digits
//$allowed_symbols = "0123456789abcdef"; #digits // 스캔 방지를 위하여 abcdef 추가 151029 15:00 //$allowed_symbols = "0123456789abcdef"; #digits // 스캔 방지를 위하여 abcdef 추가 151029 15:00
//$allowed_symbols = "abcdeghkmnpqsuvxyz"; #digits //$allowed_symbols = "abcdeghkmnpqsuvxyz"; #digits
//$allowed_symbols = "23456789abcdeghkmnpqsuvxyz"; #alphabet without similar symbols (o=0, 1=l, i=j, t=f) //$allowed_symbols = "23456789abcdeghkmnpqsuvxyz"; #alphabet without similar symbols (o=0, 1=l, i=j, t=f)
# folder with fonts # folder with fonts
$fontsdir = 'fonts'; $fontsdir = 'fonts';
# CAPTCHA string length # CAPTCHA string length
//$length = mt_rand(5,6); # random 5 or 6 //$length = mt_rand(5,6); # random 5 or 6
$length = 6; $length = 6;
# CAPTCHA image size (you do not need to change it, whis parameters is optimal) # CAPTCHA image size (you do not need to change it, whis parameters is optimal)
$width = 160; $width = 160;
$height = 60; $height = 60;
# symbol's vertical fluctuation amplitude divided by 2 # symbol's vertical fluctuation amplitude divided by 2
//$fluctuation_amplitude = 5; //$fluctuation_amplitude = 5;
//$fluctuation_amplitude = 11; // 파동&진폭 151028 14:00 //$fluctuation_amplitude = 11; // 파동&진폭 151028 14:00
$fluctuation_amplitude = 5; // 파동&진폭 원래대로 151029 15:00 $fluctuation_amplitude = 5; // 파동&진폭 원래대로 151029 15:00
#noise #noise
//$white_noise_density=0; // no white noise //$white_noise_density=0; // no white noise
$white_noise_density=1/6; $white_noise_density=1/6;
//$black_noise_density=0; // no black noise //$black_noise_density=0; // no black noise
$black_noise_density=1/20; $black_noise_density=1/20;
# increase safety by prevention of spaces between symbols # increase safety by prevention of spaces between symbols
$no_spaces = false; $no_spaces = false;
# show credits # show credits
$show_credits = false; # set to false to remove credits line. Credits adds 12 pixels to image height $show_credits = false; # set to false to remove credits line. Credits adds 12 pixels to image height
$credits = 'www.captcha.ru'; # if empty, HTTP_HOST will be shown $credits = 'www.captcha.ru'; # if empty, HTTP_HOST will be shown
# CAPTCHA image colors (RGB, 0-255) # CAPTCHA image colors (RGB, 0-255)
$foreground_color = array(0, 0, 0); $foreground_color = array(0, 0, 0);
$background_color = array(255, 255, 255); $background_color = array(255, 255, 255);
//$foreground_color = array(mt_rand(0,100), mt_rand(0,100), mt_rand(0,100)); //$foreground_color = array(mt_rand(0,100), mt_rand(0,100), mt_rand(0,100));
//$background_color = array(mt_rand(200,255), mt_rand(200,255), mt_rand(200,255)); //$background_color = array(mt_rand(200,255), mt_rand(200,255), mt_rand(200,255));
# JPEG quality of CAPTCHA image (bigger is better quality, but larger file size) # JPEG quality of CAPTCHA image (bigger is better quality, but larger file size)
$jpeg_quality = 90; $jpeg_quality = 90;
$wave = true; $wave = true;
?>

View file

@ -1,9 +1,16 @@
<?php <?php
include_once("_common.php"); include_once("_common.php");
include_once('captcha.lib.php'); include_once('captcha.lib.php');
$captcha = new KCAPTCHA(); $captcha = new KCAPTCHA();
$captcha->setKeyString(get_session("ss_captcha_key")); $ss_captcha_key = get_session("ss_captcha_key");
$captcha->getKeyString(); $ss_captcha_key_decrypt = '';
$captcha->image(); if( $ss_captcha_key && !preg_match('/^[0-9]/', $ss_captcha_key) && function_exists('get_string_decrypt') ){
?> $ip = md5(sha1($_SERVER['REMOTE_ADDR']));
$ss_captcha_key_decrypt = str_replace($ip, '', get_string_decrypt($ss_captcha_key));
}
# php 5.2 또는 5.3 버전에서 포인터처럼 해당 세션값이 변경되는 버그가 있어서 아래와 같이 조치함
if(! $ss_captcha_key_decrypt) $ss_captcha_key_decrypt = $ss_captcha_key;
$captcha->setKeyString($ss_captcha_key_decrypt);
$captcha->getKeyString();
$captcha->image();

View file

@ -1,44 +1,49 @@
<?php <?php
include_once("_common.php"); include_once("_common.php");
function make_mp3() function make_mp3()
{ {
global $config; global $config;
$number = get_session("ss_captcha_key"); $number = get_session("ss_captcha_key");
if ($number == "") return; if ($number == "") return;
if ($number == get_session("ss_captcha_save")) return; $ip = md5(sha1($_SERVER['REMOTE_ADDR']));
if( $number && function_exists('get_string_decrypt') ){
$mp3s = array(); $number = str_replace($ip, '', get_string_decrypt($number));
for($i=0;$i<strlen($number);$i++){ }
$file = G5_CAPTCHA_PATH.'/mp3/'.$config['cf_captcha_mp3'].'/'.$number[$i].'.mp3'; if ($number == get_session("ss_captcha_save")) return;
$mp3s[] = $file;
} $mp3s = array();
for($i=0;$i<strlen($number);$i++){
$ip = sprintf("%u", ip2long($_SERVER['REMOTE_ADDR'])); $file = G5_CAPTCHA_PATH.'/mp3/'.$config['cf_captcha_mp3'].'/'.$number[$i].'.mp3';
$mp3_file = 'data/cache/kcaptcha-'.$ip.'_'.G5_SERVER_TIME.'.mp3'; $mp3s[] = $file;
}
$contents = '';
foreach ($mp3s as $mp3) { $mp3_file = 'cache/kcaptcha-'.$ip.'_'.G5_SERVER_TIME.'.mp3';
$contents .= file_get_contents($mp3);
} $contents = '';
foreach ($mp3s as $mp3) {
file_put_contents(G5_PATH.'/'.$mp3_file, $contents); $contents .= file_get_contents($mp3);
}
// 지난 캡챠 파일 삭제
if (rand(0,99) == 0) { file_put_contents(G5_DATA_PATH.'/'.$mp3_file, $contents);
foreach (glob(G5_PATH.'/data/cache/kcaptcha-*.mp3') as $file) {
if (filemtime($file) + 86400 < G5_SERVER_TIME) { // 지난 캡챠 파일 삭제
@unlink($file); if (rand(0,99) == 0) {
} foreach (glob(G5_DATA_PATH.'/cache/kcaptcha-*.mp3') as $file) {
} if (filemtime($file) + 86400 < G5_SERVER_TIME) {
} @unlink($file);
}
set_session("ss_captcha_save", $number); }
}
return G5_URL.'/'.$mp3_file;
} if( $number && function_exists('get_string_encrypt') ){
$number = get_string_encrypt($ip.$number);
echo make_mp3(); }
?> set_session("ss_captcha_save", $number);
return G5_DATA_URL.'/'.$mp3_file;
}
echo make_mp3();

View file

@ -1,13 +1,18 @@
<? <?php
// 캡챠 세션값과 비교하여 맞는지? 틀린지? 결과값을 출력합니다. // 캡챠 세션값과 비교하여 맞는지? 틀린지? 결과값을 출력합니다.
include_once("_common.php"); include_once("_common.php");
//header("Content-Type: text/html; charset=$g4[charset]");
$captcha_key = isset($_POST['captcha_key']) ? $_POST['captcha_key'] : '';
$count = (int)get_session("ss_captcha_count");
if ($count >= 5) { // 설정값 이상이면 자동등록방지 입력 문자가 맞아도 오류 처리 $count = (int)get_session("ss_captcha_count");
echo false; if ($count >= 5) { // 설정값 이상이면 자동등록방지 입력 문자가 맞아도 오류 처리
} else { echo false;
set_session("ss_captcha_count", $count + 1); } else {
echo (get_session("ss_captcha_key") == $_POST['captcha_key']) ? true : false; set_session("ss_captcha_count", $count + 1);
}
?> if( $captcha_key && function_exists('get_string_encrypt') ){
$ip = md5(sha1($_SERVER['REMOTE_ADDR']));
$captcha_key = get_string_encrypt($ip.$captcha_key);
}
echo (get_session("ss_captcha_key") === $captcha_key) ? true : false;
}

View file

@ -1,18 +1,22 @@
<?php <?php
include_once("_common.php"); include_once("_common.php");
include_once(dirname(__FILE__).'/kcaptcha_config.php'); include_once(dirname(__FILE__).'/kcaptcha_config.php');
include_once('captcha.lib.php'); include_once('captcha.lib.php');
while(true){ while(true){
$keystring=''; $keystring='';
for($i=0;$i<$length;$i++){ for($i=0;$i<$length;$i++){
$keystring.=$allowed_symbols{mt_rand(0,strlen($allowed_symbols)-1)}; $keystring.=$allowed_symbols[mt_rand(0,strlen($allowed_symbols)-1)];
} }
if(!preg_match('/cp|cb|ck|c6|c9|rn|rm|mm|co|do|cl|db|qp|qb|dp|ww/', $keystring)) break; if(!preg_match('/cp|cb|ck|c6|c9|rn|rm|mm|co|do|cl|db|qp|qb|dp|ww/', $keystring)) break;
} }
set_session("ss_captcha_count", 0); if( $keystring && function_exists('get_string_encrypt') ){
set_session("ss_captcha_key", $keystring); $ip = md5(sha1($_SERVER['REMOTE_ADDR']));
$captcha = new KCAPTCHA(); $keystring = get_string_encrypt($ip.$keystring);
$captcha->setKeyString(get_session("ss_captcha_key")); }
?>
set_session("ss_captcha_count", 0);
set_session("ss_captcha_key", $keystring);
$captcha = new KCAPTCHA();
$captcha->setKeyString(get_session("ss_captcha_key"));