Wiki source for FudLogin


Show raw source

=====""FudLogin"" Mod=====

This is a try for an advanced "Single Login System" for Wikka Wiki in combination with an [[http://fudforum.org/forum/ | FUDForum]] based forum installation. It will allow anyone to log in with his forum login and password. On the first login, a user has to choose his WikiName, he likes to use.

I had the following goals in mind, when developing this mod:
- Simple installation
- Has to work with different databases for forum and wiki
- Has to work even if the wiki already has several [[WikiName]]s, pages, ACLs, UserPages, ... After the change to the new login system, any forum user has to be able to get back his old WikiName
- Even if the user has a "non CamelCase" nick in the forum, he has to be able to choose a "real WikiName" for the Wiki.

To install this mod, you at first have to specify the path to your forum in your wikka.config.php in the following way:
%%(php;1)
"fudlogin_forumpath" => "../FUDForum" // Replace with relative path to your "non HTTP reachable" forum files (backend).
%%

Then **replace** the file actions/usersettings.php with the version at the end of this page.

After doing so, any user is immediately able to login with his forum login data. Users, which already had a WikiName, will be able to enter the old WikiName on the first login. This will migrate the old WikiName to the new login system.
Users, which didn't already have a WikiName, will just choose a new one, which hasn't been already taken by someone else and isn't already in use as name for a page on your wiki.



This is the replacement for actions/usersettings.php:
%%(php;1)
<?php
// Modded usersettings.php to login against the FUDForum user database
// Copyright (C) Manuel Reimer (Manuel _dot_ Reimer _at_ gmx _dot_ de)
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// version 2 as published by the Free Software Foundation

/* !!!!!!!! THIS IS A MODDED FILE AND NOT PART OF WIKKA WIKI !!!!!!!!! */
/* More infos on this mod here: http://wikkawiki.org/FudLogin */

// defaults
if (!defined('REVISION_DISPLAY_LIMIT_MIN')) define('REVISION_DISPLAY_LIMIT_MIN', "0"); // 0 means no limit, 1 is the minimum number of revisions
if (!defined('REVISION_DISPLAY_LIMIT_MAX')) define('REVISION_DISPLAY_LIMIT_MAX', "20"); // keep this value within a reasonable limit to avoid an unnecessary long lists
if (!defined('RECENTCHANGES_DISPLAY_LIMIT_MIN')) define('RECENTCHANGES_DISPLAY_LIMIT_MIN', "0"); // 0 means no limit, 1 is the minimum number of changes
if (!defined('RECENTCHANGES_DISPLAY_LIMIT_MAX')) define('RECENTCHANGES_DISPLAY_LIMIT_MAX', "50"); // keep this value within a reasonable limit to avoid an unnecessary long list
if (!defined('INPUT_ERROR_STYLE')) define('INPUT_ERROR_STYLE', 'class="highlight"');

// i18n strings
if (!defined('USER_SETTINGS_HEADING')) define('USER_SETTINGS_HEADING', "User settings");
if (!defined('USER_LOGGED_OUT')) define('USER_LOGGED_OUT', "You have successfully logged out.");
if (!defined('USER_SETTINGS_STORED')) define('USER_SETTINGS_STORED', "User settings stored!");
if (!defined('USER_EMAIL_LABEL')) define('USER_EMAIL_LABEL', "Your email address:");
if (!defined('DOUBLECLICK_LABEL')) define('DOUBLECLICK_LABEL', "Doubleclick Editing:");
if (!defined('SHOW_COMMENTS_LABEL')) define('SHOW_COMMENTS_LABEL', "Show comments by default:");
if (!defined('RECENTCHANGES_DISPLAY_LIMIT_LABEL')) define('RECENTCHANGES_DISPLAY_LIMIT_LABEL', "RecentChanges display limit:");
if (!defined('PAGEREVISION_LIST_LIMIT_LABEL')) define('PAGEREVISION_LIST_LIMIT_LABEL', "Page revisions list limit:");
if (!defined('UPDATE_SETTINGS_INPUT')) define('UPDATE_SETTINGS_INPUT', "Update Settings");
if (!defined('QUICK_LINKS_HEADING')) define('QUICK_LINKS_HEADING', "Quick links");
if (!defined('QUICK_LINKS')) define('QUICK_LINKS', "See a list of pages you own (MyPages) and pages you've edited (MyChanges).");

if (!defined('ERROR_INVALID_REVISION_DISPLAY_LIMIT')) define('ERROR_INVALID_REVISION_DISPLAY_LIMIT', "The number of page revisions should not exceed %d.");
if (!defined('ERROR_INVALID_RECENTCHANGES_DISPLAY_LIMIT')) define('ERROR_INVALID_RECENTCHANGES_DISPLAY_LIMIT', "The number of recently changed pages should not exceed %d.");
if (!defined('WIKINAME_LABEL')) define('WIKINAME_LABEL', "Your <abbr title=\"A WikiName is formed by two or more capitalized words without space, e.g. JohnDoe\">WikiName</abbr>:");
if (!defined('LOGIN_BUTTON_LABEL')) define('LOGIN_BUTTON_LABEL', "Login");
if (!defined('LOGOUT_BUTTON_LABEL')) define('LOGOUT_BUTTON_LABEL', "Logout");

if (!defined('FUD_LOGIN_HEADING')) define('FUD_LOGIN_HEADING', "===Login===");
if (!defined('FUD_REGISTER_HEADING')) define('FUD_REGISTER_HEADING', "===Register===");
if (!defined('FUD_REGISTER_LABEL')) define('FUD_REGISTER_LABEL', "Any forum login may be used to login here. If you don't have one, then <a href=\"%s\"> get one for free</a>");
if (!defined('FUD_REGISTERED_USER_LOGIN_LABEL')) define('FUD_REGISTERED_USER_LOGIN_LABEL', "You may use your Forum login data, to log in here.");
if (!defined('FUD_LOGINNAME_LABEL')) define('FUD_LOGINNAME_LABEL', "Your Forum Login Name:");
if (!defined('FUD_PASSWORD_LABEL')) define('FUD_PASSWORD_LABEL', "Password:");
if (!defined('FUD_NEW_USER_REGISTER_LABEL')) define('FUD_NEW_USER_REGISTER_LABEL', "If you log in in for the first time, then you have to set your WikiName here. The WikiName will be used instead of your login name, to identify changes and contributions with you. It may be the best to just \"reformat\" your login name, to be in valid WikiName syntax.");
if (!defined('FUD_ERROR_WRONG_LOGIN_PASSWORD')) define('FUD_ERROR_WRONG_LOGIN_PASSWORD', "You entered a wrong username or password");
if (!defined('FUD_ERROR_UNCONFIRMED_ACCOUNT')) define('FUD_ERROR_UNCONFIRMED_ACCOUNT', "Your account has not been activated by an administrator, so far.");
if (!defined('FUD_ERROR_UNCONFIRMED_MAIL')) define('FUD_ERROR_UNCONFIRMED_MAIL', "You have not confirmed your account via mail, so far.");
if (!defined('FUD_ERROR_WIKINAME')) define('FUD_ERROR_WIKINAME', "Username must be formatted as a ##\"\"WikiName\"\"##, e.g. ##\"\"JohnDoe\"\"##.");
if (!defined('FUD_ERROR_EMPTY_WIKINAME')) define('FUD_ERROR_EMPTY_WIKINAME', "This is your first Wiki login, so you have to choose a valid \"\"WikiName\"\".");
if (!defined('FUD_ERROR_RESERVED_PAGENAME')) define('FUD_ERROR_RESERVED_PAGENAME', "Sorry, this \"\"WikiName\"\" is reserved for a page. Please choose a different name.");
if (!defined('FUD_ERROR_RESERVED_WIKINAME')) define('FUD_ERROR_RESERVED_WIKINAME', "Sorry, this WikiName is already taken by someone else.");

//initialize variables
$params = '';
$url = '';
$email = '';
$wikkauser = '';
$doubleclickedit = '';
$show_comments = '';
$revisioncount = '';
$changescount = '';
$username_highlight = '';
$wikiname_highlight = '';
$revisioncount_highlight = '';
$changescount_highlight = '';


//
// "Installation" of FUDLogin. This will create the DB table, if not
// already there
//

@mysql_query(
"CREATE TABLE ".$this->config["table_prefix"]."fudlogintranslate (".
"wikkauser varchar(75) NOT NULL default '',".
"fuduser varchar(50) NOT NULL default '',".
"PRIMARY KEY (fuduser),".
"UNIQUE (wikkauser)" .
") TYPE=MyISAM;", $this->dblink
);
$err = mysql_errno();
// Ignore error "Table already exists", but exit for all other errors!
if ($err && $err != 1050)
die(mysql_error());

//
// Start of FUDForum connection code.
//

// Returns the FUDForum configuration settings by parsing "GLOBALS.php". The
// settings are returned as array, so we don't get into conflict with other
// variables.
function fudforum_get_cfg($wikkaref) {
if (!isset($wikkaref->config["fudlogin_forumpath"]))
die('Please set "fudlogin_forumpath" in your "wikka.config.php" file');
$cfg_path = $wikkaref->config["fudlogin_forumpath"];
$cfg_path .= "/include/GLOBALS.php";
if (!file_exists($cfg_path))
die('Path in "fudlogin_forumpath" seems to be invalid! The file "' . $cfg_path . '" doesn\'t exist!');
$code = file_get_contents($cfg_path);
$tokens = token_get_all($code);
$fudcfg = array();
$varname = false;
foreach ($tokens as $token) {
if (!is_array($token)) continue;
switch($token[0]) {
case(T_VARIABLE):
$varname = $token[1];
$varname = str_replace("$", "", $varname);
break;
case(T_CONSTANT_ENCAPSED_STRING):
// Drop the quotes on string values
$token[1] = substr($token[1], 1, strlen($token[1]) - 2);
case(T_LNUMBER):
if ($varname) {
$fudcfg[$varname] = $token[1];
$varname = false;
}
break;
}
}
return $fudcfg;
}

// Returns a data object for valid login, returns "false" for invalid login.
function fudforum_fetch_user($wikkaref, $login, $passwd) {
$fudcfg = fudforum_get_cfg($wikkaref);

// Connect to the forum DB. PHP will reuse "$this->dblink", if forum and
// wiki are on the same DB!
$fud_dblink = mysql_connect($fudcfg["DBHOST"], $fudcfg["DBHOST_USER"], $fudcfg["DBHOST_PASSWORD"]);
if (!$fud_dblink ||
!mysql_select_db($fudcfg["DBHOST_DBNAME"], $fud_dblink))
die("Failed to open forum database!");

// Query for user data. Use the password in the query, so a wrong password
// will return an empty query
$result = mysql_query(sprintf(
"SELECT id, email, users_opt FROM %s WHERE login = '%s' AND passwd = '%s'",
$fudcfg["DBHOST_TBL_PREFIX"] . "users",
mysql_real_escape_string($login),
md5($passwd)
), $fud_dblink);
if (mysql_num_rows($result) != 1) return false;

$data = mysql_fetch_object($result);

// MySQL-Part is now finished, so it's time to clean up
// We *don't* close the connection on "$fud_dblink", as this is the same as
// "$this->dblink", if forum and wiki are on the same DB!
// The only thing, we do, is to re-select the right DB for "$this->dblink".
mysql_select_db($wikkaref->config['mysql_database'], $wikkaref->dblink);

// Anonymous users may not log in!
if ($data->id < 2) return false;
unset($data->id);

// Decode the parts of "users_opt", we need.
$flags = $data->users_opt;
$data->mailconfirmed = ($flags & 131072);
$data->banned = ($flags & 65536);
$data->acctconfirmed = !($flags & 2097152);
unset($data->users_opt);

return $data;
}

// Returns link to forum
function fudforum_get_forumlink($wikkaref) {
$fudcfg = fudforum_get_cfg($wikkaref);
return $fudcfg["WWW_ROOT"] . "index.php";
}

//
// End of FUDForum connection code.
//


//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($_POST['logout']) && $_POST['logout'] == LOGOUT_BUTTON_LABEL)
{
$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
$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 (($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 '.
"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 '<h3>'.USER_SETTINGS_HEADING.'</h3>';
echo $this->FormOpen();
?>
<input type="hidden" name="action" value="update" />
<table class="usersettings">
<tr>
<td> </td>
<td>Hello, <?php echo $this->Link($user['name']) ?>!</td>
</tr>
<?php

// create confirmation message if needed
switch(TRUE)
{
case (isset($_GET['stored']) && $_GET['stored'] == 'true'):
$success = USER_SETTINGS_STORED;
break;
}

// display error or confirmation message
switch(TRUE)
{
case (isset($error)):
echo '<tr><td></td><td><em class="error">'.$this->Format($error).'</em></td></tr>'."\n";
break;
case (isset($success)):
echo '<tr><td></td><td><em class="success">'.$this->Format($success).'</em></td></tr>'."\n";
break;
default:
}
?>
<tr>
<td align="right"><?php echo USER_EMAIL_LABEL ?></td>
<td><?php echo $this->htmlspecialchars_ent($email) ?></td>
</tr>
<tr>
<td align="right"><?php echo DOUBLECLICK_LABEL ?></td>
<td><input type="hidden" name="doubleclickedit" value="N" /><input type="checkbox" name="doubleclickedit" value="Y" <?php echo $doubleclickedit == 'Y' ? 'checked="checked"' : '' ?> /></td>
</tr>
<tr>
<td align="right"><?php echo SHOW_COMMENTS_LABEL ?></td>
<td><input type="hidden" name="show_comments" value="N" /><input type="checkbox" name="show_comments" value="Y" <?php echo $show_comments == 'Y' ? 'checked="checked"' : '' ?> /></td>
</tr>
<tr>
<td align="right"><?php echo PAGEREVISION_LIST_LIMIT_LABEL ?></td>
<td><input <?php echo $revisioncount_highlight; ?> name="revisioncount" value="<?php echo $this->htmlspecialchars_ent($revisioncount) ?>" size="40" /></td>
</tr>
<tr>
<td align="right"><?php echo RECENTCHANGES_DISPLAY_LIMIT_LABEL ?></td>
<td><input <?php echo $changescount_highlight; ?> name="changescount" value="<?php echo $this->htmlspecialchars_ent($changescount) ?>" size="40" /></td>
</tr>
<tr>
<td> </td>
<td><input type="submit" value="<?php echo UPDATE_SETTINGS_INPUT ?>" /><!-- <input type="button" value="<?php echo LOGOUT_BUTTON_LABEL; ?>" onclick="document.location='<?php echo $this->href('', '', 'action=logout'); ?>'" /></td>-->
<input id="logout" name="logout" type="submit" value="<?php echo LOGOUT_BUTTON_LABEL; ?>" /><!--#353,#312-->
</td>
</tr>
</table>
<?php
echo $this->FormClose(); //close user settings form
echo '<hr />'."\n";
echo '<h5>'.QUICK_LINKS_HEADING.'</h5>'."\n";
echo $this->Format(QUICK_LINKS);
}
// 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?
$email = false;
if (isset($_POST['name']) && isset($_POST['password'])) {
$data = fudforum_fetch_user($this, trim($_POST['name']), $_POST['password']);
if (!$data) {
$error = FUD_ERROR_WRONG_LOGIN_PASSWORD;
$username_highlight = INPUT_ERROR_STYLE;
}
else if (!$data->mailconfirmed)
$error = FUD_ERROR_UNCONFIRMED_MAIL;
else if (!$data->acctconfirmed)
$error = FUD_ERROR_UNCONFIRMED_ACCOUNT;
else
$email = $data->email;
}

// Valid Login (means, we fetched a valid email for the user from
// FUDForum login DB)
if ($email) {
$in_name = trim($_POST['name']);
$in_wikiname = trim($_POST["wikiname"]);

// Try to fetch wiki name for user. If there is none in our DB and
// the user-supplied wikiname is valid, then store the wikiname to
// the DB and continue with it.
$wikkauser = false;
$result = $this->Query(sprintf(
"SELECT wikkauser FROM %s WHERE fuduser = '%s'",
$this->config["table_prefix"]."fudlogintranslate",
mysql_real_escape_string($in_name)
));
if (mysql_num_rows($result) == 1) {
$obj = mysql_fetch_object($result);
$wikkauser = $obj->wikkauser;
}
else {
switch(TRUE) {
case (strlen($in_wikiname) == 0):
$error = FUD_ERROR_EMPTY_WIKINAME;
$wikiname_highlight = INPUT_ERROR_STYLE;
break;
case (!$this->IsWikiName($in_wikiname)):
$error = FUD_ERROR_WIKINAME;
$wikiname_highlight = INPUT_ERROR_STYLE;
break;
// Only match for "real" pages and not for UserPages (would
// block users with UserPage from migrating)
case ($this->ExistsPage($in_wikiname) && !$this->LoadUser($in_wikiname)):
$error = FUD_ERROR_RESERVED_PAGENAME;
$wikiname_highlight = INPUT_ERROR_STYLE;
break;
default: //valid input
// Query for the newly chosen Wiki name
$result = $this->Query(sprintf(
"SELECT wikkauser FROM %s WHERE wikkauser = '%s'",
$this->config["table_prefix"]."fudlogintranslate",
mysql_real_escape_string($in_wikiname)
));
// If the name is taken, then send error
if (mysql_num_rows($result) == 1) {
$error = FUD_ERROR_RESERVED_WIKINAME;
$wikiname_highlight = INPUT_ERROR_STYLE;
}
// Name not taken -> link it to the login name
else {
$this->Query(sprintf(
"INSERT INTO %s SET wikkauser = '%s', fuduser = '%s'",
$this->config["table_prefix"]."fudlogintranslate",
mysql_real_escape_string($in_wikiname),
mysql_real_escape_string($in_name)
));
$wikkauser = $in_wikiname;
}
}
}

// If we have a valid Wikka user now, then create an account for
// the WikiName or update the existing one
if ($wikkauser) {
$existingUser = $this->LoadUser($wikkauser);
if (!$existingUser) {
$this->Query(sprintf(
"INSERT INTO %s SET
signuptime = now(),
name = '%s',
email = '%s',
password = '%s'",
$this->config['table_prefix']."users",
mysql_real_escape_string($wikkauser),
mysql_real_escape_string($email),
md5($_POST['password'])
));
}
else {
$this->Query(sprintf(
"UPDATE %s SET
email = '%s',
password = '%s'
WHERE name = '%s'",
$this->config['table_prefix']."users",
mysql_real_escape_string($email),
md5($_POST['password']),
mysql_real_escape_string($wikkauser)
));
}
$this->SetUser($this->LoadUser($wikkauser));
$this->Redirect($url, '');
}
}

// BEGIN *** Login/Register ***
print($this->FormOpen());
?>
<input type="hidden" name="action" value="login" />
<table class="usersettings">
<tr>
<td colspan="2"><?php echo $this->Format(FUD_LOGIN_HEADING) ?></td>
<td> </td>
</tr>
<tr>
<td> </td>
<td><?php echo $this->Format(FUD_REGISTERED_USER_LOGIN_LABEL); ?></td>
</tr>
<?php
switch (true)
{
case (isset($error)):
echo '<tr><td></td><td><em class="error">'. $this->Format($error) .'</em></td></tr>'."\n";
break;
case (isset($success)):
echo '<tr><td></td><td><em class="success">'. $this->Format($success) .'</em></td></tr>'."\n";
break;
}
?>
<tr>
<td align="right"><?php echo FUD_LOGINNAME_LABEL ?></td>
<td><input <?php echo $username_highlight; ?> name="name" size="40" value="<?php echo $this->GetSafeVar('name', 'post'); ?>" /></td>
</tr>
<tr>
<td align="right"><?php echo FUD_PASSWORD_LABEL ?></td>
<td><input <?php echo $username_highlight; ?> type="password" name="password" size="40" /></td>
</tr>
<tr>
<td> </td>
<td><input type="submit" value="<?php echo LOGIN_BUTTON_LABEL ?>" size="40" /></td>
</tr>
<tr>
<td> </td>
<td width="500"><?php echo FUD_NEW_USER_REGISTER_LABEL; ?></td>
</tr>
<tr>
<td align="right"><?php echo WIKINAME_LABEL ?></td>
<td><input <?php echo $wikiname_highlight; ?> name="wikiname" size="40" /></td>
</tr>
<tr>
<td> </td>
<td><input type="submit" value="<?php echo LOGIN_BUTTON_LABEL ?>" size="40" /></td>
</tr>
<tr>
<td colspan="2"><?php echo $this->Format(FUD_REGISTER_HEADING) ?></td>
<td> </td>
</tr>
<tr>
<td> </td>
<td><?php printf(FUD_REGISTER_LABEL, fudforum_get_forumlink($this));?></td>
</tr>

</table>
<?php
print($this->FormClose());
// END *** Login/Register ***
}
?>
<!-- Please leave the following line unchanged -->
<div class="smallprint">Login powered by <a href="http://wikkawiki.org/FudLogin">FudLogin</a> written by <a href="mailto:Manuel.Reimer{at}gmx.de">Manuel Reimer</a>.</div>

%%

----
CategoryUserContributions
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki