Page Menu
Home
Code
Search
Configure Global Search
Log In
Files
F212348
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
44 KB
Subscribers
None
View Options
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 @@
+<?php
+
+namespace Zed\Engines\Perso\Events;
+
+use Zed\Engines\Perso\PersoSelector;
+
+abstract class BaseEvent {
+
+ protected PersoSelector $selector;
+
+ public function __construct (PersoSelector $selector) {
+ $this->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 @@
+<?php
+
+namespace Zed\Engines\Perso\Events;
+
+use Perso;
+
+/**
+ * This event is triggered when a perso is created,
+ * for example after a new perso form posted.
+ */
+class Create extends BaseEvent {
+
+ private ?Perso $createdPerso = null;
+ private array $errors = [];
+
+ public function isTriggered () : bool {
+ return
+ array_key_exists('form', $_POST)
+ &&
+ $_POST['form'] === 'perso.create';
+ }
+
+ public function handle () : void {
+ $isCreated = Perso::create_perso_from_form(
+ $this->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("<br />", $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 @@
+<?php
+
+namespace Zed\Engines\Perso\Events;
+
+class Logout extends BaseEvent {
+
+ public function isTriggered () : bool {
+ return array_key_exists('action', $_GET)
+ && $_GET['action'] == 'perso.logout'
+ && $this->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 @@
+<?php
+
+namespace Zed\Engines\Perso\Events;
+
+use Perso;
+
+class ReadFromSession extends BaseEvent {
+
+ public function isTriggered (): bool {
+ return isset($this->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 @@
+<?php
+
+namespace Zed\Engines\Perso\Events;
+
+use InvalidArgumentException;
+
+use Perso;
+
+class Select extends BaseEvent {
+
+ public function isTriggered () : bool {
+ return array_key_exists('action', $_GET)
+ && $_GET['action'] == 'perso.select';
+ }
+
+ public function handle () : void {
+ // User has explicitly selected a perso
+
+ if (!array_key_exists('perso_id', $_GET)) {
+ throw new InvalidArgumentException(
+ "The perso ID is missing from the URL ('perso_id')."
+ );
+ }
+
+ $perso = new Perso($_GET['perso_id']);
+ if ($perso->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 @@
+<?php
+
+namespace Zed\Engines\Perso\Events;
+
+use Perso;
+
+class TryAutoSelect extends BaseEvent {
+
+ /**
+ * @var Perso[]
+ */
+ private array $persos;
+
+ public function isTriggered (): bool {
+ return !$this->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 @@
+<?php
+
+namespace Zed\Engines\Perso;
+
+use Smarty;
+
+use Zed\Engines\Perso\Events\Create;
+use Zed\Engines\Perso\Events\Logout;
+use Zed\Engines\Perso\Events\ReadFromSession;
+use Zed\Engines\Perso\Events\Select;
+use Zed\Engines\Perso\Events\TryAutoSelect;
+
+use Perso;
+use User;
+
+use LogicException;
+
+class PersoSelector {
+
+ ///
+ /// Properties
+ ///
+
+ public User $user;
+ public Smarty $smarty;
+ public Perso $perso;
+ public bool $hasPerso = false;
+
+ ///
+ /// Constructors
+ //
+
+ /**
+ * @param User $user The currently logged user
+ */
+ public function __construct (User $user, Smarty $smarty) {
+ $this->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 @@
<?php
/**
* Perso class
*
* Zed. The immensity of stars. The HyperShip. The people.
*
* (c) 2010, Dereckson, some rights reserved.
* Released under BSD license.
*
* 0.1 2010-01-27 00:39 Autogenerated by Pluton Scaffolding
* 0.2 2010-01-29 14:39 Adding flags support
* 0.3 2010-02-06 17:50 Adding static perso hashtable
* 0.4 2012-07-04 11:37 Refactoring: moving code from index.php
*
* @package Zed
* @subpackage Model
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @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:
* <code>
* $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
* </code>
*/
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 @@
<?php
/**
* User class
*
* Zed. The immensity of stars. The HyperShip. The people.
*
* (c) 2010, Dereckson, some rights reserved.
* Released under BSD license.
*
* [DESIGN BY CONTRACT NOTE] No more than one OpenID per user
*
* @package Zed
* @subpackage Model
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @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 @@
<?php
/**
* Application entry point
*
* Zed. The immensity of stars. The HyperShip. The people.
*
* (c) 2010, Dereckson, some rights reserved.
* Released under BSD license.
*
* @package Zed
* @subpackage EntryPoints
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @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("<br />", $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');
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Nov 25, 05:54 (6 h, 59 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
20786
Default Alt Text
(44 KB)
Attached To
rZED Zed
Event Timeline
Log In to Comment