diff --git a/Engines/Perso/Events/BaseEvent.php b/Engines/Perso/Events/BaseEvent.php new file mode 100644 index 0000000..2f532d5 --- /dev/null +++ b/Engines/Perso/Events/BaseEvent.php @@ -0,0 +1,25 @@ +selector = $selector; + } + + public function run () : void { + if ($this->isTriggered()) { + $this->handle(); + } + } + + abstract public function isTriggered() : bool; + + abstract public function handle() : void; + +} diff --git a/Engines/Perso/Events/Create.php b/Engines/Perso/Events/Create.php new file mode 100644 index 0000000..04fc610 --- /dev/null +++ b/Engines/Perso/Events/Create.php @@ -0,0 +1,52 @@ +selector->user, + $this->createdPerso, + $this->errors + ); + + if ($isCreated) { + // We've got a winner. + $this->login(); + } else { + // Let's try again. + $this->printAgainCreatePersoForm(); + } + } + + private function login () : void { + $this->selector->smarty + ->assign('NOTIFY', lang_get('NewCharacterCreated')); + + $this->selector->selectAndSetPerso($this->createdPerso); + } + + private function printAgainCreatePersoForm () : void { + $this->selector->smarty + ->assign('WAP', join("
", $this->errors)) + ->assign('perso', $this->createdPerso); + } + +} diff --git a/Engines/Perso/Events/Logout.php b/Engines/Perso/Events/Logout.php new file mode 100644 index 0000000..195ab1c --- /dev/null +++ b/Engines/Perso/Events/Logout.php @@ -0,0 +1,19 @@ +selector->perso !== null; + } + + public function handle () : void { + // User wants to change perso + $this->selector->perso->on_logout(); + $this->selector->hasPerso = false; + } + +} diff --git a/Engines/Perso/Events/ReadFromSession.php b/Engines/Perso/Events/ReadFromSession.php new file mode 100644 index 0000000..91545df --- /dev/null +++ b/Engines/Perso/Events/ReadFromSession.php @@ -0,0 +1,19 @@ +selector->user->session['perso_id']); + } + + public function handle (): void { + // Gets perso ID from the session data + $perso = Perso::get($this->selector->user->session['perso_id']); + + $this->selector->setPerso($perso); + } +} diff --git a/Engines/Perso/Events/Select.php b/Engines/Perso/Events/Select.php new file mode 100644 index 0000000..81fe8fb --- /dev/null +++ b/Engines/Perso/Events/Select.php @@ -0,0 +1,33 @@ +user_id !== $this->selector->user->id) { + message_die(HACK_ERROR, "This isn't your perso."); + } + + $this->selector->selectAndSetPerso($perso); + } + +} diff --git a/Engines/Perso/Events/TryAutoSelect.php b/Engines/Perso/Events/TryAutoSelect.php new file mode 100644 index 0000000..de84ab8 --- /dev/null +++ b/Engines/Perso/Events/TryAutoSelect.php @@ -0,0 +1,49 @@ +selector->hasPerso; + } + + public function handle () : void { + $this->persos = Perso::get_persos($this->selector->user->id); + $count = count($this->persos); + + if ($count === 0) { + $this->askUserToCreatePerso(); + } elseif ($count === 1) { + $this->autoselect(); + } else { + $this->askUserToSelectPerso(); + } + } + + private function askUserToCreatePerso () : void { + $this->selector->smarty + ->display("perso_create.tpl"); + exit; + } + + private function autoselect () : void { + $this->selector->selectAndSetPerso($this->persos[0]); + } + + private function askUserToSelectPerso () : void { + $this->selector->smarty + ->assign("PERSOS", $this->persos) + ->display("perso_select.tpl"); + + $_SESSION['UserWithSeveralPersos'] = true; + exit; + } +} diff --git a/Engines/Perso/PersoSelector.php b/Engines/Perso/PersoSelector.php new file mode 100644 index 0000000..23b76ef --- /dev/null +++ b/Engines/Perso/PersoSelector.php @@ -0,0 +1,109 @@ +smarty = $smarty; + $this->user = $user; + } + + /** + * Run all the workflow to get a perso. + */ + public static function load (User $user, Smarty $smarty) : Perso { + $selector = new self($user, $smarty); + $selector->handleEvents(); + + if (!$selector->hasPerso) { + throw new LogicException(<<<'EOD' + The selector has processed the different events and scenarii + to pick a perso. The expectation after all events have been + handled is we've selected a perso or have printed any view + to create or select one. + + As such, this code should be unreachable. Debug the different + 'isTriggered' and 'handle' methods of the events to ensure the + last event exit or return a perso. + EOD); + } + + $smarty->assign('CurrentPerso', $selector->perso); + + return $selector->perso; + } + + /// + /// Properties + /// + + public function selectAndSetPerso (Perso $perso) : void { + $perso->on_select(); + $this->setPerso($perso); + } + + public function setPerso (Perso $perso) : void { + $this->perso = $perso; + $this->hasPerso = true; + } + + /// + /// Events processing + /// + + private function handleEvents () : void { + $events = $this->getDefaultEvents(); + foreach ($events as $event) { + $event->run(); + } + } + + /** + * @return \Zed\Engines\Perso\Events\BaseEvent[] + */ + private function getDefaultEvents () : array { + return [ + // Strategy 1. Look in session if the perso is already selected. + new ReadFromSession($this), + + // Strategy 2. Process forms and actions from URL. + new Create($this), + new Logout($this), + new Select($this), + + // Strategy 3. Try to autoselect a perso or ask user for one. + new TryAutoSelect($this), + ]; + } + +} diff --git a/includes/objects/perso.php b/includes/objects/perso.php index a1c6f5e..1dd6e03 100644 --- a/includes/objects/perso.php +++ b/includes/objects/perso.php @@ -1,610 +1,610 @@ * @copyright 2010, 2012 Sébastien Santoro aka Dereckson * @license http://www.opensource.org/licenses/bsd-license.php BSD * @version 0.1 * @link http://scherzo.dereckson.be/doc/zed * @link http://zed.dereckson.be/ * @filesource */ require_once("includes/geo/location.php"); /** * Perso class * * This class maps the persos table. * * The class also provides methods * to move or locate a perso, * to gets and sets perso's flags and notes (tables persos_flags and persos_notes), * to gets user's perso or check if a perso is online, * to handle on select and logout events. * */ class Perso { public $id; public $user_id; public $name; public $nickname; public $race; public $sex; public $avatar; public $location_global; public $location_local; public $flags; public $lastError; public static $hashtable_id = []; public static $hashtable_name = []; /** * Initializes a new instance * * @param mixed $data perso ID or nickname */ function __construct ($data = null) { if ($data) { if (is_numeric($data)) { $this->id = $data; } else { $this->nickname = $data; } if (!$this->load_from_database()) { message_die(GENERAL_ERROR, $this->lastError, "Can't authenticate perso"); } } else { $this->generate_id(); } } /** * Initializes a new Perso instance if needed or get already available one. * * @param mixed $data perso ID or nickname * @return Perso the perso instance */ - static function get ($data = null) { + static function get ($data = null) : Perso { if ($data) { //Checks in the hashtables if we already have loaded this instance if (is_numeric($data)) { if (array_key_exists($data, Perso::$hashtable_id)) { return Perso::$hashtable_id[$data]; } } else { if (array_key_exists($data, Perso::$hashtable_name)) { return Perso::$hashtable_name[$data]; } } } - $perso = new Perso($data); - return $perso; + return new Perso($data); } /** * Loads the object Perso (ie fill the properties) from the $_POST array */ function load_from_form () { if (array_key_exists('user_id', $_POST)) { $this->user_id = $_POST['user_id']; } if (array_key_exists('name', $_POST)) { $this->name = $_POST['name']; } if (array_key_exists('nickname', $_POST)) { $this->nickname = $_POST['nickname']; } if (array_key_exists('race', $_POST)) { $this->race = $_POST['race']; } if (array_key_exists('sex', $_POST)) { $this->sex = $_POST['sex']; } if (array_key_exists('avatar', $_POST)) { $this->avatar = $_POST['avatar']; } if (array_key_exists('location_global', $_POST)) { $this->location_global = $_POST['location_global']; } if (array_key_exists('location_local', $_POST)) { $this->location_local = $_POST['location_local']; } } /** * Loads the object Perso (ie fill the properties) from the database */ function load_from_database () { global $db; //Gets perso $sql = "SELECT * FROM " . TABLE_PERSOS; if ($this->id) { $id = $db->sql_escape($this->id); $sql .= " WHERE perso_id = '" . $id . "'"; } else { $nickname = $db->sql_escape($this->nickname); $sql .= " WHERE perso_nickname = '" . $nickname . "'"; } if ( !($result = $db->sql_query($sql)) ) { message_die(SQL_ERROR, "Unable to query persos", '', __LINE__, __FILE__, $sql); } if (!$row = $db->sql_fetchrow($result)) { $this->lastError = "Perso unknown: " . $this->id; return false; } $this->id = $row['perso_id']; $this->user_id = $row['user_id']; $this->name = $row['perso_name']; $this->nickname = $row['perso_nickname']; $this->race = $row['perso_race']; $this->sex = $row['perso_sex']; $this->avatar = $row['perso_avatar']; $this->location_global = $row['location_global']; $this->location_local = $row['location_local']; //Gets flags $sql = "SELECT flag_key, flag_value FROM " . TABLE_PERSOS_FLAGS . " WHERE perso_id = $this->id"; if (!$result = $db->sql_query($sql)) { message_die(SQL_ERROR, "Can't get flags", '', __LINE__, __FILE__, $sql); } while ($row = $db->sql_fetchrow($result)) { $this->flags[$row["flag_key"]] = $row["flag_value"]; } //Gets location $this->location = new GeoLocation( $this->location_global, $this->location_local ); //Puts object in hashtables Perso::$hashtable_id[$this->id] = $this; Perso::$hashtable_name[$this->nickname] = $this; return true; } /** * Saves to database */ function save_to_database () { global $db; $id = $this->id ? "'" . $db->sql_escape($this->id) . "'" : 'NULL'; $user_id = $db->sql_escape($this->user_id); $name = $db->sql_escape($this->name); $nickname = $db->sql_escape($this->nickname); $race = $db->sql_escape($this->race); $sex = $db->sql_escape($this->sex); $avatar = $db->sql_escape($this->avatar); $location_global = $this->location_global ? "'" . $db->sql_escape($this->location_global) . "'" : 'NULL'; $location_local = $this->location_local ? "'" . $db->sql_escape($this->location_local) . "'" : 'NULL'; //Updates or inserts $sql = "REPLACE INTO " . TABLE_PERSOS . " (`perso_id`, `user_id`, `perso_name`, `perso_nickname`, `perso_race`, `perso_sex`, `perso_avatar`, `location_global`, `location_local`) VALUES ($id, '$user_id', '$name', '$nickname', '$race', '$sex', '$avatar', $location_global, $location_local)"; if (!$db->sql_query($sql)) { message_die(SQL_ERROR, "Unable to save", '', __LINE__, __FILE__, $sql); } if (!$id) { //Gets new record id value $this->id = $db->sql_nextid(); } } /** * Updates the specified field in the database record * * @param string $field The field to save */ function save_field ($field) { global $db; if (!$this->id) { message_die(GENERAL_ERROR, "You're trying to update a perso record not yet saved in the database: $field"); } $id = $db->sql_escape($this->id); $value = $db->sql_escape($this->$field); $sql = "UPDATE " . TABLE_PERSOS . " SET `$field` = '$value' WHERE perso_id = '$id'"; if (!$db->sql_query($sql)) { message_die(SQL_ERROR, "Unable to save $field field", '', __LINE__, __FILE__, $sql); } } /** * Gets perso location * * @return string The location names */ public function where () { return $this->location->__toString(); } /** * Moves the perso to a new location * * @param string $global the global target location * @param string $global the local target location */ public function move_to ($global = null, $local = null) { //Sets global location if ($global != null) { $this->location_global = $global; } //Sets local location if ($local != null) { $this->location_local = $local; } //Updates database record if ($global != null && $local != null) { global $db; $perso_id = $db->sql_escape($this->id); $g = $db->sql_escape($this->location_global); $l = $db->sql_escape($this->location_local); $sql = "UPDATE " . TABLE_PERSOS . " SET location_global = '$g', location_local = '$l'" . " WHERE perso_id = '$perso_id'"; if (!$db->sql_query($sql)) { message_die(SQL_ERROR, "Can't save new $global $local location.", '', __LINE__, __FILE__, $sql); } } elseif ($global != null) { $this->save_field('location_global'); } elseif ($local != null) { $this->save_field('location_local'); } //Updates location member $this->location = new GeoLocation( $this->location_global, $this->location_local ); } /** * Gets the specified flag value * * @param string $key flag key * @param mixed $defaultValue default value if the flag doesn't exist * @return mixed the flag value (string) or null if not existing */ public function get_flag ($key, $defaultValue = null) { return $this->flag_exists($key) ? $this->flags[$key] : $defaultValue; } /** * Determines if the specified flag exists * * @param string $key the flag key to check * @return boolean true if the specified flag exists ; otherwise, false. */ public function flag_exists ($key) { return array_key_exists($key, $this->flags); } /** * Sets the specified flag * * @param string $key flag key * @param string $value flag value (optional, default value: 1) */ public function set_flag ($key, $value = 1) { //Checks if flag isn't already set at this value if ($this->flags != null && array_key_exists($key, $this->flags) && $this->flags[$key] === $value) { return; } //Saves flag to database global $db; $id = $db->sql_escape($this->id); $key = $db->sql_escape($key); $value = $db->sql_escape($value); $sql = "REPLACE " . TABLE_PERSOS_FLAGS . " SET perso_id = '$id', flag_key = '$key', flag_value = '$value'"; if (!$db->sql_query($sql)) { message_die(SQL_ERROR, "Can't save flag", '', __LINE__, __FILE__, $sql); } //Sets flag in this perso instance $this->flags[$key] = $value; } /** * Deletes the specified flag * * @param string $key flag key */ public function delete_flag ($key) { global $db; if (!array_key_exists($key, $this->flags)) { return; } $id = $db->sql_escape($this->id); $key = $db->sql_escape($key); $sql = "DELETE FROM " . TABLE_PERSOS_FLAGS . " WHERE flag_key = '$key' AND perso_id = '$id' LIMIT 1"; if (!$db->sql_query($sql)) { message_die(SQL_ERROR, "Can't delete flag", '', __LINE__, __FILE__, $sql); } } /** * Ensures the current perso have the specified flag or exits. * * * @param string $flag the flag to assert * @param int $threshold value the flags must strictly be greater than (optional, the default value is 0) * * Example: * * $perso->set_flag('quux.foo', 1); * //The perso wants to read quux, which we allow with the flag quux.foo * $perso->request_flag('quux.foo'); //will be okay * * //The perso wants also to write quux, which we all allow if quux.foo = 2 * //The threshold will so be 1, as 2 > 1 * $perso->request_flag('quux.foo', 1); //Will exits, with a "You don't have quux.foo permission" message * */ public function request_flag ($flag, $threshold = 0) { if (!array_key_exists($flag, $this->flags) || $this->flags[$flag] <= $threshold) { message_die(HACK_ERROR, "You don't have $flag permission.", "Permissions"); } } /** * Gets the specified note * * @param string $code the note code * @return string the note content */ public function get_note ($code) { global $db; $id = $db->sql_escape($this->id); $code = $db->sql_escape($code); $sql = "SELECT note_text FROM " . TABLE_PERSOS_NOTES . " WHERE perso_id = '$id' AND note_code LIKE '$code'"; return $db->sql_query_express($sql); } /** * Sets the specified note * * @param string $code the note code * @param string $text the note content */ public function set_note ($code, $text) { global $db; $id = $db->sql_escape($this->id); $code = $db->sql_escape($code); $text = $db->sql_escape($text); $sql = "REPLACE INTO " . TABLE_PERSOS_NOTES . " (perso_id, note_code, note_text) VALUES ('$id', '$code', '$text')"; if (!$db->sql_query($sql)) { message_die(SQL_ERROR, "Can't save note", '', __LINE__, __FILE__, $sql); } } /** * Counts the amount of notes the perso have saved * * @return int the amount of notes assigned to the this perso */ public function count_notes () { global $db; $id = $db->sql_escape($this->id); $sql = "SELECT COUNT(*) FROM " . TABLE_PERSOS_NOTES . " WHERE perso_id = '$id'"; return $db->sql_query_express($sql); } /* * Determines if the specified ID is available * * @param integer $id The perso ID to check * @return boolean true if the specified ID is available ; otherwise, false */ public static function is_available_id ($id) { global $db; $sql = "SELECT COUNT(*) FROM " . TABLE_PERSOS . " WHERE perso_id = $id LOCK IN SHARE MODE"; if (!$result = $db->sql_query($sql)) { message_die(SQL_ERROR, "Can't access users table", '', __LINE__, __FILE__, $sql); } $row = $db->sql_fetchrow($result); return ($row[0] == 0); } /** * Generates a unique ID for the current object */ private function generate_id () { do { $this->id = rand(2001, 5999); } while (!Perso::is_available_id($this->id)); } /** * Checks if the nickname is available * * @param string $nickname the nickname to check */ public static function is_available_nickname ($nickname) { global $db; $nickname = $db->sql_escape($nickname); $sql = "SELECT COUNT(*) FROM " . TABLE_PERSOS . " WHERE perso_nickname LIKE '$nickname' LOCK IN SHARE MODE;"; if (!$result = $db->sql_query($sql)) { message_die(SQL_ERROR, "Utilisateurs non parsable", '', __LINE__, __FILE__, $sql); } $row = $db->sql_fetchrow($result); return ($row[0] == 0); } /** * Counts the perso a user have * * @param int user_id the user ID - * @return the user's perso count + * @return int the user's perso count */ - public static function get_persos_count ($user_id) { + public static function get_persos_count ($user_id) : int { global $db; $sql = "SELECT COUNT(*) FROM " . TABLE_PERSOS . " WHERE user_id = $user_id"; - return $db->sql_query_express($sql); + return (int)$db->sql_query_express($sql); } /** * Gets an array with all the perso of the specified user * * @param int $user_id the user ID */ - public static function get_persos ($user_id) { + public static function get_persos (int $user_id) : array { global $db; $user_id = $db->sql_escape($user_id); $sql = "SELECT perso_id FROM " . TABLE_PERSOS . " WHERE user_id = $user_id"; if (!$result = $db->sql_query($sql)) { message_die(SQL_ERROR, "Can't get persos", '', __LINE__, __FILE__, $sql); } + $persos = []; while ($row = $db->sql_fetchrow($result)) { - $persos[] = Perso::get($row[perso_id]); + $persos[] = Perso::get($row['perso_id']); } return $persos; } /** * Gets the first perso a user have * (typically to be used when get_persos_count returns 1 to autoselect) * * @param int user_id the user ID */ public static function get_first_perso ($user_id) { global $db; $sql = "SELECT perso_id FROM " . TABLE_PERSOS ." WHERE user_id = $user_id LIMIT 1"; if ($perso_id = $db->sql_query_express($sql)) { return new Perso($perso_id); } } /** * Determines whether the perso is online * * @return bool true if the perso is online ; otherwise, false. */ public function is_online () { global $db; $id = $db->sql_escape($this->id); $sql = "SELECT MAX(online) FROM " . TABLE_SESSIONS ." WHERE perso_id = $id"; if (!$result = $db->sql_query($sql)) { message_die(SQL_ERROR, "Unable to query the table", '', __LINE__, __FILE__, $sql); } $row = $db->sql_fetchrow($result); return ($row[0] == 1); } /** * This event method is called when the user selects a new perso */ public function on_select () { //Session set_info('perso_id', $this->id); $this->set_flag("site.lastlogin", $_SERVER['REQUEST_TIME']); define("PersoSelected", true); } /** * This event method is called when the user logs off its account or perso */ public function on_logout () { //Clears perso information in $_SESSION and session table set_info('perso_id', null); clean_session(); } /** * This event method is called when the perso is created */ public function on_create () { //Notifies host $this->notify_inviter(); } /** * Creates a new perso, from a parameter form * - * @param int $user The user to attach the perso to + * @param User $user The user to attach the perso to * @param Perso $perso A reference to the created perso (don't initialize it, give it a null value) * @param array $errors A reference to the arrays containing errors (should be an empty array, or the method will always return false) * @return boolean true if the perso has ben created ; otherwise, false */ - public static function create_perso_from_form ($user, &$perso, &$errors) { + public static function create_perso_from_form (User $user, &$perso, &$errors) { $perso = new Perso(); $perso->load_from_form(); $perso->user_id = $user->id; //Validates forms if (!$perso->name) { $errors[] = lang_get("NoFullnameSpecified"); } if (!$perso->race) { $errors[] = lang_get("NoRaceSpecified"); $perso->race = "being"; } if (!$perso->sex) { $errors[] = lang_get("NoSexSpecified"); } if (!$perso->nickname) { $errors[] = lang_get("NoNicknameSpecified"); } elseif (!Perso::is_available_nickname($perso->nickname)) { $errors[] = lang_get("UnavailableNickname"); } if (count($errors)) { return false; } //Creates perso $perso->save_to_database(); $perso->on_create(); return true; } /** * Notifies the person having invited this perso */ public function notify_inviter() { require_once('includes/objects/message.php'); require_once('includes/objects/invite.php'); $message = new Message(); $message->from = 0; $message->to = invite::who_invited($this->id); $message->text = sprintf( lang_get('InvitePersoCreated'), $this->name, get_server_url() . get_url('who', $this->nickname) ); $message->send(); } } diff --git a/includes/objects/user.php b/includes/objects/user.php index 9628612..4eff382 100644 --- a/includes/objects/user.php +++ b/includes/objects/user.php @@ -1,262 +1,264 @@ * @copyright 2010 Sébastien Santoro aka Dereckson * @license http://www.opensource.org/licenses/bsd-license.php BSD * @version 0.1 * @link http://scherzo.dereckson.be/doc/zed * @link http://zed.dereckson.be/ * @filesource */ /** * User class * * This class maps the users and users_openid tables. * * It also provides helper methods to check if a login is available, * or to retrieve a username from e-mail address. */ class User { public $id; public $name; public $password; public $active = 0; public $actkey; public $email; public $regdate; public static $hashtable_id = []; public static $hashtable_name = []; + public array $session = []; + /** * Initializes a new instance * * @param int $id the primary key */ function __construct ($id = null) { if ($id) { $this->id = $id; $this->load_from_database(); } } /** * Initializes a new User instance if needed or get already available one. * * @param mixed $data user ID or name * @return User the user instance */ static function get ($data = null) { if ($data) { //Checks in the hashtables if we already have loaded this instance if (is_numeric($data)) { if (array_key_exists($data, User::$hashtable_id)) { return User::$hashtable_id[$data]; } } else { if (array_key_exists($data, User::$hashtable_name)) { return User::$hashtable_name[$data]; } } } $user = new User($data); return $user; } /** * Loads the object User (ie fill the properties) from the $_POST array */ function load_from_form () { if (array_key_exists('name', $_POST)) { $this->name = $_POST['name']; } if (array_key_exists('password', $_POST)) { $this->password = $_POST['password']; } if (array_key_exists('active', $_POST)) { $this->active = $_POST['active']; } if (array_key_exists('actkey', $_POST)) { $this->actkey = $_POST['actkey']; } if (array_key_exists('email', $_POST)) { $this->email = $_POST['email']; } if (array_key_exists('regdate', $_POST)) { $this->regdate = $_POST['regdate']; } } /** * Loads the object User (ie fill the properties) from the database */ function load_from_database () { global $db; $sql = "SELECT * FROM " . TABLE_USERS . " WHERE user_id = '" . $this->id . "'"; if ( !($result = $db->sql_query($sql)) ) { message_die(SQL_ERROR, "Unable to query users", '', __LINE__, __FILE__, $sql); } if (!$row = $db->sql_fetchrow($result)) { $this->lastError = "User unknown: " . $this->id; return false; } $this->name = $row['username']; $this->password = $row['user_password']; $this->active = $row['user_active']; $this->actkey = $row['user_actkey']; $this->email = $row['user_email']; $this->regdate = $row['user_regdate']; //Puts object in hashtables Perso::$hashtable_id[$this->id] = $this; Perso::$hashtable_name[$this->name] = $this; return true; } /** * Saves to database */ function save_to_database () { global $db; $id = $this->id ? "'" . $db->sql_escape($this->id) . "'" : 'NULL'; $name = $db->sql_escape($this->name); $password = $db->sql_escape($this->password); $active = $db->sql_escape($this->active); $actkey = $db->sql_escape($this->actkey); $email = $db->sql_escape($this->email); $regdate = $this->regdate ? "'" . $db->sql_escape($this->regdate) . "'" : 'NULL'; //Updates or inserts $sql = "REPLACE INTO " . TABLE_USERS . " (`user_id`, `username`, `user_password`, `user_active`, `user_actkey`, `user_email`, `user_regdate`) VALUES ($id, '$name', '$password', '$active', '$actkey', '$email', $regdate)"; if (!$db->sql_query($sql)) { message_die(SQL_ERROR, "Unable to save", '', __LINE__, __FILE__, $sql); } if (!$id) { //Gets new record id value $this->id = $db->sql_nextid(); } } /** * Updates the specified field in the database record */ function save_field ($field) { global $db; if (!$this->id) { message_die(GENERAL_ERROR, "You're trying to update a record not yet saved in the database"); } $id = $db->sql_escape($this->id); $value = $db->sql_escape($this->$field); $sql = "UPDATE " . TABLE_USERS . " SET `$field` = '$value' WHERE user_id = '$id'"; if (!$db->sql_query($sql)) { message_die(SQL_ERROR, "Unable to save $field field", '', __LINE__, __FILE__, $sql); } } /** * Generates a unique user id */ function generate_id () { global $db; do { $this->id = rand(2001, 5999); $sql = "SELECT COUNT(*) FROM " . TABLE_USERS . " WHERE user_id = $this->id LOCK IN SHARE MODE;"; if (!$result = $db->sql_query($sql)) { message_die(SQL_ERROR, "Can't access users table", '', __LINE__, __FILE__, $sql); } $row = $db->sql_fetchrow($result); } while ($row[0]); } /** * Fills password field with encrypted version of the specified clear password * * @param string $newpassword The user's new password */ public function set_password ($newpassword) { $this->password = md5($newpassword); } /** * Deletes OpenID for this user */ public function delete_OpenID () { $this->set_OpenID(''); } /** * Sets OpenID for this user * * @param string $url OpenID endpoint URL */ public function set_OpenID ($url) { global $db; if (!$this->id) { $this->save_to_database(); } $url = $db->sql_escape($url); $sql = "DELETE FROM " . TABLE_USERS_AUTH . " WHERE auth_type = 'OpenID' AND user_id = $this->id"; if (!$db->sql_query($sql)) { message_die(SQL_ERROR, "Can't delete old OpenID", '', __LINE__, __FILE__, $sql); } if ($url != '') { $sql = "INSERT INTO " . TABLE_USERS_AUTH . " (auth_type, auth_identity, user_id) VALUES ('OpenID', '$url', $this->id)"; if (!$db->sql_query($sql)) { message_die(SQL_ERROR, "Can't add new OpenID", '', __LINE__, __FILE__, $sql); } } } /** * Checks if a login is available * * @param string $login the login to check * @return bool true if the specified login is available ; otherwise, false. */ public static function is_available_login ($login) : bool { global $db; $sql = "SELECT COUNT(*) FROM " . TABLE_USERS . " WHERE username LIKE '$login' LOCK IN SHARE MODE;"; if (!$result = $db->sql_query($sql)) { message_die(SQL_ERROR, "Utilisateurs non parsable", '', __LINE__, __FILE__, $sql); } $row = $db->sql_fetchrow($result); return !$row[0]; } /** * Gets username from specified e-mail * * @param string $mail the mail to search * @return string|bool the username matching the mail if found ; otherwise, false. */ public static function get_username_from_email ($mail) { global $db; $sql = "SELECT username FROM " . TABLE_USERS . " WHERE user_email LIKE '$mail' LOCK IN SHARE MODE;"; if (!$result = $db->sql_query($sql)) { message_die(SQL_ERROR, "Utilisateurs non parsable", '', __LINE__, __FILE__, $sql); } if ($row = $db->sql_fetchrow($result)) { return $row['username']; } return false; } } diff --git a/index.php b/index.php index 55f0a5d..2f0e8c4 100644 --- a/index.php +++ b/index.php @@ -1,194 +1,132 @@ * @copyright 2010 Sébastien Santoro aka Dereckson * @license http://www.opensource.org/licenses/bsd-license.php BSD * @version 0.1 * @link http://scherzo.dereckson.be/doc/zed * @link http://zed.dereckson.be/ * @filesource - * @todo Consider to split the different tasks (especially - * perso select/create into several files) */ +use Zed\Engines\Perso\PersoSelector; use Zed\Engines\Templates\Smarty\Engine as SmartyEngine; //////////////////////////////////////////////////////////////////////////////// /// /// Initialization /// //Keruald (formerly Pluton) library include('includes/core.php'); //Session $IP = $_SERVER["REMOTE_ADDR"]; require_once('includes/story/story.php'); //this class can be stored in session session_start(); $_SESSION['ID'] = session_id(); session_update(); //updates or creates the session include("includes/login.php"); //login/logout $CurrentUser = get_logged_user(); //Gets current user information -//Gets current perso -require_once('includes/objects/perso.php'); -if ($perso_id = $CurrentUser->session['perso_id']) { - $CurrentPerso = new Perso($perso_id); -} - //Skin and accent to load define('THEME', $CurrentUser->session['Skin']); define('ACCENT', $CurrentUser->session['Skin_accent']); //Loads Smarty $smarty = SmartyEngine::load()->getSmarty(); //Loads language files initialize_lang(); lang_load('core.conf'); //Gets URL $url = get_current_url_fragments(); //If the user isn't logged in (is anonymous), prints login/invite page & dies. if ($CurrentUser->id < 1000) { include('controllers/anonymous.php'); exit; } //////////////////////////////////////////////////////////////////////////////// /// /// Perso (=character) selector /// -//Handles form -if ($_POST['form'] == 'perso.create') { - $perso = null; - $errors = []; - if (Perso::create_perso_from_form($CurrentUser, $perso, $errors)) { - //Notifies and logs in - $smarty->assign('NOTIFY', lang_get('NewCharacterCreated')); - $CurrentPerso = $perso; - set_info('perso_id', $perso->id); - $CurrentPerso->set_flag("site.lastlogin", $_SERVER['REQUEST_TIME']); - } else { - //Prints again perso create form, so the user can fix it - $smarty->assign('WAP', join("
", $errors)); - $smarty->assign('perso', $perso); - } -} - -if ($_GET['action'] == 'perso.logout' && $CurrentPerso != null) { - //User wants to change perso - $CurrentPerso->on_logout(); - $CurrentPerso = null; -} elseif ($_GET['action'] == 'perso.select') { - //User has selected a perso - $CurrentPerso = new Perso($_GET['perso_id']); - if ($CurrentPerso->user_id != $CurrentUser->id) { - //User have made an error in the URL - message_die(HACK_ERROR, "This isn't your perso."); - } - $CurrentPerso->on_select(); -} - -if (!$CurrentPerso) { - switch ($count = Perso::get_persos_count($CurrentUser->id)) { - case 0: - //User have to create a perso - $smarty->display("perso_create.tpl"); - exit; - - case 1: - //Autoselects only perso - $CurrentPerso = Perso::get_first_perso($CurrentUser->id); - $CurrentPerso->on_select(); - break; - - default: - //User have to pick a perso - $persos = Perso::get_persos($CurrentUser->id); - $smarty->assign("PERSOS", $persos); - $smarty->display("perso_select.tpl"); - $_SESSION['UserWithSeveralPersos'] = true; - exit; - } -} - -//Assigns current perso object as Smarty variable -$smarty->assign('CurrentPerso', $CurrentPerso); +$CurrentPerso = PersoSelector::load($CurrentUser, $smarty); //////////////////////////////////////////////////////////////////////////////// /// /// Tasks to execute before calling the URL controller: /// - assert the perso is somewhere /// - executes the smartline /// //If the perso location is unknown, ejects it to an asteroid if (!$CurrentPerso->location_global) { require_once('includes/geo/place.php'); $smarty->assign('NOTIFY', lang_get('NewLocationNotify')); $CurrentPerso->move_to(GeoPlace::get_start_location()); } //SmartLine include("includes/SmartLine/ZedSmartLine.php"); //Redirects user to user request controller if site.requests flag on if (defined('PersoSelected') && array_key_exists('site.requests', $CurrentPerso->flags) && $CurrentPerso->flags['site.requests']) { include('controllers/persorequest.php'); } //////////////////////////////////////////////////////////////////////////////// /// /// Calls the specific controller to serve the requested page /// switch ($controller = $url[0]) { case '': include('controllers/home.php'); break; case 'builder': case 'explore': case 'page': case 'request': case 'settings': case 'ship': include("controllers/$controller.php"); break; case 'who': include('controllers/profile.php'); //Azhàr controller break; case 'push': include('controllers/motd.php'); //Azhàr controller break; case 'quux': //It's like a test/debug console/sandbox, you put what you want into if (file_exists('dev/quux.php')) { include('dev/quux.php'); } else { message_die(GENERAL_ERROR, "Quux lost in Hollywood.", "Nay"); } break; default: //TODO: returns a prettier 404 page header("Status: 404 Not Found"); dieprint_r($url, 'Unknown URL'); }