Page MenuHomeCode

No OneTemporary

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

Mime Type
text/x-diff
Expires
Mon, Nov 11, 11:14 (2 w, 1 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
20786
Default Alt Text
(44 KB)

Event Timeline