===== ""FreeCap"" CAPTCHA Integration ===== >>**See also:** Ticket [[http://wush.net/trac/wikka/ticket/347 | #347]] **URCaptchaModule**: A modular CAPTCHA plugin that requires no modifications to Wikka core code. Based upon YodaHome's implementation and the [[Docs:URRegistrationValidationFramework | UR framework]] available since 1.1.6.4.>> I've recently had several attacks with bots registering dozens of users and then vandalizing my wiki where possible. While I could have just hidden the Registration I thought the obvious answer to this would be to add a CAPTCHA to the registration process. This is what I came up with. Actually I looked for nice CAPTCHA scripts and found [[http://www.puremango.co.uk/cm_php_captcha_script_113.php | FreeCap]] which seemed quite strong to me and had some nice features. It is also released under the GPL. So I integrated it with my Wikka. === Prerequisites / Installation === First you need to download the [[http://www.puremango.co.uk/freecap1.4.1.zip | FreeCap package]] from the website. (Note that this link may not lead to the latest package). Then all the files went into a "freecap" folder below the "actions" tree. Of course you might put it somewhere else but be sure that it can be properly accessed and you changed the paths correctly where necessary (see note at the bottom). I only changed the usersettings.php (this is a modified version from 1.1.6.3), look for "added for ""FreeCap""" in the comments. For convenience this is the whole file. (Scroll down for 1.1.7-compatible version.) **actions/usersettings.php** (//version 1.1.6.3 only//) %%(php) WikiName:"); if (!defined('PASSWORD_LABEL')) define('PASSWORD_LABEL', "Password (%s+ chars):"); if (!defined('LOGIN_BUTTON_LABEL')) define('LOGIN_BUTTON_LABEL', "Login"); if (!defined('LOGOUT_BUTTON_LABEL')) define('LOGOUT_BUTTON_LABEL', "Logout"); if (!defined('NEW_USER_REGISTER_LABEL')) define('NEW_USER_REGISTER_LABEL', "Stuff you only need to fill in when you're logging in for the first time (and thus signing up as a new user on this site)."); if (!defined('CONFIRM_PASSWORD_LABEL')) define('CONFIRM_PASSWORD_LABEL', "Confirm password:"); if (!defined('RETRIEVE_PASSWORD_HEADING')) define('RETRIEVE_PASSWORD_HEADING', "===Forgot your password?==="); if (!defined('RETRIEVE_PASSWORD_MESSAGE')) define('RETRIEVE_PASSWORD_MESSAGE', "If you need a password reminder, click [[PasswordForgotten | here]]. --- You can login here using your password reminder."); if (!defined('TEMP_PASSWORD_LABEL')) define('TEMP_PASSWORD_LABEL', "Password reminder:"); // added for FreeCap CAPTCHA if (!defined('CAPTCHA_LABEL')) define('CAPTCHA_LABEL', "letters in the above picture:"); //initialize variables $params = ''; $url = ''; $email = ''; $doubleclickedit = ''; $show_comments = ''; $revisioncount = ''; $changescount = ''; $password = ''; $oldpass = ''; $password_confirm = ''; $pw_selected = ''; $hash_selected = ''; $username_highlight = ''; $username_temp_highlight = ''; $password_temp_highlight = ''; $email_highlight = ''; $password_highlight = ''; $password_new_highlight = ''; $password_confirm_highlight = ''; $revisioncount_highlight = ''; $changescount_highlight = ''; //create URL $url = $this->config['base_url'].$this->tag; // append URL params depending on rewrite_mode $params = ($this->config['rewrite_mode'] == 1) ? '?' : '&'; // BEGIN *** Logout *** // is user trying to log out? #if (isset($_REQUEST['action']) && ($_REQUEST['action'] == 'logout')) // JavaScript button with GET if (isset($_POST['logout']) && $_POST['logout'] == LOGOUT_BUTTON_LABEL) // replaced with normal form button #353, #312 { $this->LogoutUser(); $params .= 'out=true'; $this->Redirect($url.$params); } // END *** Logout *** // BEGIN *** Usersettings *** // user is still logged in else if ($user = $this->GetUser()) { // is user trying to update user settings? if (isset($_POST['action']) && ($_POST['action'] == 'update')) { // get POST parameters $email = $this->GetSafeVar('email', 'post'); $doubleclickedit = $this->GetSafeVar('doubleclickedit', 'post'); $show_comments = $this->GetSafeVar('show_comments', 'post'); $revisioncount = (int) $this->GetSafeVar('revisioncount', 'post'); $changescount = (int) $this->GetSafeVar('changescount', 'post'); // validate form input switch (TRUE) { case (strlen($email) == 0): //email is empty $error = ERROR_EMAIL_ADDRESS_REQUIRED; $email_highlight = INPUT_ERROR_STYLE; break; case (!preg_match(VALID_EMAIL_PATTERN, $email)): //invalid email $error = ERROR_INVALID_EMAIL_ADDRESS; $email_highlight = INPUT_ERROR_STYLE; break; case (($revisioncount < REVISION_DISPLAY_LIMIT_MIN) || ($revisioncount > REVISION_DISPLAY_LIMIT_MAX)): //invalid revision display limit $error = sprintf(ERROR_INVALID_REVISION_DISPLAY_LIMIT, REVISION_DISPLAY_LIMIT_MAX); $revisioncount_highlight = INPUT_ERROR_STYLE; break; case (($changescount < RECENTCHANGES_DISPLAY_LIMIT_MIN) || ($changescount > RECENTCHANGES_DISPLAY_LIMIT_MAX)): //invalid recentchanges display limit $error = sprintf(ERROR_INVALID_RECENTCHANGES_DISPLAY_LIMIT, RECENTCHANGES_DISPLAY_LIMIT_MAX); $changescount_highlight = INPUT_ERROR_STYLE; break; default: // input is valid $this->Query('UPDATE '.$this->config['table_prefix'].'users SET '. "email = '".mysql_real_escape_string($email)."', ". "doubleclickedit = '".mysql_real_escape_string($doubleclickedit)."', ". "show_comments = '".mysql_real_escape_string($show_comments)."', ". "revisioncount = '".mysql_real_escape_string($revisioncount)."', ". "changescount = '".mysql_real_escape_string($changescount)."' ". "WHERE name = '".$user['name']."' LIMIT 1"); $this->SetUser($this->LoadUser($user["name"])); // forward $params .= 'stored=true'; $this->Redirect($url.$params); } } //user just logged in else { // get stored settings $email = $user['email']; $doubleclickedit = $user['doubleclickedit']; $show_comments = $user['show_comments']; $revisioncount = $user['revisioncount']; $changescount = $user['changescount']; } // display user settings form echo '

'.USER_SETTINGS_HEADING.'

'; echo $this->FormOpen(); ?> '."\n"; break; case (isset($success)): echo ''."\n"; break; default: } ?>
  Hello, Link($user['name']) ?>!
'.$this->Format($error).'
'.$this->Format($success).'
name="email" value="htmlspecialchars_ent($email) ?>" size="40" />
/>
/>
name="revisioncount" value="htmlspecialchars_ent($revisioncount) ?>" size="40" />
name="changescount" value="htmlspecialchars_ent($changescount) ?>" size="40" />
 
FormClose(); //close user settings form if (isset($_POST['action']) && ($_POST['action'] == 'changepass')) { // check password $oldpass = $_POST['oldpass']; //can be current password or hash sent as password reminder $password = $_POST['password']; $password_confirm = $_POST['password_confirm']; $update_option = $this->GetSafeVar('update_option', 'post'); switch (TRUE) { case (strlen($oldpass) == 0): $passerror = ERROR_EMPTY_PASSWORD_OR_HASH; $password_highlight = INPUT_ERROR_STYLE; break; case (($update_option == 'pw') && md5($oldpass) != $user['password']): //wrong password $passerror = ERROR_WRONG_PASSWORD; $pw_selected = 'selected="selected"'; $password_highlight = INPUT_ERROR_STYLE; break; case (($update_option == 'hash') && $oldpass != $user['password']): //wrong hash $passerror = ERROR_WRONG_HASH; $hash_selected = 'selected="selected"'; $password_highlight = INPUT_ERROR_STYLE; break; case (strlen($password) == 0): $passerror = ERROR_EMPTY_NEW_PASSWORD; $password_highlight = INPUT_ERROR_STYLE; $password_new_highlight = INPUT_ERROR_STYLE; break; case (preg_match("/ /", $password)): $passerror = ERROR_NO_BLANK; $password_highlight = INPUT_ERROR_STYLE; $password_new_highlight = INPUT_ERROR_STYLE; break; case (strlen($password) < PASSWORD_MIN_LENGTH): $passerror = sprintf(ERROR_PASSWORD_TOO_SHORT, PASSWORD_MIN_LENGTH); $password_highlight = INPUT_ERROR_STYLE; $password_new_highlight = INPUT_ERROR_STYLE; break; case (strlen($password_confirm) == 0): $passerror = ERROR_EMPTY_NEW_CONFIRMATION_PASSWORD; $password_highlight = INPUT_ERROR_STYLE; $password_new_highlight = INPUT_ERROR_STYLE; $password_confirm_highlight = INPUT_ERROR_STYLE; break; case ($password_confirm != $password): $passerror = ERROR_PASSWORD_MATCH; $password_highlight = INPUT_ERROR_STYLE; $password_new_highlight = INPUT_ERROR_STYLE; $password_confirm_highlight = INPUT_ERROR_STYLE; break; default: $this->Query('UPDATE '.$this->config['table_prefix'].'users set '."password = md5('".mysql_real_escape_string($password)."') "."WHERE name = '".$user['name']."'"); $user['password'] = md5($password); $this->SetUser($user); $params .= 'newpassword=true'; $this->Redirect($url.$params); } } //display password update form echo '
'."\n"; echo $this->FormOpen(); ?>
'."\n"); } ?>
'.$this->Format($passerror).'
type="password" name="oldpass" size="40" />
type="password" name="password" size="40" />
type="password" name="password_confirm" size="40" />
'."\n"; echo '
'.QUICK_LINKS_HEADING.'
'."\n"; echo $this->Format(QUICK_LINKS); print($this->FormClose()); } // user is not logged in else { // print confirmation message on successful logout if (isset($_GET['out']) && ($_GET['out'] == 'true')) { $success = USER_LOGGED_OUT; } // is user trying to log in or register? if (isset($_POST['action']) && ($_POST['action'] == 'login')) { // if user name already exists, check password if (isset($_POST['name']) && $existingUser = $this->LoadUser($_POST['name'])) { // check password switch(TRUE){ case (strlen($_POST['password']) == 0): $error = ERROR_EMPTY_PASSWORD; $password_highlight = INPUT_ERROR_STYLE; break; case (md5($_POST['password']) != $existingUser['password']): $error = ERROR_WRONG_PASSWORD; $password_highlight = INPUT_ERROR_STYLE; break; default: $this->SetUser($existingUser); $this->Redirect($url, ''); } } // BEGIN *** Register *** else // otherwise, proceed to registration { //added for freecap CAPTCHA if(!empty($_SESSION['freecap_word_hash']) && !empty($_POST['word'])) { // all freeCap words are lowercase. // font #4 looks uppercase, but trust me, it's not... if($_SESSION['hash_func'](strtolower($_POST['word']))==$_SESSION['freecap_word_hash']) { // reset freeCap session vars // cannot stress enough how important it is to do this // defeats re-use of known image with spoofed session id $_SESSION['freecap_attempts'] = 0; $_SESSION['freecap_word_hash'] = false; // now go somewhere else // header("Location: somewhere.php"); $name = trim($_POST['name']); $email = trim($this->GetSafeVar('email', 'post')); $password = $_POST['password']; $confpassword = $_POST['confpassword']; // validate input switch(TRUE) { case (strlen($name) == 0): $error = ERROR_EMPTY_USERNAME; $username_highlight = INPUT_ERROR_STYLE; break; case (!$this->IsWikiName($name)): $error = ERROR_WIKINAME; $username_highlight = INPUT_ERROR_STYLE; break; case ($this->ExistsPage($name)): $error = ERROR_RESERVED_PAGENAME; $username_highlight = INPUT_ERROR_STYLE; break; case (strlen($password) == 0): $error = ERROR_EMPTY_PASSWORD; $password_highlight = INPUT_ERROR_STYLE; break; case (preg_match("/ /", $password)): $error = ERROR_NO_BLANK; $password_highlight = INPUT_ERROR_STYLE; break; case (strlen($password) < PASSWORD_MIN_LENGTH): $error = sprintf(ERROR_PASSWORD_TOO_SHORT, PASSWORD_MIN_LENGTH); $password_highlight = INPUT_ERROR_STYLE; break; case (strlen($confpassword) == 0): $error = ERROR_EMPTY_CONFIRMATION_PASSWORD; $password_highlight = INPUT_ERROR_STYLE; $password_confirm_highlight = INPUT_ERROR_STYLE; break; case ($confpassword != $password): $error = ERROR_PASSWORD_MATCH; $password_highlight = INPUT_ERROR_STYLE; $password_confirm_highlight = INPUT_ERROR_STYLE; break; case (strlen($email) == 0): $error = ERROR_EMAIL_ADDRESS_REQUIRED; $email_highlight = INPUT_ERROR_STYLE; $password_highlight = INPUT_ERROR_STYLE; $password_confirm_highlight = INPUT_ERROR_STYLE; break; case (!preg_match(VALID_EMAIL_PATTERN, $email)): $error = ERROR_INVALID_EMAIL_ADDRESS; $email_highlight = INPUT_ERROR_STYLE; $password_highlight = INPUT_ERROR_STYLE; $password_confirm_highlight = INPUT_ERROR_STYLE; break; default: //valid input, create user $this->Query("INSERT INTO ".$this->config['table_prefix']."users SET ". "signuptime = now(), ". "name = '".mysql_real_escape_string($name)."', ". "email = '".mysql_real_escape_string($email)."', ". "password = md5('".mysql_real_escape_string($_POST['password'])."')"); // log in $this->SetUser($this->LoadUser($name)); $params .= 'registered=true'; $this->Redirect($url.$params); } } else { $captcha="You entered the wrong letters, please try again."; } } else { $captcha="You entered none of the letters. Please do so."; } } // END *** Register *** } // BEGIN *** Usersettings *** elseif (isset($_POST['action']) && ($_POST['action'] == 'updatepass')) { $name = trim($_POST['yourname']); if (strlen($name) == 0) // empty username { $newerror = ERROR_EMPTY_USERNAME; $username_temp_highlight = INPUT_ERROR_STYLE; } elseif (!$this->IsWikiName($name)) // check if name is WikiName style { $newerror = ERROR_WIKINAME; $username_temp_highlight = INPUT_ERROR_STYLE; } elseif (!($this->LoadUser($_POST['yourname']))) //check if user exists { $newerror = ERROR_NON_EXISTENT_USERNAME; $username_temp_highlight = INPUT_ERROR_STYLE; } elseif ($existingUser = $this->LoadUser($_POST['yourname'])) // if user name already exists, check password { // updatepassword if ($existingUser['password'] == $_POST['temppassword']) { $this->SetUser($existingUser, $_POST['remember']); $this->Redirect($url); } else { $newerror = ERROR_WRONG_PASSWORD; $password_temp_highlight = INPUT_ERROR_STYLE; } } } // END *** Usersettings *** // BEGIN *** Login/Register *** print($this->FormOpen()); ?> '."\n"; break; case (isset($success)): echo ''."\n"; break; // added for FreeCap CAPTCHA case (isset($captcha)): echo ''."\n"; break; } ?>
Format(REGISTER_HEADING) ?>  
  Format(REGISTERED_USER_LOGIN_LABEL); ?>
'.$this->Format($error).'
'.$this->Format($success).'
'.$this->Format($captcha).'
name="name" size="40" value="GetSafeVar('name', 'post'); ?>" />
type="password" name="password" size="40" />
 
  Format(NEW_USER_REGISTER_LABEL); ?>
type="password" name="confpassword" size="40" />
name="email" size="40" value="" />
If you can't read the word, click here
 
FormClose()); // END *** Login/Register *** // BEGIN *** Login Temp Password *** print($this->FormOpen()); ?> '."\n"); } ?>


Format(RETRIEVE_PASSWORD_HEADING) ?>
Format(RETRIEVE_PASSWORD_MESSAGE) ?>
'.$this->Format($newerror).'
name="yourname" value="GetSafeVar('yourname', 'post'); ?>" size="40" />
name="temppassword" size="40" />
 
FormClose()); // END *** Login Temp Password *** } ?> %% **actions/usersettings/usersettings.php** (//version 1.1.7 [trunk] only//) %%(php) '.WIKINAME_SHORT.''; //create URL $url = $this->Href(); //Remember referring page if internal. // - Getting correct regex to find the tag of referring page preg_match('/^(.*)ReferrerMarker/', $this->Href('', 'ReferrerMarker'), $match); $regex_referrer = '/^'.preg_quote($match[1], '/')."([^\\/\\?&]*)/"; if (isset($_SERVER['HTTP_REFERER']) && preg_match($regex_referrer, $_SERVER['HTTP_REFERER'], $match)) { if (strcasecmp($this->tag, $match[1])) { $_SESSION['go_back'] = $_SERVER['HTTP_REFERER']; //We save the tag of the referring page, this tag is to be shown in label . We must use a session here because if the user //Refresh the page by hitting on the address bar, the value would be lost. $_SESSION['go_back_tag'] = $match[1]; } } // append URL params depending on rewrite_mode $params = ($this->config['rewrite_mode'] == 1) ? '?' : '&'; // BEGIN *** Logout *** // is user trying to log out? if (isset($_POST['logout']) && $_POST['logout'] == LOGOUT_BUTTON) // replaced with normal form button #353, #312 { $this->LogoutUser(); } // END *** Logout *** // BEGIN *** Usersettings *** // user is still logged in if ($user = $this->GetUser()) { // is user trying to update user settings? if (isset($_POST['action']) && ($_POST['action'] == 'update')) { // get POST parameters $email = $this->GetSafeVar('email', 'post'); $doubleclickedit = $this->GetSafeVar('doubleclickedit', 'post'); $show_comments = $this->GetSafeVar('show_comments', 'post'); $default_comment_display = $this->GetSafeVar('default_comment_display', 'post'); $revisioncount = (int) $this->GetSafeVar('revisioncount', 'post'); $changescount = (int) $this->GetSafeVar('changescount', 'post'); // validate form input switch (TRUE) { case (strlen($email) == 0): //email is empty $error = ERROR_EMPTY_EMAIL_ADDRESS; $email_highlight = INPUT_ERROR_STYLE; break; case (!preg_match(VALID_EMAIL_PATTERN, $email)): //invalid email $error = ERROR_INVALID_EMAIL_ADDRESS; $email_highlight = INPUT_ERROR_STYLE; break; case (($revisioncount < REVISION_DISPLAY_LIMIT_MIN) || ($revisioncount > REVISION_DISPLAY_LIMIT_MAX)): //invalid revision display limit $error = sprintf(ERROR_INVALID_REVISION_DISPLAY_LIMIT, REVISION_DISPLAY_LIMIT_MAX); $revisioncount_highlight = INPUT_ERROR_STYLE; break; case (($changescount < RECENTCHANGES_DISPLAY_LIMIT_MIN) || ($changescount > RECENTCHANGES_DISPLAY_LIMIT_MAX)): //invalid recentchanges display limit $error = sprintf(ERROR_INVALID_RECENTCHANGES_DISPLAY_LIMIT, RECENTCHANGES_DISPLAY_LIMIT_MAX); $changescount_highlight = INPUT_ERROR_STYLE; break; default: // input is valid $this->Query('UPDATE '.$this->config['table_prefix'].'users SET '. "email = '".mysql_real_escape_string($email)."', ". "doubleclickedit = '".mysql_real_escape_string($doubleclickedit)."', ". "show_comments = '".mysql_real_escape_string($show_comments)."', ". "default_comment_display = '".mysql_real_escape_string($default_comment_display)."', ". "revisioncount = '".mysql_real_escape_string($revisioncount)."', ". "changescount = '".mysql_real_escape_string($changescount)."' ". "WHERE name = '".$user['name']."' LIMIT 1"); unset($this->specialCache['user'][strtolower($user['name'])]); //invalidate cache if exists #368 $this->SetUser($this->LoadUser($user["name"])); } } //user just logged in else { // get stored settings $email = $user['email']; $doubleclickedit = $user['doubleclickedit']; $show_comments = $user['show_comments']; $default_comment_display = $user['default_comment_display']; $revisioncount = $user['revisioncount']; $changescount = $user['changescount']; } // display user settings form echo $this->FormOpen(); ?>
Link($user['name'])); ?>
'.$error.'
'."\n"; break; case (isset($success)): echo ''.$success.'
'."\n"; break; } if (isset($_POST['action']) && ($_POST['action'] == 'changepass')) { // check password $oldpass = $_POST['oldpass']; //can be current password or hash sent as password reminder $password = $_POST['password']; $password_confirm = $_POST['password_confirm']; $update_option = $this->GetSafeVar('update_option', 'post'); switch (TRUE) { case (strlen($oldpass) == 0): $passerror = ERROR_EMPTY_PASSWORD_OR_HASH; $password_highlight = INPUT_ERROR_STYLE; break; case (($update_option == 'pw') && md5($oldpass) != $user['password']): //wrong old password $passerror = ERROR_INVALID_OLD_PASSWORD; $pw_selected = 'selected="selected"'; $password_highlight = INPUT_ERROR_STYLE; break; case (($update_option == 'hash') && $oldpass != $user['password']): //wrong reminder (hash) $passerror = ERROR_INVALID_HASH; $hash_selected = 'selected="selected"'; $password_highlight = INPUT_ERROR_STYLE; break; case (strlen($password) == 0): $passerror = ERROR_EMPTY_NEW_PASSWORD; $password_highlight = INPUT_ERROR_STYLE; $password_new_highlight = INPUT_ERROR_STYLE; break; case (preg_match("/ /", $password)): $passerror = ERROR_PASSWORD_NO_BLANK; $password_highlight = INPUT_ERROR_STYLE; $password_new_highlight = INPUT_ERROR_STYLE; break; case (strlen($password) < PASSWORD_MIN_LENGTH): $passerror = sprintf(ERROR_PASSWORD_TOO_SHORT, PASSWORD_MIN_LENGTH); $password_highlight = INPUT_ERROR_STYLE; $password_new_highlight = INPUT_ERROR_STYLE; break; case (strlen($password_confirm) == 0): $passerror = ERROR_EMPTY_NEW_CONFIRMATION_PASSWORD; $password_highlight = INPUT_ERROR_STYLE; $password_new_highlight = INPUT_ERROR_STYLE; $password_confirm_highlight = INPUT_ERROR_STYLE; break; case ($password_confirm != $password): $passerror = ERROR_PASSWORD_MATCH; $password_highlight = INPUT_ERROR_STYLE; $password_new_highlight = INPUT_ERROR_STYLE; $password_confirm_highlight = INPUT_ERROR_STYLE; break; default: $this->Query('UPDATE '.$this->config['table_prefix'].'users SET '."password = md5('".mysql_real_escape_string($password)."') "."WHERE name = '".$user['name']."'"); unset($this->specialCache['user'][strtolower($name)]); //invalidate cache if exists #368 $user['password'] = md5($password); $this->SetUser($user); $passsuccess = USER_PASSWORD_CHANGED_SUCCESS; } } ?> name="email" value="htmlspecialchars_ent($email) ?>" size="40" />
/>
/>
/>
/>
/>

name="revisioncount" value="htmlspecialchars_ent($revisioncount) ?>" size="40" />
name="changescount" value="htmlspecialchars_ent($changescount) ?>" size="40" />

FormClose(); //close user settings form //display password update form echo $this->FormOpen(); ?>
'.$passerror.'
'."\n"; } else if (isset($passsuccess)) { echo ''.$passsuccess.'
'."\n"; } ?> type="password" name="oldpass" size="40" />
type="password" name="password" size="40" />
type="password" name="password_confirm" size="40" />

FormClose(); } // END *** Usersettings *** // BEGIN *** LOGIN/LOGOUT *** else // user is not logged in { // print confirmation message on successful logout if (isset($_POST['logout']) && $_POST['logout'] == LOGOUT_BUTTON) { $success = USER_LOGGED_OUT_SUCCESS; } // is user trying to log in or register? $register = $this->GetConfigValue('allow_user_registration'); if (isset($_POST['action']) && ($_POST['action'] == 'login')) { // if user name already exists, check password if (isset($_POST['name']) && $existingUser = $this->LoadUser($_POST['name'])) { // check password switch(TRUE){ case (strlen($_POST['password']) == 0): $error = ERROR_EMPTY_PASSWORD; $password_highlight = INPUT_ERROR_STYLE; break; case (md5($_POST['password']) != $existingUser['password']): $error = ERROR_INVALID_PASSWORD; $password_highlight = INPUT_ERROR_STYLE; break; default: $this->SetUser($existingUser); if ((isset($_SESSION['go_back'])) && (isset($_POST['do_redirect']))) { $go_back = $_SESSION['go_back']; unset($_SESSION['go_back']); unset($_SESSION['go_back_tag']); $this->Redirect($go_back); } $this->Redirect($url, ''); } } // END *** Login/Logout *** // BEGIN *** Register *** // 3 = captcha registration else if ($register == '1' || $register == '2' || $register == '3') // otherwise, proceed to registration { if($register == '3' && (empty($_SESSION['freecap_word_hash']) || empty($_POST['word']))) { $captcha="You entered none of the letters. Please do so."; } else if($register == '3' && !($_SESSION['hash_func'](strtolower($_POST['word']))==$_SESSION['freecap_word_hash'])) { $captcha="You entered the wrong letters, please try again."; } else { $name = trim($_POST['name']); $email = trim($this->GetSafeVar('email', 'post')); $password = $_POST['password']; $confpassword = $_POST['confpassword']; // validate input switch(TRUE) { case (strlen($name) == 0): $error = ERROR_EMPTY_USERNAME; $username_highlight = INPUT_ERROR_STYLE; break; case (!$this->IsWikiName($name)): $error = $this->Format(sprintf(ERROR_WIKINAME,'##""WikiName""##','##""'.WIKKA_SAMPLE_WIKINAME.'""##')); $username_highlight = INPUT_ERROR_STYLE; break; case ($this->ExistsPage($name)): $error = ERROR_RESERVED_PAGENAME; $username_highlight = INPUT_ERROR_STYLE; break; case (strlen($password) == 0): $error = ERROR_EMPTY_PASSWORD; $password_highlight = INPUT_ERROR_STYLE; break; case (preg_match("/ /", $password)): $error = ERROR_NO_BLANK; $password_highlight = INPUT_ERROR_STYLE; break; case (strlen($password) < PASSWORD_MIN_LENGTH): $error = sprintf(ERROR_PASSWORD_TOO_SHORT, PASSWORD_MIN_LENGTH); $password_highlight = INPUT_ERROR_STYLE; break; case (strlen($confpassword) == 0): $error = ERROR_EMPTY_CONFIRMATION_PASSWORD; $password_highlight = INPUT_ERROR_STYLE; $password_confirm_highlight = INPUT_ERROR_STYLE; break; case ($confpassword != $password): $error = ERROR_PASSWORD_MATCH; $password_highlight = INPUT_ERROR_STYLE; $password_confirm_highlight = INPUT_ERROR_STYLE; break; case (strlen($email) == 0): $error = ERROR_EMAIL_ADDRESS_REQUIRED; $email_highlight = INPUT_ERROR_STYLE; $password_highlight = INPUT_ERROR_STYLE; $password_confirm_highlight = INPUT_ERROR_STYLE; break; case (!preg_match(VALID_EMAIL_PATTERN, $email)): $error = ERROR_INVALID_EMAIL_ADDRESS; $email_highlight = INPUT_ERROR_STYLE; $password_highlight = INPUT_ERROR_STYLE; $password_confirm_highlight = INPUT_ERROR_STYLE; break; case ($register == '2' && $_POST['invitation_code'] !== $this->GetConfigValue('invitation_code')): $error = ERROR_INVALID_INVITATION_CODE; $invitation_code_highlight = INPUT_ERROR_STYLE; break; default: //valid input, create user $this->Query("INSERT INTO ".$this->config['table_prefix']."users SET ". "signuptime = now(), ". "name = '".mysql_real_escape_string($name)."', ". "email = '".mysql_real_escape_string($email)."', ". "password = md5('".mysql_real_escape_string($_POST['password'])."')"); unset($this->specialCache['user'][strtolower($name)]); //invalidate cache if exists #368 // log in $this->SetUser($this->LoadUser($name)); if ((isset($_SESSION['go_back'])) && (isset($_POST['do_redirect']))) { $go_back = $_SESSION['go_back']; unset($_SESSION['go_back']); $this->Redirect($go_back); } $_SESSION['usersettings_registered'] = true; $this->Redirect($url.$params); } } } } // END *** Register *** // BEGIN *** Usersettings *** elseif (isset($_POST['action']) && ($_POST['action'] == 'updatepass')) { $name = trim($_POST['yourname']); if (strlen($name) == 0) // empty username { $newerror = WIKKA_ERROR_EMPTY_USERNAME; $username_temp_highlight = INPUT_ERROR_STYLE; } elseif (!$this->IsWikiName($name)) // check if name is WikiName style { $newerror = ERROR_WIKINAME; $username_temp_highlight = INPUT_ERROR_STYLE; } elseif (!($this->LoadUser($_POST['yourname']))) //check if user exists { $newerror = ERROR_NONEXISTENT_USERNAME; $username_temp_highlight = INPUT_ERROR_STYLE; } elseif ($existingUser = $this->LoadUser($_POST['yourname'])) // if user name already exists, check password { // updatepassword if ($existingUser['password'] == $_POST['temppassword']) { $this->SetUser($existingUser, $_POST['remember']); $this->Redirect($url); } else { $newerror = ERROR_WRONG_PASSWORD; $password_temp_highlight = INPUT_ERROR_STYLE; } } } // END *** Usersettings *** // BEGIN *** Login/Logout *** // BEGIN *** Register *** print($this->FormOpen()); if($register == '3') { ?>
'.$error.'
'."\n"; break; case (isset($success)): echo ''.$success.'
'."\n"; break; case (isset($captcha)): echo ''.$this->Format($captcha).''."\n"; break; } ?>
name="name" size="40" value="GetSafeVar('name', 'post'); ?>" />
type="password" name="password" size="40" />
/>


GetConfigValue('allow_user_registration'); if ($register == '1' || $register == '2' || $register == '3') { ?>
type="password" name="confpassword" size="40" />
name="email" size="40" value="" />

?> '.INVITATION_CODE_SHORT.'' ?> size="20" name="invitation_code" />

'."\n"; print($this->FormClose()); // END *** Register *** print($this->FormOpen()); ?>
'.$newerror.'
'."\n"; } $retrieve_password_link = 'PasswordForgotten'; $retrieve_password_caption = $this->Format(sprintf(RETRIEVE_PASSWORD_CAPTION,$retrieve_password_link)); ?>
name="yourname" value="GetSafeVar('yourname', 'post'); ?>" size="40" />
name="temppassword" size="40" />

FormClose()); } ?> %% === Problems === Integration went very straight after the example that comes with the package except for one thing. The ""FreeCap"" script assumed a standard php session to use but because Wikka uses a custom session name it missed this. Since this is no link (no href but rather a src where the freecap.php is linked) I couldn't give the name to the script via URL (also it would be visible then) so I put the name in a cookie. This works and I don't think it's insecure for the cookie can't be read by anyone else but the one who placed it. Of course it doesn't work when cookies are off. If anyone could come up with a better solution that would be great. ~& You will also need to pass the session name saved in the cookie to the freecap.php script by including the following statement **before** session_start() in freecap.php: %%session_name($_COOKIE['sessname']);%%. Also, if you decide to relocate your freecap dir to another location (for instance, under ##3rdparty/plugins/freenode##), you must also modify the setcookie() call so that the cookie is accessible by the freecap.php script. The quick and dirty way to do this would be: %%setcookie('sessname', session_name(), 0, '/');%%. === Note for Rewrite Users === The image will not show up unless you exclude it in your mod_rewrite settings. For example, I initially had a rewrite rule found elsewhere on this site that didn't exclude rewriting for the actions directory. %% RewriteRule ^(css|images|wikiedit2)/(.*)$ $1/$2 [L] %% Changing that rule to include the actions directory, like as follows, fixed the problem. %% RewriteRule ^(actions|css|images|wikiedit2)/(.*)$ $1/$2 [L] %% ~& If you didn't define a list with directories to exclude from rewrite, you can also copy an .htaccess -file into the actions directory - or any other directory you want to be accessable - containing the simple rule to turn rewrite off for that directory: %% RewriteEngine off %% === Customization === You can edit the freecap.php to customize the CAPTCHAs, change the hash encryption and type of image format. The script can use a dictionary to read the words from but I prefer random letters although they're hard to read sometimes. The dictionary must NOT be readable on your webspace (check it!) if you use it. In addition there should be an option for people who can't see the CAPTCHA to register on the site (the ""FreeCap"" author suggests to let them register and check those registrations manually but audio CAPTCHA would also be possible). Any comments are appreciated! ---- CategoryUserContributions