$username and $password and authenticates
* them against the database. The passwords are encrypted using the crypt() function.
* The username is stored in the $_SESSION["wt_user"] session variable.
* @param string $user_name the username for the user attempting to login
* @param string $password the plain text password to test
* @param boolean $basic true if the userName and password were retrived via Basic HTTP authentication. Defaults to false. At this point, this is only used for logging
* @return the user_id if sucessful, false otherwise
*/
function authenticateUser($user_name, $password, $basic=false) {
// If we were already logged in, log out first
if (getUserId()) {
userLogout(getUserId());
}
if ($user_id=get_user_id($user_name)) {
$dbpassword=get_user_password($user_id);
if (crypt($password, $dbpassword)==$dbpassword) {
if (get_user_setting($user_id, 'verified')=='yes' && get_user_setting($user_id, 'verified_by_admin')=='yes' || get_user_setting($user_id, 'canadmin')=='Y') {
set_user_setting($user_id, 'loggedin', 'Y');
//-- reset the user's session
$_SESSION = array();
$_SESSION['wt_user'] = $user_id;
AddToLog(($basic ? 'Basic HTTP Authentication' :'Login'). ' Successful', 'auth');
return $user_id;
}
}
}
AddToLog(($basic ? 'Basic HTTP Authentication' : 'Login').' Failed ->'.$user_name.'<-', 'auth');
return false;
}
/**
* authenticate a username and password using Basic HTTP Authentication
*
* This function uses authenticateUser(), for authentication, but retrives the userName and password provided via basic auth.
* @return bool return true if the user is already logged in or the basic HTTP auth username and password credentials match a user in the database return false if they don't
* @TODO Security audit for this functionality
* @TODO Do we really need a return value here?
* @TODO should we reauthenticate the user even if already logged in?
* @TODO do we need to set the user language and other jobs done in login.php? Should that loading be moved to a function called from the authenticateUser function?
*/
function basicHTTPAuthenticateUser() {
$user_id = getUserId();
if (empty($user_id)){ //not logged in.
if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])
|| (! authenticateUser($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'], true))) {
header('WWW-Authenticate: Basic realm="' . i18n::translate('webtrees Authentication System') . '"');
header('HTTP/1.0 401 Unauthorized');
echo i18n::translate('You must enter a valid login ID and password to access this resource') ;
exit;
}
} else { //already logged in or successful basic authentication
return true; //probably not needed
}
}
/**
* logs a user out of the system
* @param string $user_id logout a specific user
*/
function userLogout($user_id) {
set_user_setting($user_id, 'loggedin', 'N');
if ($user_id != "Anonymous" and $user_id != "") {
AddToLog('Logout '.getUserName($user_id), 'auth');
}
// If we are logging ourself out, then end our session too.
if (WT_USER_ID==$user_id) {
session_destroy();
}
}
/**
* Updates the login time in the database of the given user
* The login time is used to automatically logout users who have been
* inactive for the defined session time
* @param string $username the username to update the login info for
*/
function userUpdateLogin($user_id) {
set_user_setting($user_id, 'sessiontime', time());
}
/**
* get the current user's ID and Name
*
* Returns 0 and NULL if we are not logged in.
*
* If you want to embed PGV within a content management system, you would probably
* rewrite these functions to extract the data from the parent system, and then
* populate PGV's user/user_setting/user_gedcom_setting tables as appropriate.
*
*/
function getUserId() {
if (empty($_SESSION['wt_user'])) {
return 0;
} else {
return $_SESSION['wt_user'];
}
}
function getUserName() {
if (getUserID()) {
return get_user_name(getUserID());
} else {
return null;
}
}
/**
* check if given username is an admin
*/
function userIsAdmin($user_id=WT_USER_ID) {
if ($user_id) {
return get_user_setting($user_id, 'canadmin')=='Y';
} else {
return false;
}
}
/**
* check if given username is an admin for the given gedcom
*/
function userGedcomAdmin($user_id=WT_USER_ID, $ged_id=WT_GED_ID) {
if ($user_id) {
return get_user_gedcom_setting($user_id, $ged_id, 'canedit')=='admin' || userIsAdmin($user_id);
} else {
return false;
}
}
/**
* check if the given user has access privileges on this gedcom
*/
function userCanAccess($user_id=WT_USER_ID, $ged_id=WT_GED_ID) {
if ($user_id) {
if (userIsAdmin($user_id)) {
return true;
} else {
$tmp=get_user_gedcom_setting($user_id, $ged_id, 'canedit');
return $tmp=='admin' || $tmp=='accept' || $tmp=='edit' || $tmp=='access';
}
} else {
return false;
}
}
/**
* check if the given user has write privileges for the given gedcom
*/
function userCanEdit($user_id=WT_USER_ID, $ged_id=WT_GED_ID) {
global $ALLOW_EDIT_GEDCOM;
if ($ALLOW_EDIT_GEDCOM && $user_id) {
if (userIsAdmin($user_id)) {
return true;
} else {
$tmp=get_user_gedcom_setting($user_id, $ged_id, 'canedit');
return $tmp=='admin' || $tmp=='accept' || $tmp=='edit';
}
} else {
return false;
}
}
/**
* check if the given user can accept changes for the given gedcom
*
* takes a username and checks if the user has write privileges to
* change the gedcom data and accept changes
* @param string $username the username of the user check privileges
* @return boolean true if user can accept false if user cannot accept
*/
function userCanAccept($user_id=WT_USER_ID, $ged_id=WT_GED_ID) {
global $ALLOW_EDIT_GEDCOM;
// An admin can always accept changes, even if editing is disabled
if (userGedcomAdmin($user_id, $ged_id)) {
return true;
}
if ($ALLOW_EDIT_GEDCOM) {
$tmp=get_user_gedcom_setting($user_id, $ged_id, 'canedit');
return $tmp=='admin' || $tmp=='accept';
} else {
return false;
}
}
/**
* Should user's changed automatically be accepted
*/
function userAutoAccept($user_id=WT_USER_ID) {
return get_user_setting($user_id, 'auto_accept')=='Y';
}
/**
* Does an admin user exist? Used to redirect to install/config page
* during initial setup.
*/
function adminUserExists() {
return admin_user_exists();
}
// Get the full name for a user
function getUserFullName($user_id) {
global $TBLPREFIX;
return WT_DB::prepare("SELECT real_name FROM {$TBLPREFIX}user WHERE user_id=?")->execute(array($user_id))->fetchOne();
}
// Set the full name for a user
function setUserFullName($user_id, $real_name) {
global $TBLPREFIX;
return WT_DB::prepare("UPDATE {$TBLPREFIX}user SET real_name=? WHERE user_id=?")->execute(array($real_name, $user_id));
}
// Get the email for a user
function getUserEmail($user_id) {
global $TBLPREFIX;
return WT_DB::prepare("SELECT email FROM {$TBLPREFIX}user WHERE user_id=?")->execute(array($user_id))->fetchOne();
}
// Set the email for a user
function setUserEmail($user_id, $email) {
global $TBLPREFIX;
return WT_DB::prepare("UPDATE {$TBLPREFIX}user SET email=? WHERE user_id=?")->execute(array($email, $user_id));
}
// Get the root person for this gedcom
function getUserRootId($user_id, $ged_id) {
if ($user_id) {
return get_user_gedcom_setting(WT_USER_ID, WT_GED_ID, 'rootid');
} else {
return getUserGedcomId($user_id, $ged_id);
}
}
// Get the user's ID in the given gedcom
function getUserGedcomId($user_id, $ged_id) {
if ($user_id) {
return get_user_gedcom_setting(WT_USER_ID, WT_GED_ID, 'gedcomid');
} else {
return null;
}
}
/**
* add a message into the log-file
*/
function AddToLog($log_message, $log_type='error') {
global $TBLPREFIX, $argc;
WT_DB::prepare(
"INSERT INTO {$TBLPREFIX}log (log_type, log_message, ip_address, user_id, gedcom_id) VALUES (?, ?, ?, ?, ?)"
)->execute(array(
$log_type,
$log_message,
$argc ? 'cli' : $_SERVER['REMOTE_ADDR'],
getUserId() ? getUserId() : null,
defined('WT_GED_ID') ? WT_GED_ID : null // logs raised before we select the gedcom won't have this.
));
}
//----------------------------------- AddToSearchLog
//-- requires a string to add into the searchlog-file
function AddToSearchLog($log_message, $geds) {
global $TBLPREFIX;
$all_geds=get_all_gedcoms();
foreach ($geds as $ged_id=>$ged_name) {
WT_DB::prepare(
"INSERT INTO {$TBLPREFIX}log (log_type, log_message, ip_address, user_id, gedcom_id) VALUES ('search', ?, ?, ?, ?)"
)->execute(array(
(count($all_geds)==count($geds) ? 'Global search: ' : 'Gedcom search: ').$log_message,
$_SERVER['REMOTE_ADDR'],
WT_USER_ID ? WT_USER_ID : null,
$ged_id
));
}
}
//----------------------------------- AddToChangeLog
//-- requires a string to add into the changelog-file
function AddToChangeLog($log_message, $ged_id=WT_GED_ID) {
global $TBLPREFIX;
WT_DB::prepare(
"INSERT INTO {$TBLPREFIX}log (log_type, log_message, ip_address, user_id, gedcom_id) VALUES ('change', ?, ?, ?, ?)"
)->execute(array(
$log_message,
$_SERVER['REMOTE_ADDR'],
WT_USER_ID ? WT_USER_ID : null,
$ged_id
));
}
//----------------------------------- addMessage
//-- stores a new message in the database
function addMessage($message) {
global $TBLPREFIX, $WT_STORE_MESSAGES, $SERVER_URL;
global $TEXT_DIRECTION;
global $WEBTREES_EMAIL;
//-- do not allow users to send a message to themselves
if ($message["from"]==$message["to"]) {
return false;
}
$user_id_from=get_user_id($message['from']);
$user_id_to =get_user_id($message['to']);
require_once WT_ROOT.'includes/functions/functions_mail.php';
if (!$user_id_to) {
//-- the to user must be a valid user in the system before it will send any mails
return false;
}
// Switch to the "from" user's language
i18n::init(get_user_setting($user_id_from, 'language'));
//-- setup the message body for the "from" user
$email2 = $message["body"];
if (isset($message["from_name"]))
$email2 = i18n::translate('Your Name:')." ".$message["from_name"]."\r\n".i18n::translate('Email Address:')." ".$message["from_email"]."\r\n\r\n".$email2;
if (!empty($message["url"]))
$email2 .= "\r\n\r\n--------------------------------------\r\n\r\n".i18n::translate('This message was sent while viewing the following URL: ')."\r\n".$SERVER_URL.$message["url"]."\r\n";
$email2 .= "\r\n=--------------------------------------=\r\nIP ADDRESS: ".$_SERVER['REMOTE_ADDR']."\r\n";
$email2 .= "DNS LOOKUP: ".gethostbyaddr($_SERVER['REMOTE_ADDR'])."\r\n";
$email2 .= "LANGUAGE: ".WT_LOCALE."\r\n";
$subject2 = "[".i18n::translate('webtrees Message').($TEXT_DIRECTION=="ltr"?"] ":" [").$message["subject"];
$from ="";
if (!$user_id_from) {
$from = $message["from"];
$email2 = i18n::translate('You sent the following message to a webtrees administrator:')."\r\n\r\n".$email2;
$fromFullName = $message["from"];
} else {
$fromFullName = getUserFullName($user_id_from);
if (!get_site_setting('SIMPLE_MAIL'))
$from = hex4email($fromFullName, 'UTF-8'). " <".getUserEmail($user_id_from).">";
else
$from = getUserEmail($user_id_from);
$email2 = i18n::translate('You sent the following message to a webtrees user:')."\r\n\r\n".$email2;
}
if ($message["method"]!="messaging") {
$subject1 = "[".i18n::translate('webtrees Message').($TEXT_DIRECTION=="ltr"?"] ":" [").$message["subject"];
if (!$user_id_from) {
$email1 = i18n::translate('The following message has been sent to your webtrees user account from ');
if (!empty($message["from_name"])) {
$email1 .= $message["from_name"]."\r\n\r\n".$message["body"];
} else {
$email1 .= $from."\r\n\r\n".$message["body"];
}
} else {
$email1 = i18n::translate('The following message has been sent to your webtrees user account from ');
$email1 .= $fromFullName."\r\n\r\n".$message["body"];
}
if (!isset($message["no_from"])) {
if (stristr($from, $WEBTREES_EMAIL)){
$from = getUserEmail(get_gedcom_setting(WT_GED_ID, 'WEBMASTER_USER_ID'));
}
if (!$user_id_from) {
$header2 = $WEBTREES_EMAIL;
} elseif (isset($to)) {
$header2 = $to;
}
if (!empty($header2)) {
webtreesMail($from, $header2, $subject2, $email2);
}
}
}
//-- Load the "to" users language
i18n::init(get_user_setting($user_id_to, 'language'));
if (isset($message["from_name"]))
$message["body"] = i18n::translate('Your Name:')." ".$message["from_name"]."\r\n".i18n::translate('Email Address:')." ".$message["from_email"]."\r\n\r\n".$message["body"];
//-- [ webtrees-Feature Requests-1588353 ] Supress admin IP address in Outgoing PGV Email
if (!userIsAdmin($user_id_from)) {
if (!empty($message["url"]))
$message["body"] .= "\r\n\r\n--------------------------------------\r\n\r\n".i18n::translate('This message was sent while viewing the following URL: ')."\r\n".$SERVER_URL.$message["url"]."\r\n";
$message["body"] .= "\r\n=--------------------------------------=\r\nIP ADDRESS: ".$_SERVER['REMOTE_ADDR']."\r\n";
$message["body"] .= "DNS LOOKUP: ".gethostbyaddr($_SERVER['REMOTE_ADDR'])."\r\n";
$message["body"] .= "LANGUAGE: ".WT_LOCALE."\r\n";
}
if (empty($message["created"]))
$message["created"] = gmdate ("D, d M Y H:i:s T");
if ($WT_STORE_MESSAGES && ($message["method"]!="messaging3" && $message["method"]!="mailto" && $message["method"]!="none")) {
WT_DB::prepare("INSERT INTO {$TBLPREFIX}messages (m_id, m_from, m_to, m_subject, m_body, m_created) VALUES (?, ? ,? ,? ,? ,?)")
->execute(array(get_next_id("messages", "m_id"), $message["from"], $message["to"], $message["subject"], $message["body"], $message["created"]));
}
if ($message["method"]!="messaging") {
$subject1 = "[".i18n::translate('webtrees Message').($TEXT_DIRECTION=="ltr"?"] ":" [").$message["subject"];
if (!$user_id_from) {
$email1 = i18n::translate('The following message has been sent to your webtrees user account from ');
if (!empty($message["from_name"]))
$email1 .= $message["from_name"]."\r\n\r\n".$message["body"];
else
$email1 .= $from."\r\n\r\n".$message["body"];
} else {
$email1 = i18n::translate('The following message has been sent to your webtrees user account from ');
$email1 .= $fromFullName."\r\n\r\n".$message["body"];
}
if (!$user_id_to) {
//-- the to user must be a valid user in the system before it will send any mails
return false;
} else {
$toFullName=getUserFullName($user_id_to);
if (!get_site_setting('SIMPLE_MAIL'))
$to = hex4email($toFullName, 'UTF-8'). " <".getUserEmail($user_id_to).">";
else
$to = getUserEmail($user_id_to);
}
if (getUserEmail($user_id_to))
webtreesMail($to, $from, $subject1, $email1);
}
i18n::init(WT_LOCALE); // restore language settings if needed
return true;
}
//----------------------------------- deleteMessage
//-- deletes a message in the database
function deleteMessage($message_id) {
global $TBLPREFIX;
return (bool)WT_DB::prepare("DELETE FROM {$TBLPREFIX}messages WHERE m_id=?")->execute(array($message_id));
}
//----------------------------------- getUserMessages
//-- Return an array of a users messages
function getUserMessages($username) {
global $TBLPREFIX;
$rows=
WT_DB::prepare("SELECT * FROM {$TBLPREFIX}messages WHERE m_to=? ORDER BY m_id DESC")
->execute(array($username))
->fetchAll();
$messages=array();
foreach ($rows as $row) {
$messages[]=array(
"id"=>$row->m_id,
"to"=>$row->m_to,
"from"=>$row->m_from,
"subject"=>$row->m_subject,
"body"=>$row->m_body,
"created"=>$row->m_created
);
}
return $messages;
}
/**
* stores a new favorite in the database
* @param array $favorite the favorite array of the favorite to add
*/
function addFavorite($favorite) {
global $TBLPREFIX;
// -- make sure a favorite is added
if (empty($favorite["gid"]) && empty($favorite["url"]))
return false;
//-- make sure this is not a duplicate entry
$sql = "SELECT 1 FROM {$TBLPREFIX}favorites WHERE";
if (!empty($favorite["gid"])) {
$sql.=" fv_gid=?";
$vars=array($favorite["gid"]);
} else {
$sql.=" fv_url=?";
$vars=array($favorite["url"]);
}
$sql.=" AND fv_file=? AND fv_username=?";
$vars[]=$favorite["file"];
$vars[]=$favorite["username"];
if (WT_DB::prepare($sql)->execute($vars)->fetchOne()) {
return false;
}
//-- add the favorite to the database
return (bool)
WT_DB::prepare("INSERT INTO {$TBLPREFIX}favorites (fv_id, fv_username, fv_gid, fv_type, fv_file, fv_url, fv_title, fv_note) VALUES (?, ? ,? ,? ,? ,? ,? ,?)")
->execute(array(get_next_id("favorites", "fv_id"), $favorite["username"], $favorite["gid"], $favorite["type"], $favorite["file"], $favorite["url"], $favorite["title"], $favorite["note"]));
}
/**
* deleteFavorite
* deletes a favorite in the database
* @param int $fv_id the id of the favorite to delete
*/
function deleteFavorite($fv_id) {
global $TBLPREFIX;
return (bool)
WT_DB::prepare("DELETE FROM {$TBLPREFIX}favorites WHERE fv_id=?")
->execute(array($fv_id));
}
/**
* Get a user's favorites
* Return an array of a users messages
* @param string $username the username to get the favorites for
*/
function getUserFavorites($username) {
global $TBLPREFIX;
$rows=
WT_DB::prepare("SELECT * FROM {$TBLPREFIX}favorites WHERE fv_username=?")
->execute(array($username))
->fetchAll();
$favorites = array();
foreach ($rows as $row) {
if (get_id_from_gedcom($row->fv_file)) { // If gedcom exists
$favorites[]=array(
"id"=>$row->fv_id,
"username"=>$row->fv_username,
"gid"=>$row->fv_gid,
"type"=>$row->fv_type,
"file"=>$row->fv_file,
"title"=>$row->fv_title,
"note"=>$row->fv_note,
"url"=>$row->fv_url
);
}
}
return $favorites;
}
/**
* Set Blocks
*
* Sets the blocks for a gedcom or user portal
* the $setdefault parameter tells the program to also store these blocks as the blocks used by default
* @param String $username the username or gedcom name to update the blocks for
* @param array $ublocks the new blocks to set for the user or gedcom
* @param boolean $setdefault if true tells the program to also set these blocks as the blocks for the defaultuser
*/
function setBlocks($username, $ublocks, $setdefault=false) {
global $TBLPREFIX;
WT_DB::prepare("DELETE FROM {$TBLPREFIX}blocks WHERE b_username=? AND b_name!=?")
->execute(array($username, 'faq'));
if ($setdefault) {
WT_DB::prepare("DELETE FROM {$TBLPREFIX}blocks WHERE b_username=?")
->execute(array('defaultuser'));
}
$statement=WT_DB::prepare("INSERT INTO {$TBLPREFIX}blocks (b_id, b_username, b_location, b_order, b_name, b_config) VALUES (?, ?, ?, ?, ?, ?)");
foreach($ublocks["main"] as $order=>$block) {
$statement->execute(array(get_next_id("blocks", "b_id"), $username, 'main', $order, $block[0], serialize($block[1])));
if ($setdefault) {
$statement->execute(array(get_next_id("blocks", "b_id"), 'defaultuser', 'main', $order, $block[0], serialize($block[1])));
}
}
foreach($ublocks["right"] as $order=>$block) {
$statement->execute(array(get_next_id("blocks", "b_id"), $username, 'right', $order, $block[0], serialize($block[1])));
if ($setdefault) {
$statement->execute(array(get_next_id("blocks", "b_id"), 'defaultuser', 'right', $order, $block[0], serialize($block[1])));
}
}
}
/**
* Adds a news item to the database
*
* This function adds a news item represented by the $news array to the database.
* If the $news array has an ["id"] field then the function assumes that it is
* as update of an older news item.
*
* @author John Finlay
* @param array $news a news item array
*/
function addNews($news) {
global $TBLPREFIX;
if (!isset($news["date"]))
$news["date"] = client_time();
if (!empty($news["id"])) {
// In case news items are added from usermigrate, it will also contain an ID.
// So we check first if the ID exists in the database. If not, insert instead of update.
$exists=
WT_DB::prepare("SELECT 1 FROM {$TBLPREFIX}news where n_id=?")
->execute(array($news["id"]))
->fetchOne();
if (!$exists) {
return (bool)
WT_DB::prepare("INSERT INTO {$TBLPREFIX}news (n_id, n_username, n_date, n_title, n_text) VALUES (?, ? ,? ,? ,?)")
->execute(array($news["id"], $news["username"], $news["date"], $news["title"], $news["text"]));
} else {
return (bool)
WT_DB::prepare("UPDATE {$TBLPREFIX}news SET n_date=?, n_title=? , n_text=? WHERE n_id=?")
->execute(array($news["date"], $news["title"], $news["text"], $news["id"]));
}
} else {
return (bool)
WT_DB::prepare("INSERT INTO {$TBLPREFIX}news (n_id, n_username, n_date, n_title, n_text) VALUES (?, ? ,? ,? ,?)")
->execute(array(get_next_id("news", "n_id"), $news["username"], $news["date"], $news["title"], $news["text"]));
}
}
/**
* Deletes a news item from the database
*
* @author John Finlay
* @param int $news_id the id number of the news item to delete
*/
function deleteNews($news_id) {
global $TBLPREFIX;
return (bool)WT_DB::prepare("DELETE FROM {$TBLPREFIX}news WHERE n_id=?")->execute(array($news_id));
}
/**
* Gets the news items for the given user or gedcom
*
* @param String $username the username or gedcom file name to get news items for
*/
function getUserNews($username) {
global $TBLPREFIX;
$rows=
WT_DB::prepare("SELECT * FROM {$TBLPREFIX}news WHERE n_username=? ORDER BY n_date DESC")
->execute(array($username))
->fetchAll();
$news=array();
foreach ($rows as $row) {
$news[$row->n_id]=array(
"id"=>$row->n_id,
"username"=>$row->n_username,
"date"=>$row->n_date,
"title"=>$row->n_title,
"text"=>$row->n_text,
"anchor"=>"article".$row->n_id
);
}
return $news;
}
/**
* Gets the news item for the given news id
*
* @param int $news_id the id of the news entry to get
*/
function getNewsItem($news_id) {
global $TBLPREFIX;
$row=
WT_DB::prepare("SELECT * FROM {$TBLPREFIX}news WHERE n_id=?")
->execute(array($news_id))
->fetchOneRow();
if ($row) {
return array(
"id"=>$row->n_id,
"username"=>$row->n_username,
"date"=>$row->n_date,
"title"=>$row->n_title,
"text"=>$row->n_text,
"anchor"=>"article".$row->n_id
);
} else {
return null;
}
}
?>