summaryrefslogtreecommitdiff
path: root/library/WT
diff options
context:
space:
mode:
Diffstat (limited to 'library/WT')
-rw-r--r--library/WT/User.php518
1 files changed, 160 insertions, 358 deletions
diff --git a/library/WT/User.php b/library/WT/User.php
index ca7c188744..6b5239426b 100644
--- a/library/WT/User.php
+++ b/library/WT/User.php
@@ -1,5 +1,5 @@
<?php
-// Provide an interface to the wt_gedcom table
+// Provide an interface to the wt_user table
//
// webtrees: Web based Family History software
// Copyright (C) 2014 webtrees development team
@@ -23,409 +23,211 @@ if (!defined('WT_WEBTREES')) {
exit;
}
-class WT_Tree {
- // Tree attributes
- public $tree_id =null; // The "gedcom ID" number
- public $tree_name =null; // The "gedcom name" text
- public $tree_name_url =null;
- public $tree_name_html =null;
- public $tree_title =null; // The "gedcom title" text
- public $tree_title_html =null;
- public $imported =null;
+class WT_User {
+ // Reasons why a user authentication attempt failed
+ const ERROR_ACCOUNT_NOT_VERIFIED = -1;
+ const ERROR_ACCOUNT_NOT_APPROVED = -2;
+ const ERROR_INCORRECT_PASSWORD = -3;
+ const ERROR_NO_SUCH_USER = -4;
+ const ERROR_NO_SESSION_COOKIES = -5;
+ // Reasons why a user account cannot be created
+ const ERROR_DUPLICATE_USER_NAME = -6;
+ const ERROR_DUPLICATE_EMAIL = -7;
- // List of all trees
- private static $trees =null;
+ // Attributes of the user, from the wt_user table
+ private $user_id;
+ private $user_name;
+ private $real_name;
+ private $email;
- // Tree settings
- private $preference =null; // wt_gedcom_setting table
- private $user_preference=array(); // wt_user_gedcom_setting table
+ // Settings for the user, from the wt_user_setting table
+ private $settings;
- // Create a tree object. This is a private constructor - it can only
- // be called from WT_Tree::getAll() to ensure proper initialisation.
- private function __construct($tree_id, $tree_name, $tree_title, $imported) {
- if (strpos($tree_title, '%')===false) {
- // Allow users to translate tree titles.
- //$tree_title=WT_I18N::Translate($tree_title);
- }
- $this->tree_id =$tree_id;
- $this->tree_name =$tree_name;
- $this->tree_name_url =rawurlencode($tree_name);
- $this->tree_name_html =WT_Filter::escapeHtml($tree_name);
- $this->tree_title =$tree_title;
- $this->tree_title_html='<span dir="auto">' . WT_Filter::escapeHtml($tree_title) . '</span>';
- $this->imported =$imported;
+ public function __construct($user_id) {
+ $row = WT_DB::prepare(
+ "SELECT SQL_CACHE user_name, real_name, email FROM `##user` WHERE user_id = ?"
+ )->execute(array($user_id))->fetchOneRow();
+
+ $this->user_id = $user_id;
+ $this->user_name = $row->user_name;
+ $this->real_name = $row->real_name;
+ $this->email = $row->email;
}
- // Get and Set the tree’s configuration settings
- public function preference($setting_name, $setting_value=null) {
- // There are lots of settings, and we need to fetch lots of them on every page
- // so it is quicker to fetch them all in one go.
- if ($this->preference===null) {
- $this->preference=WT_DB::prepare(
- "SELECT SQL_CACHE setting_name, setting_value FROM `##gedcom_setting` WHERE gedcom_id=?"
- )->execute(array($this->tree_id))->fetchAssoc();
- }
+ // Create a new user.
+ //
+ // On success, return the user_id of the account.
+ // On failure, return the reason for failure.
+ public function create($user_name, $real_name, $email, $password) {
+ self::passwordCompatibility();
- // If $setting_value is null, then GET the setting
- if ($setting_value===null) {
- // If parameter two is not specified, GET the setting
- if (!array_key_exists($setting_name, $this->preference)) {
- $this->preference[$setting_name]=null;
- }
- return $this->preference[$setting_name];
- } else {
- // If parameter two is specified, then SET the setting
- if ($this->preference($setting_name)!=$setting_value) {
- $this->preference[$setting_name]=$setting_value;
- // Audit log of changes
- AddToLog('Gedcom setting "'.$setting_name.'" set to "'.$setting_value.'"', 'config');
- }
- WT_DB::prepare(
- "REPLACE INTO `##gedcom_setting` (gedcom_id, setting_name, setting_value) VALUES (?, ?, LEFT(?, 255))"
- )->execute(array($this->tree_id, $setting_name, $setting_value));
- return $this;
+ if (WT_DB::prepare("SELECT 1 FROM `##user` WHERE user_name = ?")->execute(array($user_name))->fetchOne()) {
+ return self::ERROR_DUPLICATE_USER_NAME;
}
- }
- // Get and Set the tree’s configuration settings
- public function userPreference($user_id, $setting_name, $setting_value=null) {
- // There are lots of settings, and we need to fetch lots of them on every page
- // so it is quicker to fetch them all in one go.
- if (!array_key_exists($user_id, $this->user_preference)) {
- $this->user_preference[$user_id]=WT_DB::prepare(
- "SELECT SQL_CACHE setting_name, setting_value FROM `##user_gedcom_setting` WHERE user_id=? AND gedcom_id=?"
- )->execute(array($user_id, $this->tree_id))->fetchAssoc();
+ if (WT_DB::prepare("SELECT 1 FROM `##user` WHERE email = ?")->execute(array($email))->fetchOne()) {
+ return self::ERROR_DUPLICATE_EMAIL;
}
- // If $setting_value is null, then GET the setting
- if ($setting_value===null) {
- // If parameter two is not specified, GET the setting
- if (!array_key_exists($setting_name, $this->user_preference[$user_id])) {
- $this->user_preference[$user_id][$setting_name]=null;
- }
- return $this->user_preference[$user_id][$setting_name];
- } else {
- // If parameter two is specified, then SET the setting.
- if ($this->preference($setting_name)!=$setting_value) {
- // Audit log of changes
- AddToLog('Gedcom setting "'.$setting_name.'" set to "'.$setting_value.'"', 'config');
- }
- WT_DB::prepare(
- "REPLACE INTO `##user_gedcom_setting` (user_id, gedcom_id, setting_name, setting_value) VALUES (?, ?, ?, LEFT(?, 255))"
- )->execute(array($user_id, $this->tree_id, $setting_name, $setting_value));
- return $this;
- }
- }
+ WT_DB::prepare(
+ "INSERT INTO `##user` (user_name, real_name, email, password) VALUES (?, ?, ?, ?)"
+ )->execute(array($user_name, $real_name, $email, password_hash($password, PASSWORD_DEFAULT)));
- // Can a user accept changes for this tree?
- public function canAcceptChanges($user_id) {
- return
- userIsAdmin($user_id) ||
- $this->userPreference($user_id, 'canedit')=='admin' ||
- $this->userPreference($user_id, 'canedit')=='accept';
+ return WT_DB::prepare("SELECT LAST_INSERT_ID()")->fetchOne();
}
- // Fetch all the trees that we have permission to access.
- public static function getAll() {
- if (self::$trees===null) {
- self::$trees=array();
- $rows=WT_DB::prepare(
- "SELECT SQL_CACHE g.gedcom_id AS tree_id, g.gedcom_name AS tree_name, gs1.setting_value AS tree_title, gs2.setting_value AS imported".
- " FROM `##gedcom` g".
- " LEFT JOIN `##gedcom_setting` gs1 ON (g.gedcom_id=gs1.gedcom_id AND gs1.setting_name='title')".
- " LEFT JOIN `##gedcom_setting` gs2 ON (g.gedcom_id=gs2.gedcom_id AND gs2.setting_name='imported')".
- " LEFT JOIN `##gedcom_setting` gs3 ON (g.gedcom_id=gs3.gedcom_id AND gs3.setting_name='REQUIRE_AUTHENTICATION')".
- " LEFT JOIN `##user_gedcom_setting` ugs ON (g.gedcom_id=ugs.gedcom_id AND ugs.setting_name='canedit' AND ugs.user_id=?)".
- " WHERE ".
- " g.gedcom_id>0 AND (". // exclude the "template" tree
- " EXISTS (SELECT 1 FROM `##user_setting` WHERE user_id=? AND setting_name='canadmin' AND setting_value=1)". // Admin sees all
- " ) OR (".
- " gs2.setting_value = 1 AND (". // Allow imported trees, with either:
- " gs3.setting_value <> 1 OR". // visitor access
- " IFNULL(ugs.setting_value, 'none')<>'none'". // explicit access
- " )".
- " )".
- " ORDER BY g.sort_order, 3"
- )->execute(array(WT_USER_ID, WT_USER_ID))->fetchAll();
- foreach ($rows as $row) {
- self::$trees[$row->tree_id]=new WT_Tree($row->tree_id, $row->tree_name, $row->tree_title, $row->imported);
- }
- }
- return self::$trees;
+ // Getters and setters for user attributes
+ public function getUserId() {
+ return $this->user_id;
}
- // Get the tree with a specific ID. TODO - is this function needed long-term, or just while
- // we integrate this class into the rest of the code?
- public static function get($tree_id) {
- $trees=self::getAll();
- return $trees[$tree_id];
+ public function getUserName() {
+ return $this->user_name;
}
- // Create arguments to select_edit_control()
- // Note - these will be escaped later
- public static function getIdList() {
- $list=array();
- foreach (self::getAll() as $tree) {
- $list[$tree->tree_id]=$tree->tree_title;
- }
- return $list;
+ public function setUserName($user_name) {
+ $this->user_name = $user_name;
+ WT_DB::prepare(
+ "UPDATE `##user` SET user_name = ? WHERE user_id = ?"
+ )->execute(array($user_name, $this->user_id));
}
- // Create arguments to select_edit_control()
- // Note - these will be escaped later
- public static function getNameList() {
- $list=array();
- foreach (self::getAll() as $tree) {
- $list[$tree->tree_name]=$tree->tree_title;
- }
- return $list;
+ public function getRealName() {
+ return $this->real_name;
}
- public static function getIdFromName($tree_name) {
- foreach (self::getAll() as $tree_id=>$tree) {
- if ($tree->tree_name==$tree_name) {
- return $tree_id;
- }
- }
- return null;
+ public function setRealName($real_name) {
+ $this->real_name = $real_name;
+ WT_DB::prepare(
+ "UPDATE `##user` SET real_name = ? WHERE user_id = ?"
+ )->execute(array($real_name, $this->user_id));
}
- public static function getNameFromId($tree_id) {
- return self::get($tree_id)->tree_name;
+ public function getEmail() {
+ return $this->email;
}
- // Create a new tree
- public static function create($tree_name) {
- try {
- // Create a new tree
- WT_DB::prepare(
- "INSERT INTO `##gedcom` (gedcom_name) VALUES (?)"
- )->execute(array($tree_name));
- $tree_id=WT_DB::prepare("SELECT LAST_INSERT_ID()")->fetchOne();
- } catch (PDOException $ex) {
- // A tree with that name already exists?
- return;
- }
+ public function setEmail($email) {
+ $this->email = $email;
+ WT_DB::prepare(
+ "UPDATE `##user` SET email = ? WHERE user_id = ?"
+ )->execute(array($email, $this->user_id));
+ }
- // Update the list of trees - to include this new one
- self::$trees=null;
+ public function setPassword($password) {
+ self::passwordCompatibility();
- // Module privacy
- WT_Module::setDefaultAccess($tree_id);
+ WT_DB::prepare(
+ "UPDATE `##user` SET password = ? WHERE user_id = ?"
+ )->execute(array(password_hash($password, PASSWORD_DEFAULT), $this->user_id));
+ }
- // Gedcom and privacy settings
- set_gedcom_setting($tree_id, 'ADVANCED_NAME_FACTS', 'NICK,_AKA');
- set_gedcom_setting($tree_id, 'ADVANCED_PLAC_FACTS', '');
- set_gedcom_setting($tree_id, 'ALLOW_THEME_DROPDOWN', true);
- set_gedcom_setting($tree_id, 'CALENDAR_FORMAT', 'gregorian');
- set_gedcom_setting($tree_id, 'CHART_BOX_TAGS', '');
- set_gedcom_setting($tree_id, 'COMMON_NAMES_ADD', '');
- set_gedcom_setting($tree_id, 'COMMON_NAMES_REMOVE', '');
- set_gedcom_setting($tree_id, 'COMMON_NAMES_THRESHOLD', '40');
- set_gedcom_setting($tree_id, 'CONTACT_USER_ID', WT_USER_ID);
- set_gedcom_setting($tree_id, 'DEFAULT_PEDIGREE_GENERATIONS', '4');
- set_gedcom_setting($tree_id, 'EXPAND_RELATIVES_EVENTS', false);
- set_gedcom_setting($tree_id, 'EXPAND_SOURCES', false);
- set_gedcom_setting($tree_id, 'FAM_FACTS_ADD', 'CENS,MARR,RESI,SLGS,MARR_CIVIL,MARR_RELIGIOUS,MARR_PARTNERS,RESN');
- set_gedcom_setting($tree_id, 'FAM_FACTS_QUICK', 'MARR,DIV,_NMR');
- set_gedcom_setting($tree_id, 'FAM_FACTS_UNIQUE', 'NCHI,MARL,DIV,ANUL,DIVF,ENGA,MARB,MARC,MARS');
- set_gedcom_setting($tree_id, 'FAM_ID_PREFIX', 'F');
- set_gedcom_setting($tree_id, 'FORMAT_TEXT', 'markdown');
- set_gedcom_setting($tree_id, 'FULL_SOURCES', false);
- set_gedcom_setting($tree_id, 'GEDCOM_ID_PREFIX', 'I');
- set_gedcom_setting($tree_id, 'GEDCOM_MEDIA_PATH', '');
- set_gedcom_setting($tree_id, 'GENERATE_UIDS', false);
- set_gedcom_setting($tree_id, 'HIDE_GEDCOM_ERRORS', true);
- set_gedcom_setting($tree_id, 'HIDE_LIVE_PEOPLE', true);
- set_gedcom_setting($tree_id, 'INDI_FACTS_ADD', 'AFN,BIRT,DEAT,BURI,CREM,ADOP,BAPM,BARM,BASM,BLES,CHRA,CONF,FCOM,ORDN,NATU,EMIG,IMMI,CENS,PROB,WILL,GRAD,RETI,DSCR,EDUC,IDNO,NATI,NCHI,NMR,OCCU,PROP,RELI,RESI,SSN,TITL,BAPL,CONL,ENDL,SLGC,_MILI,ASSO,RESN');
- set_gedcom_setting($tree_id, 'INDI_FACTS_QUICK', 'BIRT,BURI,BAPM,CENS,DEAT,OCCU,RESI');
- set_gedcom_setting($tree_id, 'INDI_FACTS_UNIQUE', '');
- set_gedcom_setting($tree_id, 'KEEP_ALIVE_YEARS_BIRTH', '');
- set_gedcom_setting($tree_id, 'KEEP_ALIVE_YEARS_DEATH', '');
- set_gedcom_setting($tree_id, 'LANGUAGE', WT_LOCALE); // Default to the current admin’s language
- set_gedcom_setting($tree_id, 'MAX_ALIVE_AGE', 120);
- set_gedcom_setting($tree_id, 'MAX_DESCENDANCY_GENERATIONS', '15');
- set_gedcom_setting($tree_id, 'MAX_PEDIGREE_GENERATIONS', '10');
- set_gedcom_setting($tree_id, 'MEDIA_DIRECTORY', 'media/');
- set_gedcom_setting($tree_id, 'MEDIA_ID_PREFIX', 'M');
- set_gedcom_setting($tree_id, 'MEDIA_UPLOAD', WT_PRIV_USER);
- set_gedcom_setting($tree_id, 'META_DESCRIPTION', '');
- set_gedcom_setting($tree_id, 'META_TITLE', WT_WEBTREES);
- set_gedcom_setting($tree_id, 'NOTE_FACTS_ADD', 'SOUR,RESN');
- set_gedcom_setting($tree_id, 'NOTE_FACTS_QUICK', '');
- set_gedcom_setting($tree_id, 'NOTE_FACTS_UNIQUE', '');
- set_gedcom_setting($tree_id, 'NOTE_ID_PREFIX', 'N');
- set_gedcom_setting($tree_id, 'NO_UPDATE_CHAN', false);
- set_gedcom_setting($tree_id, 'PEDIGREE_FULL_DETAILS', true);
- set_gedcom_setting($tree_id, 'PEDIGREE_LAYOUT', true);
- set_gedcom_setting($tree_id, 'PEDIGREE_ROOT_ID', '');
- set_gedcom_setting($tree_id, 'PEDIGREE_SHOW_GENDER', false);
- set_gedcom_setting($tree_id, 'PREFER_LEVEL2_SOURCES', '1');
- set_gedcom_setting($tree_id, 'QUICK_REQUIRED_FACTS', 'BIRT,DEAT');
- set_gedcom_setting($tree_id, 'QUICK_REQUIRED_FAMFACTS', 'MARR');
- set_gedcom_setting($tree_id, 'REPO_FACTS_ADD', 'PHON,EMAIL,FAX,WWW,NOTE,SHARED_NOTE,RESN');
- set_gedcom_setting($tree_id, 'REPO_FACTS_QUICK', '');
- set_gedcom_setting($tree_id, 'REPO_FACTS_UNIQUE', 'NAME,ADDR');
- set_gedcom_setting($tree_id, 'REPO_ID_PREFIX', 'R');
- set_gedcom_setting($tree_id, 'REQUIRE_AUTHENTICATION', false);
- set_gedcom_setting($tree_id, 'SAVE_WATERMARK_IMAGE', false);
- set_gedcom_setting($tree_id, 'SAVE_WATERMARK_THUMB', false);
- set_gedcom_setting($tree_id, 'SHOW_AGE_DIFF', false);
- set_gedcom_setting($tree_id, 'SHOW_COUNTER', true);
- set_gedcom_setting($tree_id, 'SHOW_DEAD_PEOPLE', WT_PRIV_PUBLIC);
- set_gedcom_setting($tree_id, 'SHOW_EST_LIST_DATES', false);
- set_gedcom_setting($tree_id, 'SHOW_FACT_ICONS', true);
- set_gedcom_setting($tree_id, 'SHOW_GEDCOM_RECORD', false);
- set_gedcom_setting($tree_id, 'SHOW_HIGHLIGHT_IMAGES', true);
- set_gedcom_setting($tree_id, 'SHOW_LDS_AT_GLANCE', false);
- set_gedcom_setting($tree_id, 'SHOW_LEVEL2_NOTES', true);
- set_gedcom_setting($tree_id, 'SHOW_LIVING_NAMES', WT_PRIV_USER);
- set_gedcom_setting($tree_id, 'SHOW_MEDIA_DOWNLOAD', false);
- set_gedcom_setting($tree_id, 'SHOW_NO_WATERMARK', WT_PRIV_USER);
- set_gedcom_setting($tree_id, 'SHOW_PARENTS_AGE', true);
- set_gedcom_setting($tree_id, 'SHOW_PEDIGREE_PLACES', '9');
- set_gedcom_setting($tree_id, 'SHOW_PEDIGREE_PLACES_SUFFIX', false);
- set_gedcom_setting($tree_id, 'SHOW_PRIVATE_RELATIONSHIPS', true);
- set_gedcom_setting($tree_id, 'SHOW_RELATIVES_EVENTS', '_BIRT_CHIL,_BIRT_SIBL,_MARR_CHIL,_MARR_PARE,_DEAT_CHIL,_DEAT_PARE,_DEAT_GPAR,_DEAT_SIBL,_DEAT_SPOU');
- set_gedcom_setting($tree_id, 'SHOW_STATS', false);
- set_gedcom_setting($tree_id, 'SOURCE_ID_PREFIX', 'S');
- set_gedcom_setting($tree_id, 'SOUR_FACTS_ADD', 'NOTE,REPO,SHARED_NOTE,RESN');
- set_gedcom_setting($tree_id, 'SOUR_FACTS_QUICK', 'TEXT,NOTE,REPO');
- set_gedcom_setting($tree_id, 'SOUR_FACTS_UNIQUE', 'AUTH,ABBR,TITL,PUBL,TEXT');
- set_gedcom_setting($tree_id, 'SUBLIST_TRIGGER_I', '200');
- set_gedcom_setting($tree_id, 'SURNAME_LIST_STYLE', 'style2');
- switch (WT_LOCALE) {
- case 'es': set_gedcom_setting($tree_id, 'SURNAME_TRADITION', 'spanish'); break;
- case 'is': set_gedcom_setting($tree_id, 'SURNAME_TRADITION', 'icelandic'); break;
- case 'lt': set_gedcom_setting($tree_id, 'SURNAME_TRADITION', 'lithuanian'); break;
- case 'pl': set_gedcom_setting($tree_id, 'SURNAME_TRADITION', 'polish'); break;
- case 'pt':
- case 'pt-BR': set_gedcom_setting($tree_id, 'SURNAME_TRADITION', 'portuguese'); break;
- default: set_gedcom_setting($tree_id, 'SURNAME_TRADITION', 'paternal'); break;
+ // Fetch a user option/setting from the wt_user_setting table
+ //
+ // Since we'll fetch several settings for each user, and since there aren’t
+ // that many of them, fetch them all in one database query
+ public function getSetting($setting_name, $default=null) {
+ if ($this->settings === null) {
+ $this->settings = WT_DB::prepare(
+ "SELECT SQL_CACHE setting_name, setting_value FROM `##user_setting` WHERE user_id = ?"
+ )->execute(array($this->user_id))->fetchAssoc();
}
- set_gedcom_setting($tree_id, 'THEME_DIR', 'webtrees');
- set_gedcom_setting($tree_id, 'THUMBNAIL_WIDTH', '100');
- set_gedcom_setting($tree_id, 'USE_RIN', false);
- set_gedcom_setting($tree_id, 'USE_SILHOUETTE', true);
- set_gedcom_setting($tree_id, 'WATERMARK_THUMB', false);
- set_gedcom_setting($tree_id, 'WEBMASTER_USER_ID', WT_USER_ID);
- set_gedcom_setting($tree_id, 'WEBTREES_EMAIL', '');
- set_gedcom_setting($tree_id, 'WORD_WRAPPED_NOTES', false);
- set_gedcom_setting($tree_id, 'imported', 0);
- set_gedcom_setting($tree_id, 'title', /* I18N: Default title for new family trees */ WT_I18N::translate('My family tree'));
- // Default restriction settings
- $statement=WT_DB::prepare(
- "INSERT INTO `##default_resn` (gedcom_id, xref, tag_type, resn) VALUES (?, NULL, ?, ?)"
- );
- $statement->execute(array($tree_id, 'SSN', 'confidential'));
- $statement->execute(array($tree_id, 'SOUR', 'privacy'));
- $statement->execute(array($tree_id, 'REPO', 'privacy'));
- $statement->execute(array($tree_id, 'SUBM', 'confidential'));
- $statement->execute(array($tree_id, 'SUBN', 'confidential'));
-
- // Genealogy data
- // It is simpler to create a temporary/unimported GEDCOM than to populate all the tables...
- $john_doe=/* I18N: This should be a common/default/placeholder name of an individual. Put slashes around the surname. */
- WT_I18N::translate('John /DOE/');
- $note=WT_I18N::translate('Edit this individual and replace their details with your own');
- WT_DB::prepare("INSERT INTO `##gedcom_chunk` (gedcom_id, chunk_data) VALUES (?, ?)")->execute(array(
- $tree_id,
- "0 HEAD\n0 @I1@ INDI\n1 NAME {$john_doe}\n1 SEX M\n1 BIRT\n2 DATE 01 JAN 1850\n2 NOTE {$note}\n0 TRLR\n"
- ));
-
- // Set the initial blocks
- WT_DB::prepare(
- "INSERT INTO `##block` (gedcom_id, location, block_order, module_name)".
- " SELECT ?, location, block_order, module_name".
- " FROM `##block`".
- " WHERE gedcom_id=-1"
- )->execute(array($tree_id));
-
- // Update the list of trees - to include the new configuration settings
- self::$trees=null;
+ if (array_key_exists($setting_name, $this->settings)) {
+ return $this->settings[$setting_name];
+ } else {
+ return $default;
+ }
}
- // Delete everything relating to a tree
- public static function delete($tree_id) {
- // If this is the default tree, then unset
- if (WT_Site::preference('DEFAULT_GEDCOM')==self::getNameFromId($tree_id)) {
- WT_Site::preference('DEFAULT_GEDCOM', '');
+ // Update a setting for the user.
+ public function setSetting($setting_name, $setting_value) {
+ if ($setting_value===null) {
+ WT_DB::prepare("DELETE FROM `##user_setting` WHERE user_id=? AND setting_name=?")
+ ->execute(array($this->user_id, $setting_name));
+ unset($this->settings[$setting_name]);
+ } else {
+ WT_DB::prepare("REPLACE INTO `##user_setting` (user_id, setting_name, setting_value) VALUES (?, ?, LEFT(?, 255))")
+ ->execute(array($this->user_id, $setting_name, $setting_value));
+ $this->settings[$setting_name] = $setting_value;
}
- // Don't delete the logs.
- WT_DB::prepare("UPDATE `##log` SET gedcom_id=NULL WHERE gedcom_id =?")->execute(array($tree_id));
-
- WT_DB::prepare("DELETE `##block_setting` FROM `##block_setting` JOIN `##block` USING (block_id) WHERE gedcom_id=?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##block` WHERE gedcom_id =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##dates` WHERE d_file =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##families` WHERE f_file =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##user_gedcom_setting` WHERE gedcom_id =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##gedcom_setting` WHERE gedcom_id =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##individuals` WHERE i_file =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##link` WHERE l_file =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##media` WHERE m_file =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##module_privacy` WHERE gedcom_id =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##name` WHERE n_file =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##next_id` WHERE gedcom_id =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##other` WHERE o_file =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##placelinks` WHERE pl_file =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##places` WHERE p_file =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##sources` WHERE s_file =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##hit_counter` WHERE gedcom_id =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##change` WHERE gedcom_id =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##default_resn` WHERE gedcom_id =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##gedcom_chunk` WHERE gedcom_id =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##log` WHERE gedcom_id =?")->execute(array($tree_id));
- WT_DB::prepare("DELETE FROM `##gedcom` WHERE gedcom_id =?")->execute(array($tree_id));
+ }
- // After updating the database, we need to fetch a new (sorted) copy
- self::$trees=null;
+ // PHP5.5 provides new password hash functions.
+ // For earlier versions, use a compatibility library.
+ private static function passwordCompatibility() {
+ if (!function_exists('password_hash')) {
+ // The compatibility library requires the $2$y salt prefix, which is available in
+ // PHP5.3.7 and *some* earlier/patched versions.
+ $hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
+ if (crypt("password", $hash) === $hash) {
+ require 'library/ircmaxell/password-compat/lib/password.php';
+ } else {
+ // For older/unpatched versions of PHP, use the default crypt behaviour.
+ function password_hash($password, $algo, $options=array()) {
+ $salt = '$2a$12$';
+ $salt_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./';
+ for ($i = 0; $i < 22; ++$i) {
+ $salt .= setsubstr($salt_chars, mt_rand(0, 63), 1);
+ }
+ return crypt($password, $salt);
+ }
+ function password_needs_rehash($password, $algo, $options=array()) {
+ return false;
+ }
+ function password_verify($password, $hash) {
+ return crypt($password, $hash) === $hash;
+ }
+ define('PASSWORD_DEFAULT', 1);
+ }
+ }
}
- //////////////////////////////////////////////////////////////////////////////
+ // Authenticate a username/password combination.
//
- // Export the tree to a GEDCOM file
- //
- //////////////////////////////////////////////////////////////////////////////
+ // On success, return the user_id of the account.
+ // On failure, return the reason for failure.
+ public static function authenticate($user_name, $password) {
+ self::passwordCompatibility();
- public function exportGedcom($gedcom_file) {
+ // If no cookies are available, then we cannot log in.
+ if (empty($_COOKIE)) {
+ return self::NO_SESSION_COOKIES;
+ }
- // TODO: these functions need to be moved to the GedcomRecord(?) class
- require_once WT_ROOT.'includes/functions/functions_export.php';
+ $row = WT_DB::prepare(
+ "SELECT SQL_CACHE user_id, password FROM `wt_user` WHERE user_name = ? OR email = ?"
+ )->execute(array($user_name, $user_name))->fetchOneRow();
- // To avoid partial trees on timeout/diskspace/etc, write to a temporary file first
- $tmp_file = $gedcom_file . '.tmp';
+ if (!$row) {
+ // No such user with that username or email address
+ return self::NO_SUCH_USER;
+ }
- $file_pointer = @fopen($tmp_file, 'w');
- if ($file_pointer === false) {
- return false;
+ $user = new WT_User($row->user_id);
+ if (!password_verify($password, $row->password)) {
+ // Incorrect password
+ return self::INCORRECT_PASSWORD;
}
-
- $buffer = reformat_record_export(gedcom_header($this->tree_name));
- $stmt = WT_DB::prepare(
- "SELECT i_gedcom AS gedcom FROM `##individuals` WHERE i_file = ?" .
- " UNION ALL " .
- "SELECT f_gedcom AS gedcom FROM `##families` WHERE f_file = ?" .
- " UNION ALL " .
- "SELECT s_gedcom AS gedcom FROM `##sources` WHERE s_file = ?" .
- " UNION ALL " .
- "SELECT o_gedcom AS gedcom FROM `##other` WHERE o_file = ? AND o_type NOT IN ('HEAD', 'TRLR')" .
- " UNION ALL " .
- "SELECT m_gedcom AS gedcom FROM `##media` WHERE m_file = ?"
- )->execute(array($this->tree_id, $this->tree_id, $this->tree_id, $this->tree_id, $this->tree_id));
+ // Was the password hash created using an old or insecure algorithm?
+ if (password_needs_rehash($row->password, PASSWORD_DEFAULT)) {
+ // Generate a new hash
+ $user->setPassword(password_hash($password, PASSWORD_DEFAULT));
+ }
- while ($row = $stmt->fetch()) {
- $buffer .= reformat_record_export($row->gedcom);
- if (strlen($buffer)>65535) {
- fwrite($file_pointer, $buffer);
- $buffer = '';
- }
+ if (!$user->getSetting('verified') && !$user->getSetting('canadmin')) {
+ // The user has not verified their email address.
+ return self::ACCOUNT_NOT_VERIFIED;
}
- fwrite($file_pointer, $buffer . '0 TRLR' . WT_EOL);
- fclose($file_pointer);
+ if (!$user->getSetting('verified_by_admin') && !$user->getSetting('canadmin')) {
+ // An administrator has not approved the account.
+ // Admins do not need to be approved.
+ return self::ACCOUNT_NOT_APPROVED;
+ }
- return @rename($tmp_file, $gedcom_file);
+ // All checks passed. The user is permitted to log in.
+ return $row->user_id;
}
}