Page MenuHomeCode

No OneTemporary

This document is not UTF8. It was detected as ISO-8859-1 (Latin 1) and converted to UTF8 for display.
diff --git a/do.php b/do.php
index 6b82483..4f1e6dc 100644
--- a/do.php
+++ b/do.php
@@ -1,293 +1,292 @@
<?php
/**
* AJAX callbacks
*
* Zed. The immensity of stars. The HyperShip. The people.
*
* (c) 2010, Dereckson, some rights reserved.
* Released under BSD license.
*
* As main controller could potentially be interrupted (e.g. if site.requests
* flag is at 1, user is redirected to controllers/userrequest.php), all AJAX
* queries should be handled by this script and not directly by the controllers.
*
* Standard return values:
* -7 user is logged but perso isn't selected,
* -9 user is not logged.
*
* @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
*/
////////////////////////////////////////////////////////////////////////////////
///
/// Constants
///
//We define one negative number constant by standard erroneous return value.
/**
* Magic number which indicates the user is not logged in.
*/
define('USER_NOT_LOGGED', -9);
/**
* Magic number which indicates the user is logged in, but haven't selected its perso.
*/
define('PERSO_NOT_SELECTED', -7);
////////////////////////////////////////////////////////////////////////////////
///
/// Initialization
///
//Pluton library
include('includes/core.php');
//Session
$IP = encode_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 infos
//Gets current perso
require_once('includes/objects/perso.php');
if ($perso_id = $CurrentUser->session['perso_id']) {
$CurrentPerso = new Perso($perso_id);
}
//Requires user and perso
if ($CurrentUser->id < 1000) {
echo USER_NOT_LOGGED;
exit;
}
if (!$CurrentPerso) {
echo PERSO_NOT_SELECTED;
exit;
}
//Loads Smarty (as it handles l10n, it will be used by lang_get)
require('includes/Smarty/Smarty.class.php');
$smarty = new Smarty();
$current_dir = dirname(__FILE__);
$smarty->template_dir = $current_dir . '/skins/zed';
$smarty->compile_dir = $current_dir . '/cache/compiled';
$smarty->cache_dir = $current_dir . '/cache';
$smarty->config_dir = $current_dir;
//Loads language files
initialize_lang();
lang_load('core.conf');
////////////////////////////////////////////////////////////////////////////////
///
/// Actions definitions
///
/**
* Actions class
*
* Each method is called by first part of your URL, other parts are arguments
* e.g. /do.php/validate_quux_request/52 = Actions::validate_quux_request(52);
*
* You can also use $_GET, $_POST or better $_REQUEST.
*
* Don't echo the value but return it, so we can in the future implement custom
* formats like api_output();
*/
-
class Actions {
/**
* Checks the arguments hash and determines wheter it is valid.
*
* @param Array $args the arguments, the last being the hash
* @return boolean true if the hash is valid ; otherwise, false.
*/
static private function is_hash_valid ($args) {
global $Config;
return array_pop($args) == md5($_SESSION['ID'] . $Config['SecretKey'] . implode('', $args));
}
/**
* Handles a allow/deny perso request.
*
* @param string $request_flag the request flag to clear
* @param string $store 'perso' or 'registry'
* @param string $key the perso flag or registry key
* @param string $value the value to store
* @param string $hash the security hash
* @return boolean true if the request is valid and have been processed ; otherwise, false.
*/
static function perso_request ($request_flag, $store, $key, $value, $hash) {
global $CurrentPerso;
//Ensures we've the correct amount of arguments
if (func_num_args() < 4) return false;
//Checks hash
$args = func_get_args();
if (!self::is_hash_valid($args)) {
return false;
}
//Sets flag
switch ($store) {
case 'perso':
$CurrentPerso->set_flag($key, $value);
break;
case 'registry':
registry_set($key, $value);
break;
default:
//Unknown storage location
return false;
}
//Clears request flag
if ((string)$request_flag !== "0") {
$CurrentPerso->delete_flag($request_flag);
}
return true;
}
/**
* Sets current perso's local location.
*
* We don't require a security hash. If the users want to play with it, no problem.
* You generally moves inside a global location as you wish.
* So, if you write a story capturing a perso, use flags to handle this escape!
*
* @param string $location_local the local location
* @return GeoLocation the current perso's GeoLocation object
*/
static function set_local_location ($location_local) {
global $CurrentPerso;
//Ensures we've the correct amount of arguments
if (func_num_args() < 1) return null;
//Moves current perso to specified location
$CurrentPerso->move_to(null, $location_local);
//Returns GeoLocation relevant instance
return $CurrentPerso->location;
}
/**
* Handles upload content form.
*
* @return string new content path
*/
static function upload_content () {
global $CurrentPerso, $CurrentUser;
require_once('includes/objects/content.php');
//Initializes a new content instance
$content = new Content();
//Reads form
$content->load_from_form();
//Sets current user/perso parameters
$content->user_id = $CurrentUser->id;
$content->perso_id = $CurrentPerso->id;
$content->location_global = $CurrentPerso->location_global;
//Saves file
if ($content->handle_uploaded_file($_FILES['artwork'])) {
$content->save_to_database();
$content->generate_thumbnail();
return true;
}
return false;
}
/**
* Gets multimedia content for the specified location
*
* @param string $location_global The global location (local is to specified in ?location_local parameter)
* @return Array an array of Content instances
*/
static function get_content ($location_global) {
//Ensures we've the correct amount of arguments
if (func_num_args() < 1) return null;
//Checks hash
$args = func_get_args();
if (!self::is_hash_valid($args)) {
return false;
}
//Checks local location is specified somewhere (usually in $_GET)
if (!array_key_exists('location_local', $_REQUEST)) {
return false;
}
//Gets content
require_once('includes/objects/content.php');
return Content::get_local_content($location_global, $_REQUEST['location_local']);
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// Handles request
///
//You really should use $_SERVER['PATH_INFO']
//i.e. calling /do.php/your request without any mod rewrite intervention
//
//If you choose otherwise, uncomment and tweak one of the following lines:
//$Config['SiteURL'] = 'http://yourserver/zed/do.php';
//$Config['SiteURL'] = get_server_url() . '/do.php';
$args = get_current_url_fragments();
$method = array_shift($args);
if ($_REQUEST['debug']) {
//Debug version
//Most of E_STRICT errors are evaluated at the compile time thus such errors
//are not reported
ini_set('display_errors', 'stderr');
error_reporting(-1);
if (method_exists('Actions', $method)) {
$result = call_user_func_array(array('Actions', $method), $args);
echo json_encode($result);
} else {
echo "<p>Method doesn't exist: $method</p>";
}
if (array_key_exists('redirectTo', $_REQUEST)) {
//If user JS disabled, you can add ?redirectTo= followed by an URL
echo "<p>Instead to print a callback value, redirects to <a href=\"$_REQUEST[redirectTo]\">$_REQUEST[redirectTo]</a></p>";
}
} else {
//Prod version doesn't prints warning <== silence operator
if (method_exists('Actions', $method)) {
$result = @call_user_func_array(array('Actions', $method), $args);
if (array_key_exists('redirectTo', $_REQUEST)) {
//If user JS disabled, you can add ?redirectTo= followed by an URL
header("location: " . $_REQUEST['redirectTo']);
} else {
echo json_encode($result);
}
}
}
?>
\ No newline at end of file
diff --git a/includes/autoload.php b/includes/autoload.php
index 089ee6f..35a2302 100644
--- a/includes/autoload.php
+++ b/includes/autoload.php
@@ -1,52 +1,77 @@
<?php
+/**
+ * Autoloader
+ *
+ * Zed. The immensity of stars. The HyperShip. The people.
+ *
+ * (c) 2010, Dereckson, some rights reserved.
+ * Released under BSD license.
+ *
+ * This file provides an __autoload function to help loading objects files.
+ *
+ * This function is autogenerated by the TCL script dev/scripts/autoload.tcl
+ *
+ * @package Zed
+ * @subpackage Keruald
+ * @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
+ */
+
/**
* This magic method is called when a class can't be loaded
+ *
+ * @param string $className the class to load
*/
function __autoload ($className) {
//Classes
$classes['Cache'] = 'includes/cache/cache.php';
$classes['CacheMemcached'] = 'includes/cache/memcached.php';
$classes['CacheVoid'] = 'includes/cache/void.php';
$classes['GeoBody'] = 'includes/geo/body.php';
$classes['GeoGalaxy'] = 'includes/geo/galaxy.php';
$classes['GeoLocation'] = 'includes/geo/location.php';
$classes['GeoPlace'] = 'includes/geo/place.php';
$classes['GeoPoint3D'] = 'includes/geo/point3D.php';
$classes['GeoScene'] = 'includes/geo/scene.php';
$classes['Application'] = 'includes/objects/application.php';
$classes['Content'] = 'includes/objects/content.php';
$classes['Invite'] = 'includes/objects/invite.php';
$classes['Message'] = 'includes/objects/message.php';
$classes['MOTD'] = 'includes/objects/motd.php';
$classes['Perso'] = 'includes/objects/perso.php';
$classes['Port'] = 'includes/objects/port.php';
$classes['Profile'] = 'includes/objects/profile.php';
$classes['ProfileComment'] = 'includes/objects/profilecomment.php';
$classes['ProfilePhoto'] = 'includes/objects/profilephoto.php';
$classes['Ship'] = 'includes/objects/ship.php';
$classes['User'] = 'includes/objects/user.php';
$classes['SettingsPage'] = 'includes/settings/page.php';
$classes['Setting'] = 'includes/settings/setting.php';
$classes['Settings'] = 'includes/settings/settings.php';
$classes['StoryChoice'] = 'includes/story/choice.php';
$classes['StoryHook'] = 'includes/story/hook.php';
$classes['DemoStoryHook'] = 'includes/story/hook_demo.php';
$classes['SpatioportStoryHook'] = 'includes/story/hook_spatioport.php';
$classes['StorySection'] = 'includes/story/section.php';
$classes['Story'] = 'includes/story/story.php';
$classes['TravelPlace'] = 'includes/travel/place.php';
$classes['Travel'] = 'includes/travel/travel.php';
//Loader
if (array_key_exists($className, $classes)) {
require_once($classes[$className]);
}
}
?>
\ No newline at end of file
diff --git a/includes/core.php b/includes/core.php
index ea40aad..1602ef6 100644
--- a/includes/core.php
+++ b/includes/core.php
@@ -1,573 +1,666 @@
-<?php
-
-/**
- * Core: helper methods and main libraries loader
- *
- * Zed. The immensity of stars. The HyperShip. The people.
- *
- * (c) 2010, Dereckson, some rights reserved.
- * Released under BSD license.
- *
- * @package Zed
- * @subpackage Pluton
- * @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
- */
-
-////////////////////////////////////////////////////////////////////////////////
-/// ///
-/// Configures PHP and loads site-wide used libraries ///
-/// ///
-////////////////////////////////////////////////////////////////////////////////
-
-//No register globals
-ini_set('register_globals', 'off');
-error_reporting(E_ALL & ~E_NOTICE);
-
-//Load libraries
-include_once("config.php"); //Site config
-include_once("error.php"); //Error management
-include_once("mysql.php"); //MySQL layer
-include_once("sessions.php"); //Sessions handler
-include_once("autoload.php"); //__autoload()
-
-////////////////////////////////////////////////////////////////////////////////
-/// ///
-/// Information helper methods ///
-/// ///
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- * Gets the nickname from the specified perso
- *
- * @param integer $perso_id The specified perso's ID
- * @return string The perso's nickname
- */
-function get_name ($perso_id) {
- global $db;
- $perso_id = $db->sql_escape($perso_id);
- $sql = 'SELECT perso_nickname FROM '. TABLE_PERSOS . " WHERE perso_id = '$perso_id'";
- if (!$result = $db->sql_query($sql)) message_die(SQL_ERROR, "Can't query persos table.", '', __LINE__, __FILE__, $sql);
- $row = $db->sql_fetchrow($result);
- return $row['perso_nickname'];
-}
-
-//Gets user_id from specified username
-function get_userid ($username) {
- global $db;
- $username = $db->sql_escape($username);
- $sql = 'SELECT user_id FROM '. TABLE_USERS . " WHERE username LIKE '$username'";
- if (!$result = $db->sql_query($sql)) message_die(SQL_ERROR, "Can't query users table.", '', __LINE__, __FILE__, $sql);
- $row = $db->sql_fetchrow($result);
- return $row['user_id'];
-}
-
-function registry_get ($key) {
- global $db;
- $key = $db->sql_escape($key);
- $sql = "SELECT registry_value FROM " . TABLE_REGISTRY . " WHERE registry_key = '$key'";
- if (!$result = $db->sql_query($sql)) message_die(SQL_ERROR, "Can't read registry.", '', __LINE__, __FILE__, $sql);
-
- $row = $db->sql_fetchrow($result);
- return $row['registry_value'];
-}
-
-function registry_set ($key, $value) {
- global $db;
- $key = $db->sql_escape($key);
- $value = $db->sql_escape($value);
- $sql = "REPLACE INTO " . TABLE_REGISTRY . " (registry_key, registry_value) VALUES ('$key', '$value')";
- if (!$db->sql_query($sql))
- message_die(SQL_ERROR, "Can't update registry", '', __LINE__, __FILE__, $sql);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// ///
-/// Misc helper methods ///
-/// ///
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- * Generates a random string
- * @author Pierre Habart <p.habart@ifrance.com>
- *
- * @param string $format The format e.g. AAA111
- * @return string a random string
- */
-function generate_random_string ($format) {
- mt_srand((double)microtime()*1000000);
- $str_to_return="";
-
- $t_alphabet=explode(",","A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z");
- $t_number=explode(",","1,2,3,4,5,6,7,8,9,0");
-
- for ($i=0;$i<strlen($format);$i++)
- {
- if (preg_match("/^[a-zA-Z]/",$format[$i]))
- {
- $add=$t_alphabet[mt_rand() % sizeof($t_alphabet)];
- if (preg_match("/^[a-z]/",$format[$i]))
- $add=strtolower($add);
- }
- elseif(preg_match("/^[0-9]/",$format[$i]))
- $add=$t_number[mt_rand() % sizeof($t_number)];
- else $add="?";
-
- $str_to_return.=$add;
- }
- return $str_to_return;
-}
-
-function generer_hexa($longueur) {
- mt_srand((double)microtime()*1000000);
- $str_to_return="";
- $t_number=explode(",","1,2,3,4,5,6,7,8,9,0,A,B,C,D,E,F");
- for ($i = 0 ; $i < $longueur ; $i++) {
- $str_to_return .= $t_number[mt_rand() % sizeof($t_number)];
- }
- return $str_to_return;
-}
-
-//Plural management
-
-function s ($amount) {
- if ($amount > 1) return "s";
-}
-
-function x ($amount) {
- if ($amount > 1) return "x";
-}
-
-//Debug
-
-/**
- * Prints human-readable information about a variable (like the print_r command),
- * enclosed in <pre></pre> tags, to have a preformatted HTML output.
- *
- * @param mixed The expression to be printed
- */
-function dprint_r ($expression) {
- echo '<pre>';
- print_r($expression);
- echo '</pre>';
-}
-
-//GUID
-
-function new_guid() {
- $characters = explode(",","a,b,c,d,e,f,0,1,2,3,4,5,6,7,8,9");
- $guid = "";
- for ($i = 0 ; $i < 36 ; $i++) {
- if ($i == 8 || $i == 13 || $i == 18 || $i == 23) {
- $guid .= "-";
- } else {
- $guid .= $characters[mt_rand() % sizeof($characters)];
- }
- }
- return $guid;
-}
-
-
-function is_guid ($expression) {
- //We avoid regexp to speed up the check
- //A guid is a 36 characters string
- if (strlen($expression) != 36) return false;
-
- $expression = strtolower($expression);
- for ($i = 0 ; $i < 36 ; $i++) {
- if ($i == 8 || $i == 13 || $i == 18 || $i == 23) {
- //with dashes
- if ($expression[$i] != "-") return false;
- } else {
- //and numbers
- if (!is_numeric($expression[$i]) && $expression[$i] != 'a' && $expression[$i] != 'b' && $expression[$i] != 'c' && $expression[$i] != 'd' && $expression[$i] != 'e' && $expression[$i] != 'f' ) return false;
- }
- }
- return true;
-}
-
-/*
- * Gets file extension
- * @param string $file the file to get the extension
- */
-function get_extension ($file) {
- $dotPosition = strrpos($file, ".");
- return substr($file, $dotPosition + 1);
-}
-
-/*
- * Determines if a string starts with specified substring
- * @param string $haystack the string to check
- * @param string $needle the substring to determines if it's the start
- * @param boolean $case_sensitive determines if the search must be case sensitive
- * @return boolean true if $haystack starts with $needle ; otherwise, false.
- */
-function string_starts_with ($haystack, $needle, $case_sensitive = true) {
- if (!$case_sensitive) {
- $haystack = strtoupper($haystack);
- $needle = strtoupper($needle);
- }
- if ($haystack == $needle) return true;
- return strpos($haystack, $needle) === 0;
-}
-
-/*
- * Inserts a message into the supralog
- * @param string $category the entry category
- * @param string $message the message to log
- * @param string $source the entry source.
- */
-function supralog ($category, $message, $source = null) {
- global $db, $CurrentUser, $CurrentPerso;
- $category = $db->sql_query_express($category);
- $message = $db->sql_query_express($message);
- $source = $db->sql_query_express($source ? $source : $_SERVER['SERVER_ADDR']);
- $ip = $_SERVER['REMOTE_ADDR'];
- $sql = "INSERT INTO " . TABLE_LOG .
- " (entry_ip, user_id, perso_id, entry_category, entry_message, entry_source) VALUES
- ('$ip', $CurrentUser->id, $CurrentPerso->id, '$category', '$message', '$source')";
- if ( !($result = $db->sql_query($sql)) )
- message_die(SQL_ERROR, "Can't log this entry.", '', __LINE__, __FILE__, $sql);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// ///
-/// Localization (l10n) ///
-/// ///
-////////////////////////////////////////////////////////////////////////////////
-
-/*
- * Defines LANG constant to lang to print
- */
-function initialize_lang () {
- //If $_SESSION['lang'] doesn't exist yet, find a common language
- if (!array_key_exists('lang', $_SESSION)) {
- $lang = find_lang();
- $_SESSION['lang'] = $lang ? $lang : '-';
- }
-
- if ($_SESSION['lang'] != '-')
- define('LANG', $_SESSION['lang']);
-}
-
-/*
- * Gets a common lang spoken by the site and the user
- * @return string the language
- */
-function find_lang () {
- if (file_exists('lang') && is_dir('lang')) {
- //Gets lang/ subdirectories: this is the list of available languages
- $handle = opendir('lang');
- while ($file = readdir($handle)) {
- if ($file != '.' && $file != '..' && is_dir("lang/$file")) {
- $langs[] = $file;
- }
- }
-
- //The array $langs contains now the language available.
- //Gets the langs the user should want:
- if (!$userlangs = get_http_accept_languages())
- return;
-
- //Gets the intersection between the both languages arrays
- //If it matches, returns first result
- $intersect = array_intersect($userlangs, $langs);
- if (count($intersect)) {
- return $intersect[0];
- }
-
- //Now it's okay with Opera and Firefox but Internet Explorer will
- //by default return en-US and not en or fr-BE and not fr, so second pass
- foreach ($userlangs as $userlang) {
- $lang = explode('-', $userlang);
- if (count($lang) > 1)
- $userlangs2[] = $lang[0];
- }
- $intersect = array_intersect($userlangs2, $langs);
- if (count($intersect)) {
- return $intersect[0];
- }
- }
-}
-
-/*
- * Returns the languages accepted by the browser, by order of priority
- * @return Array a array of languages string
- */
-
-function get_http_accept_languages () {
- //What language to print is sent by browser in HTTP_ACCEPT_LANGUAGE var.
- //This will be something like en,fr;q=0.8,fr-fr;q=0.5,en-us;q=0.3
-
- if (!array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) {
- return null;
- }
-
- $http_accept_language = explode(',', $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
- foreach ($http_accept_language as $language) {
- $userlang = explode(';q=', $language);
- if (count($userlang) == 1) {
- $userlangs[] = array(1, $language);
- } else {
- $userlangs[] = array($userlang[1], $userlang[0]);
- }
- }
- rsort($userlangs);
- foreach ($userlangs as $userlang) {
- $result[] = $userlang[1];
- }
- return $result;
-}
-
-/*
- * Loads specified language Smarty configuration file
- *
- * @param string $file the file to load
- * @param mixed $sections array of section names, single section or null
- */
-function lang_load ($file, $sections = null) {
- global $smarty;
-
- //Loads English file as fallback if some parameters are missing
- if (file_exists("lang/en/$file"))
- $smarty->config_load("lang/en/$file", $sections);
-
- //Loads wanted file (if it exists and a language have been defined)
- if (defined('LANG') && LANG != 'en' && file_exists('lang/' . LANG . '/' . $file))
- $smarty->config_load('lang/' . LANG . '/' . $file, $sections);
-}
-
-/*
- * Gets a specified language expression defined in configuration file
- *
- * @param string $key the configuration key matching the value to get
- * @return string The value in the configuration file
- */
-function lang_get ($key) {
- global $smarty;
-
- $smartyConfValue = $smarty->config_vars[$key];
- return $smartyConfValue ? $smartyConfValue : "#$key#";
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// ///
-/// Zed date and time helper methods ///
-/// ///
-////////////////////////////////////////////////////////////////////////////////
-
-/*
- * Converts a YYYYMMDD or YYYY-MM-DD timestamp to unixtime
- */
-function to_unixtime ($timestamp) {
- switch (strlen($timestamp)) {
- case 8:
- //YYYYMMDD
- return mktime(0, 0, 0, substr($timestamp, 4, 2), substr($timestamp, 6, 2), substr($timestamp, 0, 4));
-
- case 10:
- //YYYY-MM-DD
- return mktime(0, 0, 0, substr($timestamp, 5, 2), substr($timestamp, 8, 2), substr($timestamp, 0, 4));
-
- default:
- throw new Exception("timestamp is not a valid YYYYMMDD or YYYY-MM-DD timestamp: $timestamp");
- }
-}
-
-/*
- * Converts a unixtime to the YYYYMMDD or YYYY-MM-DD timestamp format
- *
- * @param int $unixtime the time to convert
- * @param int $format 8 or 10. If 8 (default), will output YYYYMMDD. If 10, YYYY-MM-DD.
- */
-function to_timestamp ($unixtime = null, $format = 8) {
- //If no parameter is specified (or null, or false), current time is used
- //==== allows to_timestamp(0) to return correct 1970-1-1 value.
- if ($unixtime === null || $unixtime === false) $unixtime = time();
-
- switch ($format) {
- case 8:
- //YYYYMMDD
- return date('Ymd', $unixtime);
-
- case 10:
- //YYYY-MM-DD
- return date('Y-m-d', $unixtime);
-
- default:
- throw new Exception("format must be 8 (YYYYMMDD) or 10 (YYYY-MM-DD) and not $format.");
- }
-}
-
-/*
- * Converts a unixtime to the Hypership time format.
- */
-function get_hypership_time ($unixtime = null) {
- //If unixtime is not specified, it's now
- if ($unixtime === null) $unixtime = time();
-
- //Hypership time is a count of days since launch @ 2010-07-03 00:00:00
- //Followed by a fraction of the current day /1000, like the internet time
- //but in UTC timezone and not Switzerland CET/CEST.
- //We don't need to use floor(), as we output the result at int, truncating
- //automatically decimal values instead of round it (like in C).
- $seconds = $unixtime - 1278115200;
- $days = $seconds / 86400;
- $fraction = (abs($seconds) % 86400) / 86.4;
- return sprintf("%d.%03d", $days, $fraction);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// ///
-/// URL helpers functions ///
-/// ///
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- * Gets URL
- * @return string URL
- */
-function get_url () {
- global $Config;
- if (func_num_args() > 0) {
- $pieces = func_get_args();
- return $Config['BaseURL'] . '/' . implode('/', $pieces);
- } elseif ($Config['BaseURL'] == "" || $Config['BaseURL'] == "/index.php") {
- return "/";
- } else {
- return $Config['BaseURL'];
- }
-}
-
-/*
- * Gets page URL
- * @return string URL
- */
-function get_page_url () {
- $url = $_SERVER['SCRIPT_NAME'] . $_SERVER['PATH_INFO'];
- if (substr($url, -10) == "/index.php") {
- return substr($url, 0, -9);
- }
- return $url;
-}
-
-/*
- * Gets server URL
- * @todo find a way to detect https:// on non standard port
- * @return string the server URL
- */
-function get_server_url () {
- switch ($port = $_SERVER['SERVER_PORT']) {
- case '80':
- return "http://$_SERVER[SERVER_NAME]";
-
- case '443':
- return "https://$_SERVER[SERVER_NAME]";
-
- default:
- return "http://$_SERVER[SERVER_NAME]:$_SERVER[SERVER_PORT]";
- }
-}
-
-/*
- * Gets $_SERVER['PATH_INFO'] or computes the equivalent if not defined.
- * @return string the relevant URL part
- */
-function get_current_url () {
- global $Config;
-
- //Gets relevant URL part from relevant $_SERVER variables
- if (array_key_exists('PATH_INFO', $_SERVER)) {
- //Without mod_rewrite, and url like /index.php/controller
- //we use PATH_INFO. It's the easiest case.
- return $_SERVER["PATH_INFO"];
- }
-
- //In other cases, we'll need to get the relevant part of the URL
- $current_url = get_server_url() . $_SERVER['REQUEST_URI'];
-
- //Relevant URL part starts after the site URL
- $len = strlen($Config['SiteURL']);
-
- //We need to assert it's the correct site
- if (substr($current_url, 0, $len) != $Config['SiteURL']) {
- dieprint_r(GENERAL_ERROR, "Edit includes/config.php and specify the correct site URL<br /><strong>Current value:</strong> $Config[SiteURL]<br /><strong>Expected value:</strong> a string starting by " . get_server_url(), "Setup");
- }
-
- if (array_key_exists('REDIRECT_URL', $_SERVER)) {
- //With mod_rewrite, we can use REDIRECT_URL
- //We takes the end of the URL, ie *FROM* $len position
- return substr(get_server_url() . $_SERVER["REDIRECT_URL"], $len);
- }
-
- //Last possibility: use REQUEST_URI, but remove QUERY_STRING
- //If you need to edit here, use $_SERVER['REQUEST_URI']
- //but you need to discard $_SERVER['QUERY_STRING']
-
- //We takes the end of the URL, ie *FROM* $len position
- $url = substr(get_server_url() . $_SERVER["REQUEST_URI"], $len);
-
- //But if there are a query string (?action=... we need to discard it)
- if ($_SERVER['QUERY_STRING']) {
- return substr($url, 0, strlen($url) - strlen($_SERVER['QUERY_STRING']) - 1);
- }
-
- return $url;
-}
-
-/*
- * Gets an array of url fragments to be processed by controller
- */
-function get_current_url_fragments () {
- $url_source = get_current_url();
- if ($url_source == '/index.php') return array();
- return explode('/', substr($url_source, 1));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// ///
-/// URL xmlHttpRequest helpers functions ///
-/// ///
-////////////////////////////////////////////////////////////////////////////////
-
-/*
- * Gets an hash value to check the integrity of URLs in /do.php calls
- * @param Array $args the args to compute the hash
- * @return the hash paramater for your xmlHttpRequest url
- */
-function get_xhr_hash ($args) {
- global $Config;
-
- array_shift($args);
- return md5($_SESSION['ID'] . $Config['SecretKey'] . implode('', $args));
-}
-
-/*
- * Gets the URL to call do.php, the xmlHttpRequest controller
- * @return string the xmlHttpRequest url, with an integrity hash
- */
-function get_xhr_hashed_url () {
- global $Config;
-
- $args = func_get_args();
- $args[] = get_xhr_hash($args);
- return $Config['DoURL'] . '/' . implode('/', $args);
-}
-
-/*
- * Gets the URL to call do.php, the xmlHttpRequest controller
- * @return string the xmlHttpRequest url
- */
-function get_xhr_url () {
- global $Config;
-
- $args = func_get_args();
- return $Config['DoURL'] . '/' .implode('/', $args);
-}
-
-?>
+<?php
+
+/**
+ * Core: helper methods and main libraries loader
+ *
+ * Zed. The immensity of stars. The HyperShip. The people.
+ *
+ * (c) 2010, Dereckson, some rights reserved.
+ * Released under BSD license.
+ *
+ * @package Zed
+ * @subpackage Keruald
+ * @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
+ */
+
+////////////////////////////////////////////////////////////////////////////////
+/// ///
+/// Configures PHP and loads site-wide used libraries ///
+/// ///
+////////////////////////////////////////////////////////////////////////////////
+
+//No register globals
+ini_set('register_globals', 'off');
+error_reporting(E_ALL & ~E_NOTICE);
+
+//Load libraries
+include_once("config.php"); //Site config
+include_once("error.php"); //Error management
+include_once("mysql.php"); //MySQL layer
+include_once("sessions.php"); //Sessions handler
+include_once("autoload.php"); //__autoload()
+
+////////////////////////////////////////////////////////////////////////////////
+/// ///
+/// Information helper methods ///
+/// ///
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Gets the nickname from the specified perso ID
+ *
+ * @param integer $perso_id The specified perso ID
+ * @return string The perso's nickname
+ */
+function get_name ($perso_id) {
+ global $db;
+ $perso_id = $db->sql_escape($perso_id);
+ $sql = 'SELECT perso_nickname FROM '. TABLE_PERSOS . " WHERE perso_id = '$perso_id'";
+ if (!$result = $db->sql_query($sql)) message_die(SQL_ERROR, "Can't query persos table.", '', __LINE__, __FILE__, $sql);
+ $row = $db->sql_fetchrow($result);
+ return $row['perso_nickname'];
+}
+
+/**
+ * Gets the user ID from the specified username
+ *
+ * @param string $username The username
+ * @return integer the user ID
+ */
+function get_userid ($username) {
+ global $db;
+ $username = $db->sql_escape($username);
+ $sql = 'SELECT user_id FROM '. TABLE_USERS . " WHERE username LIKE '$username'";
+ if (!$result = $db->sql_query($sql)) message_die(SQL_ERROR, "Can't query users table.", '', __LINE__, __FILE__, $sql);
+ $row = $db->sql_fetchrow($result);
+ return $row['user_id'];
+}
+
+/**
+ * Gets an information from the application global registry
+ *
+ * @param string $key the registry's key
+ * @return string The key value
+ */
+function registry_get ($key) {
+ global $db;
+ $key = $db->sql_escape($key);
+ $sql = "SELECT registry_value FROM " . TABLE_REGISTRY . " WHERE registry_key = '$key'";
+ if (!$result = $db->sql_query($sql)) message_die(SQL_ERROR, "Can't read registry.", '', __LINE__, __FILE__, $sql);
+
+ $row = $db->sql_fetchrow($result);
+ return $row['registry_value'];
+}
+
+/**
+ * Sets an information in the application global registry
+ *
+ * @param string $key the registry key
+ * @param string $value the value to store at the specified registry key
+ */
+function registry_set ($key, $value) {
+ global $db;
+ $key = $db->sql_escape($key);
+ $value = $db->sql_escape($value);
+ $sql = "REPLACE INTO " . TABLE_REGISTRY . " (registry_key, registry_value) VALUES ('$key', '$value')";
+ if (!$db->sql_query($sql))
+ message_die(SQL_ERROR, "Can't update registry", '', __LINE__, __FILE__, $sql);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// ///
+/// Misc helper methods ///
+/// ///
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Generates a random string, according the specified format.
+ *
+ * <code>
+ * echo generate_random_string('AAA111'); //this could output SDQ245.
+ * </code>
+ *
+ * @author Pierre Habart <p.habart@ifrance.com>
+ *
+ * @param string $format The format e.g. AAA111
+ * @return string a random string
+ */
+function generate_random_string ($format) {
+ mt_srand((double)microtime()*1000000);
+ $str_to_return="";
+
+ $t_alphabet=explode(",","A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z");
+ $t_number=explode(",","1,2,3,4,5,6,7,8,9,0");
+
+ for ($i=0;$i<strlen($format);$i++)
+ {
+ if (preg_match("/^[a-zA-Z]/",$format[$i]))
+ {
+ $add=$t_alphabet[mt_rand() % sizeof($t_alphabet)];
+ if (preg_match("/^[a-z]/",$format[$i]))
+ $add=strtolower($add);
+ }
+ elseif(preg_match("/^[0-9]/",$format[$i]))
+ $add=$t_number[mt_rand() % sizeof($t_number)];
+ else $add="?";
+
+ $str_to_return.=$add;
+ }
+ return $str_to_return;
+}
+
+//Plural management
+
+/**
+ * Returns "s" when the $amount request a plural
+ * This function is a French plural helper.
+ *
+ * @param $amount the amount of objects
+ * @return string 's' if $amount implies a plural ; '' if it implies a singular.
+ */
+function s ($amount) {
+ if ($amount >= 2 || $amount <= -2) return "s";
+}
+
+/**
+ * Returns "x" when the $amount request a plural
+ * This function is a French plural helper.
+ *
+ * @param $amount the amount of objects
+ * @return string 'x' if $amount implies a plural ; '' if it implies a singular.
+ */
+function x ($amount) {
+ if ($amount >= 2 || $amount <= -2) return "x";
+}
+
+//Debug
+
+/**
+ * Prints human-readable information about a variable.
+ *
+ * It behaves like the print_r command, but the output is enclosed in pre tags,
+ * to have a preformatted HTML output.
+ *
+ * @param mixed The expression to be printed
+ */
+function dprint_r ($expression) {
+ echo '<pre>';
+ print_r($expression);
+ echo '</pre>';
+}
+
+//GUID
+
+/**
+ * Generates a GUID, or more precisely an UUID
+ * @link http://en.wikipedia.org/wiki/Universally_Unique_Identifier Wikipedia, Universally Unique Identifier.
+ *
+ * A UUID is a 36 chars string of 32 hexadecimal and 4 dashes, with a
+ * very high probability to be unique.
+ *
+ * @return string the UUID
+ */
+function new_guid() {
+ $characters = explode(",","a,b,c,d,e,f,0,1,2,3,4,5,6,7,8,9");
+ $guid = "";
+ for ($i = 0 ; $i < 36 ; $i++) {
+ if ($i == 8 || $i == 13 || $i == 18 || $i == 23) {
+ $guid .= "-";
+ } else {
+ $guid .= $characters[mt_rand() % sizeof($characters)];
+ }
+ }
+ return $guid;
+}
+
+/**
+ * Determines if the expression is a valid UUID (a guid without {}).
+ * @see new_guid
+ *
+ * @param string $expression the expression to chjeck
+ * @return boolean true if the specified expression is a valid UUID ; otherwise, false.
+ */
+function is_guid ($expression) {
+ //We avoid regexp to speed up the check
+ //A guid is a 36 characters string
+ if (strlen($expression) != 36) return false;
+
+ $expression = strtolower($expression);
+ for ($i = 0 ; $i < 36 ; $i++) {
+ if ($i == 8 || $i == 13 || $i == 18 || $i == 23) {
+ //with dashes
+ if ($expression[$i] != "-") return false;
+ } else {
+ //and numbers
+ if (!is_numeric($expression[$i]) && $expression[$i] != 'a' && $expression[$i] != 'b' && $expression[$i] != 'c' && $expression[$i] != 'd' && $expression[$i] != 'e' && $expression[$i] != 'f' ) return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * Gets file extension
+ *
+ * @param string $file the file to get the extension
+ * @return string the extension froùm the specified tfile
+ */
+function get_extension ($file) {
+ $dotPosition = strrpos($file, ".");
+ return substr($file, $dotPosition + 1);
+}
+
+/**
+ * Determines if a string starts with specified substring
+ *
+ * @param string $haystack the string to check
+ * @param string $needle the substring to determines if it's the start
+ * @param boolean $case_sensitive determines if the search must be case sensitive
+ * @return boolean true if $haystack starts with $needle ; otherwise, false.
+ */
+function string_starts_with ($haystack, $needle, $case_sensitive = true) {
+ if (!$case_sensitive) {
+ $haystack = strtoupper($haystack);
+ $needle = strtoupper($needle);
+ }
+ if ($haystack == $needle) return true;
+ return strpos($haystack, $needle) === 0;
+}
+
+/**
+ * Inserts a message into the supralog
+ *
+ * @param string $category the entry category
+ * @param string $message the message to log
+ * @param string $source the entry source.
+ */
+function supralog ($category, $message, $source = null) {
+ global $db, $CurrentUser, $CurrentPerso;
+ $category = $db->sql_query_express($category);
+ $message = $db->sql_query_express($message);
+ $source = $db->sql_query_express($source ? $source : $_SERVER['SERVER_ADDR']);
+ $ip = $_SERVER['REMOTE_ADDR'];
+ $sql = "INSERT INTO " . TABLE_LOG .
+ " (entry_ip, user_id, perso_id, entry_category, entry_message, entry_source) VALUES
+ ('$ip', $CurrentUser->id, $CurrentPerso->id, '$category', '$message', '$source')";
+ if ( !($result = $db->sql_query($sql)) )
+ message_die(SQL_ERROR, "Can't log this entry.", '', __LINE__, __FILE__, $sql);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// ///
+/// Localization (l10n) ///
+/// ///
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Defines the LANG constant, to lang to print
+ *
+ * This information is contained in the session, or if not yet defined,
+ * it's to determine according the user's browser preferences.
+ * @see find_lang
+ */
+function initialize_lang () {
+ //If $_SESSION['lang'] doesn't exist yet, find a common language
+ if (!array_key_exists('lang', $_SESSION)) {
+ $lang = find_lang();
+ $_SESSION['lang'] = $lang ? $lang : '-';
+ }
+
+ if ($_SESSION['lang'] != '-')
+ define('LANG', $_SESSION['lang']);
+}
+
+/**
+ * Gets a common lang spoken by the site and the user's browser
+ * @see get_http_accept_languages
+ *
+ * @return string the language
+ */
+function find_lang () {
+ if (file_exists('lang') && is_dir('lang')) {
+ //Gets lang/ subdirectories: this is the list of available languages
+ $handle = opendir('lang');
+ while ($file = readdir($handle)) {
+ if ($file != '.' && $file != '..' && is_dir("lang/$file")) {
+ $langs[] = $file;
+ }
+ }
+
+ //The array $langs contains now the language available.
+ //Gets the langs the user should want:
+ if (!$userlangs = get_http_accept_languages())
+ return;
+
+ //Gets the intersection between the both languages arrays
+ //If it matches, returns first result
+ $intersect = array_intersect($userlangs, $langs);
+ if (count($intersect)) {
+ return $intersect[0];
+ }
+
+ //Now it's okay with Opera and Firefox but Internet Explorer will
+ //by default return en-US and not en or fr-BE and not fr, so second pass
+ foreach ($userlangs as $userlang) {
+ $lang = explode('-', $userlang);
+ if (count($lang) > 1)
+ $userlangs2[] = $lang[0];
+ }
+ $intersect = array_intersect($userlangs2, $langs);
+ if (count($intersect)) {
+ return $intersect[0];
+ }
+ }
+}
+
+/**
+ * Gets the languages accepted by the browser, by order of priority.
+ *
+ * This will read the HTTP_ACCEPT_LANGUAGE variable sent by the browser in the
+ * HTTP request.
+ *
+ * @return Array an array of string, each item a language accepted by browser
+ */
+function get_http_accept_languages () {
+ //What language to print is sent by browser in HTTP_ACCEPT_LANGUAGE var.
+ //This will be something like en,fr;q=0.8,fr-fr;q=0.5,en-us;q=0.3
+
+ if (!array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) {
+ return null;
+ }
+
+ $http_accept_language = explode(',', $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
+ foreach ($http_accept_language as $language) {
+ $userlang = explode(';q=', $language);
+ if (count($userlang) == 1) {
+ $userlangs[] = array(1, $language);
+ } else {
+ $userlangs[] = array($userlang[1], $userlang[0]);
+ }
+ }
+ rsort($userlangs);
+ foreach ($userlangs as $userlang) {
+ $result[] = $userlang[1];
+ }
+ return $result;
+}
+
+/**
+ * Loads specified language Smarty configuration file
+ *
+ * @param string $file the file to load
+ * @param mixed $sections array of section names, single section or null
+ */
+function lang_load ($file, $sections = null) {
+ global $smarty;
+
+ //Loads English file as fallback if some parameters are missing
+ if (file_exists("lang/en/$file"))
+ $smarty->config_load("lang/en/$file", $sections);
+
+ //Loads wanted file (if it exists and a language have been defined)
+ if (defined('LANG') && LANG != 'en' && file_exists('lang/' . LANG . '/' . $file))
+ $smarty->config_load('lang/' . LANG . '/' . $file, $sections);
+}
+
+/**
+ * Gets a specified language expression defined in configuration file
+ *
+ * @param string $key the configuration key matching the value to get
+ * @return string The value in the configuration file
+ */
+function lang_get ($key) {
+ global $smarty;
+
+ $smartyConfValue = $smarty->config_vars[$key];
+ return $smartyConfValue ? $smartyConfValue : "#$key#";
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// ///
+/// Zed date and time helper methods ///
+/// ///
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Converts a YYYYMMDD or YYYY-MM-DD timestamp to unixtime
+ * @link http://en.wikipedia.org/wiki/Unix_time Unix time
+ *
+ * @param string $timestamp the timestamp to convert
+ * @return inteeger the unixtime
+ */
+function to_unixtime ($timestamp) {
+ switch (strlen($timestamp)) {
+ case 8:
+ //YYYYMMDD
+ return mktime(0, 0, 0, substr($timestamp, 4, 2), substr($timestamp, 6, 2), substr($timestamp, 0, 4));
+
+ case 10:
+ //YYYY-MM-DD
+ return mktime(0, 0, 0, substr($timestamp, 5, 2), substr($timestamp, 8, 2), substr($timestamp, 0, 4));
+
+ default:
+ throw new Exception("timestamp is not a valid YYYYMMDD or YYYY-MM-DD timestamp: $timestamp");
+ }
+}
+
+/**
+ * Converts a unixtime to the YYYYMMDD or YYYY-MM-DD timestamp format
+ * @see to_unixtime
+ *
+ * @param int $unixtime the time to convert
+ * @param int $format 8 or 10. If 8 (default), will output YYYYMMDD. If 10, YYYY-MM-DD.
+ * @return string the timestamp
+ */
+function to_timestamp ($unixtime = null, $format = 8) {
+ //If no parameter is specified (or null, or false), current time is used
+ //==== allows to_timestamp(0) to return correct 1970-1-1 value.
+ if ($unixtime === null || $unixtime === false) $unixtime = time();
+
+ switch ($format) {
+ case 8:
+ //YYYYMMDD
+ return date('Ymd', $unixtime);
+
+ case 10:
+ //YYYY-MM-DD
+ return date('Y-m-d', $unixtime);
+
+ default:
+ throw new Exception("format must be 8 (YYYYMMDD) or 10 (YYYY-MM-DD) and not $format.");
+ }
+}
+
+/**
+ * Converts a unixtime to the Hypership time format or gets the current hypership time.
+ * @link http://en.wikipedia.org/wiki/Unix_time
+ * @link http://www.purl.org/NET/Zed/blog/HyperShipTime
+ *
+ * @param int $unixtime The unixtime to convert to HyperShip time. If omitted, the current unixtime.
+ * @return string The HyperShip time
+ */
+function get_hypership_time ($unixtime = null) {
+ //If unixtime is not specified, it's now
+ if ($unixtime === null) $unixtime = time();
+
+ //Hypership time is a count of days since launch @ 2010-07-03 00:00:00
+ //Followed by a fraction of the current day /1000, like the internet time
+ //but in UTC timezone and not Switzerland CET/CEST.
+ //We don't need to use floor(), as we output the result at int, truncating
+ //automatically decimal values instead of round it (like in C).
+ $seconds = $unixtime - 1278115200;
+ $days = $seconds / 86400;
+ $fraction = (abs($seconds) % 86400) / 86.4;
+ return sprintf("%d.%03d", $days, $fraction);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// ///
+/// URL helpers functions ///
+/// ///
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Gets the URL matching the specified resource.
+ *
+ * Example:
+ * <code>
+ * $url = get_url('ship', $ship);
+ * echo $url; //if $ship contains S00001, this should print /ship/S00001
+ * </code>
+ *
+ * @param string $resource,... the resources
+ * @return string the URL matching the specified resource
+ */
+function get_url () {
+ global $Config;
+ if (func_num_args() > 0) {
+ $pieces = func_get_args();
+ return $Config['BaseURL'] . '/' . implode('/', $pieces);
+ } elseif ($Config['BaseURL'] == "" || $Config['BaseURL'] == "/index.php") {
+ return "/";
+ } else {
+ return $Config['BaseURL'];
+ }
+}
+
+/**
+ * Gets the current page URL
+ *
+ * @return string the current page URL
+ */
+function get_page_url () {
+ $url = $_SERVER['SCRIPT_NAME'] . $_SERVER['PATH_INFO'];
+ if (substr($url, -10) == "/index.php") {
+ return substr($url, 0, -9);
+ }
+ return $url;
+}
+
+/**
+ * Gets the server URL
+ * @todo find a way to detect https:// on non standard port
+ *
+ * @return string the server URL
+ */
+function get_server_url () {
+ switch ($port = $_SERVER['SERVER_PORT']) {
+ case '80':
+ return "http://$_SERVER[SERVER_NAME]";
+
+ case '443':
+ return "https://$_SERVER[SERVER_NAME]";
+
+ default:
+ return "http://$_SERVER[SERVER_NAME]:$_SERVER[SERVER_PORT]";
+ }
+}
+
+/**
+ * Gets $_SERVER['PATH_INFO'] or computes the equivalent if not defined.
+ *
+ * This function allows the entry point controllers to get the current URL
+ * in a consistent way, for any redirection configuration
+ *
+ * So with /foo/bar, /index.php/foo/bar, /zed/index.php/foo/bar or /zed/foo/bar
+ * get_current_url will return /foo/bar
+ *
+ * @return string the relevant URL part
+ */
+function get_current_url () {
+ global $Config;
+
+ //Gets relevant URL part from relevant $_SERVER variables
+ if (array_key_exists('PATH_INFO', $_SERVER)) {
+ //Without mod_rewrite, and url like /index.php/controller
+ //we use PATH_INFO. It's the easiest case.
+ return $_SERVER["PATH_INFO"];
+ }
+
+ //In other cases, we'll need to get the relevant part of the URL
+ $current_url = get_server_url() . $_SERVER['REQUEST_URI'];
+
+ //Relevant URL part starts after the site URL
+ $len = strlen($Config['SiteURL']);
+
+ //We need to assert it's the correct site
+ if (substr($current_url, 0, $len) != $Config['SiteURL']) {
+ dieprint_r(GENERAL_ERROR, "Edit includes/config.php and specify the correct site URL<br /><strong>Current value:</strong> $Config[SiteURL]<br /><strong>Expected value:</strong> a string starting by " . get_server_url(), "Setup");
+ }
+
+ if (array_key_exists('REDIRECT_URL', $_SERVER)) {
+ //With mod_rewrite, we can use REDIRECT_URL
+ //We takes the end of the URL, ie *FROM* $len position
+ return substr(get_server_url() . $_SERVER["REDIRECT_URL"], $len);
+ }
+
+ //Last possibility: use REQUEST_URI, but remove QUERY_STRING
+ //If you need to edit here, use $_SERVER['REQUEST_URI']
+ //but you need to discard $_SERVER['QUERY_STRING']
+
+ //We takes the end of the URL, ie *FROM* $len position
+ $url = substr(get_server_url() . $_SERVER["REQUEST_URI"], $len);
+
+ //But if there are a query string (?action=... we need to discard it)
+ if ($_SERVER['QUERY_STRING']) {
+ return substr($url, 0, strlen($url) - strlen($_SERVER['QUERY_STRING']) - 1);
+ }
+
+ return $url;
+}
+
+/**
+ * Gets an array of url fragments to be processed by controller
+ * @see get_current_url
+ *
+ * This method is used by the controllers entry points to know the URL and
+ * call relevant subcontrollers.
+ *
+ * @return Array an array of string, one for each URL fragment
+ */
+function get_current_url_fragments () {
+ $url_source = get_current_url();
+ if ($url_source == '/index.php') return array();
+ return explode('/', substr($url_source, 1));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// ///
+/// URL xmlHttpRequest helpers functions ///
+/// ///
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Gets an hash value to check the integrity of URLs in /do.php calls
+ *
+ * @param Array $args the args to compute the hash
+ * @return the hash paramater for your xmlHttpRequest url
+ */
+function get_xhr_hash ($args) {
+ global $Config;
+
+ array_shift($args);
+ return md5($_SESSION['ID'] . $Config['SecretKey'] . implode('', $args));
+}
+
+/**
+ * Gets the URL to call do.php, the xmlHttpRequest controller
+ *
+ * @return string the xmlHttpRequest url, with an integrity hash
+ */
+function get_xhr_hashed_url () {
+ global $Config;
+
+ $args = func_get_args();
+ $args[] = get_xhr_hash($args);
+ return $Config['DoURL'] . '/' . implode('/', $args);
+}
+
+/**
+ * Gets the URL to call do.php, the xmlHttpRequest controller
+ *
+ * @return string the xmlHttpRequest url
+ */
+function get_xhr_url () {
+ global $Config;
+
+ $args = func_get_args();
+ return $Config['DoURL'] . '/' .implode('/', $args);
+}
+
+?>
diff --git a/includes/login.php b/includes/login.php
index 7cf45e8..ba90153 100644
--- a/includes/login.php
+++ b/includes/login.php
@@ -1,122 +1,136 @@
<?php
-/*
- * Zed
- * (c) 2010, Dereckson, some rights reserved
- * Released under BSD license
- *
+/**
* Login/logout
+ *
+ * Zed. The immensity of stars. The HyperShip. The people.
+ *
+ * (c) 2010, Dereckson, some rights reserved.
+ * Released under BSD license.
+ *
+ * @package Zed
+ * @subpackage Keruald
+ * @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 reenable OpenID
+ * @todo Pick between DumbStore and FileStore and cleans the file accordingly.
*/
if (!file_exists('/dev/urandom')) {
//We're on Windows, without reliable source of random numbers
define('Auth_OpenID_RAND_SOURCE', null);
}
//require_once('Auth/OpenID/Consumer.php');
//require_once('Auth/OpenID/DumbStore.php');
//require_once('Auth/OpenID/FileStore.php');
/*
function get_openid_consumer () {
if (!file_exists('/dev/urandom')) {
//We're on Windows, without reliable source of random numbers
define('Auth_OpenID_RAND_SOURCE', null);
}
$fs = new Auth_OpenID_FileStore('cache/openid');
return new Auth_OpenID_Consumer($fs);
}
*/
function openid_login ($url) {
global $db, $_SESSION, $LoginError, $LoginSuccessful;
$url = $db->sql_escape($url);
$sql = 'SELECT user_id FROM ' . TABLE_USERS_OPENID
. " WHERE openid_url LIKE '$url'";
if ($user_id = $db->sql_query_express($sql)) {
$sql = "UPDATE " . TABLE_SESSIONS . " SET user_id = '$user_id' WHERE session_id LIKE '$_SESSION[ID]'";
if (!$db->sql_query($sql)) message_die(SQL_ERROR, "Impossible de procéder à la connexion", '', __LINE__, __FILE__, $sql);
$LoginSuccessful = true;
setcookie("LastOpenID", $url, time() + 2592000);
header("location: " . get_url());
} else {
$LoginError = "To join Zed, you need an invite. Read the source to get one.";
}
}
if ($_GET['action'] == 'openid.login') {
$LoginError = "OpenID temporarily disabled.";
/*
//Gets Auth_OpenID_Consumer instance
$fs = new Auth_OpenID_DumbStore("rien n'est sûr mais c'est une piste");
//$fs = new Auth_OpenID_FileStore('cache/openid');
$consumer = new Auth_OpenID_Consumer($fs);
//$consumer = get_openid_consumer();
//Completes the OpenID transaction
$reply = $consumer->complete(get_server_url() . $_SERVER['REQUEST_URI']);
if ($reply->status == Auth_OpenID_SUCCESS) {
openid_login($reply->endpoint->claimed_id);
} elseif ($reply->message) {
$LoginError = "[OpenID] $reply->message";
} else {
$LoginError = "[OpenID] $reply->status";
}
*/
} elseif ($_POST['LogIn']) {
//User have filled login form
if ($_POST['openid']) {
$LoginError = "OpenID temporarily disabled.";
/*
//Gets Auth_OpenID_Consumer instance
$fs = new Auth_OpenID_DumbStore("rien n'est sûr mais c'est une piste");
//$fs = new Auth_OpenID_FileStore('cache/openid');
$consumer = new Auth_OpenID_Consumer($fs);
//$consumer = get_openid_consumer();
//Starts the OpenID transaction and redirects user to provider url
if ($request = $consumer->begin($_POST['openid'])) {
$url = $request->redirectURL(get_server_url(), "$Config[SiteURL]/?action=openid.login", false);
header("location: $url");
$LoginError = '<a href="' . $url . '">Click here to continue login</a>';
} else {
$LoginError = 'Invalid OpenID URL.';
}
*/
} else {
//GESTION LOGIN
$Login = $_POST['username'];
$sql = "SELECT user_password, user_id FROM " . TABLE_USERS . " WHERE username = '$Login'";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Impossible d'interroger le listing des utilisateurs", '', __LINE__, __FILE__, $sql);
if ($row = $db->sql_fetchrow($result)) {
if (!$row['user_password']) {
$LoginError = "This account exists but haven't a password defined. Use OpenID or contact dereckson (at) espace-win.org to fix that.";
} elseif ($row['user_password'] != md5($_POST['password'])) {
//PASS NOT OK
$LoginError = "Incorrect password.";
} else {
login($row[user_id], $Login);
$LoginSuccessful = true;
}
} else {
//Idiot proof facility
//Redirects people using login page as invitation claim page
$code = $db->sql_escape($_POST['password']);
$sql = "SELECT * FROM " . TABLE_USERS_INVITES . " WHERE invite_code = '$code'";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Can't get invites", '', __LINE__, __FILE__, $sql);
}
if ($row = $db->sql_fetchrow($result)) {
$url = get_url('invite', $_POST['password']);
header('location: ' . $url);
}
//Login not found
$LoginError = "Login not found.";
}
}
} elseif ($_POST['LogOut'] || $_GET['action'] == "user.logout") {
Logout();
}
?>
diff --git a/includes/mysql.php b/includes/mysql.php
index b6b5928..280db90 100644
--- a/includes/mysql.php
+++ b/includes/mysql.php
@@ -1,98 +1,179 @@
<?php
-/*
- * MySQL layer and helper class
- *
- * @package Zed
- * @subpackage Pluton
- * @copyright Copyright (c) 2010, Dereckson
- * @license Released under BSD license
- * @version 0.1
+/**
+ * MySQL layer and helper class
*
+ * Zed. The immensity of stars. The HyperShip. The people.
+ *
+ * (c) 2010, Dereckson, some rights reserved.
+ * Released under BSD license.
+ *
+ * @package Zed
+ * @subpackage Keruald
+ * @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
*/
if (!defined('SQL_LAYER')) {
define('SQL_LAYER', 'mysql');
+ /**
+ * SQL database class
+ *
+ * This is the MySQL implementation of our SQL abstraction layer
+ */
class sql_db {
+ /*
+ * @var int the connection identifier
+ */
private $id;
-
+
+ /**
+ * Initializes a new instance of the database abstraction class, for MySQL engine
+ *
+ * @param string $host the SQL server to connect [optionnal, by default localhost]
+ * @param string $username the SQL username [optionnal, by default root]
+ * @param string $password the SQL password [optionnal, by default blank]
+ * @param string $database the database to select [optionnal]
+ */
function __construct($host = 'localhost', $username = 'root', $password = '' , $database = '') {
- $this->id = @mysql_connect($host, $username, $password) or $this->sql_die(); //or die ("Can't connect to SQL server.");
- if ($database != '') {
+ //Connects to the MySQL server
+ $this->id = @mysql_connect($host, $username, $password) or $this->sql_die(); //or die ("Can't connect to SQL server.");
+
+ //Selects database
+ if ($database != '') {
mysql_select_db($database, $this->id);
}
}
+
+ /**
+ * Outputs a can't connect to the SQL server message and exits.
+ * It's called on connect failure
+ */
function sql_die () {
+ //You can custom here code when you can't connect to SQL server
+ //e.g. in a demo or appliance context, include('start.html'); exit;
+ //die ("Can't connect to SQL server.");
include('start.html');
exit;
}
+ /**
+ * Sends a unique query to the database
+ *
+ * @param string $query the query to execute
+ * @return resource if the query is successful, a resource identifier ; otherwise, false
+ */
function sql_query ($query) {
return mysql_query($query, $this->id);
}
+ /**
+ * Fetches a row of result into an associative array
+ *
+ * @param resource $result The result that is being evaluated, from sql_query
+ * @return array an associative array with columns names as keys and row values as values
+ */
function sql_fetchrow ($result) {
return mysql_fetch_array($result);
}
+ /**
+ * Gets last SQL error information
+ *
+ * @return array an array with two keys, code and message, containing error information
+ */
function sql_error () {
$error['code'] = mysql_errno($this->id);
$error['message'] = mysql_error($this->id);
return $error;
}
+
+ /**
+ * Gets the number of rows affected or returned by a query
+ *
+ * @return int the number of rows affected (delete/insert/update) or the number of rows in query result
+ */
function sql_numrows ($result) {
return mysql_num_rows($result);
}
+ /**
+ * Gets the primary key value of the last query (works only in INSERT context)
+ *
+ * @return int the primary key value
+ */
function sql_nextid () {
return mysql_insert_id($this->id);
}
- /*
+ /**
* Express query method, returns an immediate and unique result
*
* @param string $query the query to execute
* @param string $error_message the error message
* @param boolean $return_as_string return result as string, and not as an array
- *
* @return mixed the row or the scalar result
*/
function sql_query_express ($query = '', $error_message = "Impossible d'exécuter cette requête.", $return_as_string = true) {
- if (!$query) {
+ if ($query === '' || $query === false || $query === null) {
+ //No query, no value
return '';
} elseif (!$result = $this->sql_query($query)) {
message_die(SQL_ERROR, $error_message, '', __LINE__, __FILE__, $query);
} else {
+ //Fetches row
$row = $this->sql_fetchrow($result);
+
+ //If $return_as_string is true, returns first query item (scalar mode) ; otherwise, returns row
return $return_as_string ? $row[0] : $row;
}
}
- /*
+ /**
* Escapes a SQL expression
*
- * @param string expression The expression to escape
+ * @param string $expression The expression to escape
* @return string The escaped expression
*/
function sql_escape ($expression) {
return mysql_real_escape_string($expression);
}
+ /*
+ * Sets the client character set (requires MySQL 5.0.7+).
+ *
+ * @param string $encoding the charset encoding to set
+ */
function set_charset ($encoding) {
- mysql_set_charset('utf8', $this->id);
+ if (function_exists('mysql_set_charset')) {
+ //>=PHP 5.2.3
+ mysql_set_charset($encoding, $this->id);
+ } else {
+ //Old PHP version
+ $this->sql_query("SET NAMES '$encoding'");
+ }
}
}
+
+ /**
+ * The main sql_db instance
+ *
+ * @global sql_db $_GLOBALS['db']
+ */
+ $db = new sql_db($Config['sql']['host'], $Config['sql']['username'], $Config['sql']['password'], $Config['sql']['database']);
+ $db->set_charset('utf8');
+
+ //By security, we unset the SQL parameters, so you can safely output Zed
+ //config parts (there's still the problem of the secret key, but it's less
+ //a security problem than database password)
+ unset($Config['sql']);
}
-
-
-
-$db = new sql_db($Config['sql']['host'], $Config['sql']['username'], $Config['sql']['password'], $Config['sql']['database']);
-
-unset($Config['sql']);
-
-//Sets SQL connexion in UTF8. PHP 5.2.3+
-$db->set_charset('utf8');
?>
\ No newline at end of file
diff --git a/includes/objects/ship.php b/includes/objects/ship.php
index 92a8aa7..2a0fd97 100644
--- a/includes/objects/ship.php
+++ b/includes/objects/ship.php
@@ -1,281 +1,283 @@
<?php
/*
* Ship class
*
* 0.1 2010-02-05 18:51 Autogenerated by Pluton Scaffolding
* 0.2 2010-02-06 17:30 Ship API
*
* @package Zed
* @copyright Copyright (c) 2010, Dereckson
* @license Released under BSD license
* @version 0.1
*
*/
require_once("perso.php");
require_once("includes/geo/location.php");
class Ship {
/*
* ----------------------------------------------------------------------- *
* Ship class definition
* ----------------------------------------------------------------------- *
*/
public $id;
public $name;
public $location_global;
public $location_local;
public $api_key;
public $description;
private static $hashtable = array();
/*
* Initializes a new instance
* @param int $id the primary key
*/
function __construct ($id = null) {
if ($id) {
if (preg_match("/^S[0-9]{5}$/", $id)) {
$id = substr($id, 1);
}
$this->id = $id;
$this->load_from_database();
}
}
/*
* Initializes a new Ship instance if needed or gets already available one.
* @param mixed $data ship ID
* @eturn Ship the ship instance
*/
static function get ($data = null) {
if ($data !== null) {
//Checks in the hashtable if we already have loaded this instance
if (array_key_exists($data, self::$hashtable)) {
return self::$hashtable[$data];
}
}
$ship = new Ship($data);
return $ship;
}
/*
* Loads the object Ship (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('location_global', $_POST)) $this->location = $_POST['location_global'];
if (array_key_exists('location_local', $_POST)) $this->location = $_POST['location_local'];
if (array_key_exists('api_key', $_POST)) $this->api_key = $_POST['api_key'];
if (array_key_exists('description', $_POST)) $this->description = $_POST['description'];
}
/*
* Loads the object Ship (ie fill the properties) from the database
*/
function load_from_database () {
global $db;
$id = $db->sql_escape($this->id);
$sql = "SELECT * FROM ships WHERE ship_id = '" . $id . "'";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Unable to query Ships", '', __LINE__, __FILE__, $sql);
if (!$row = $db->sql_fetchrow($result)) {
$this->lastError = "Ship unkwown: " . $this->id;
return false;
}
$this->name = $row['ship_name'];
$this->location_global = $row['location_global'];
$this->location_local = $row['location_local'];
$this->api_key = $row['api_key'];
$this->description = $row['ship_description'];
//Puts object in hashtables
self::$hashtable[$this->id] = $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);
$location_global = $db->sql_escape($this->location_global);
$location_local = $db->sql_escape($this->location_local);
$api_key = $db->sql_escape($this->api_key);
$description = $db->sql_escape($this->description);
//Updates or inserts
$sql = "REPLACE INTO ships (`ship_id`, `ship_name`, `location_global`, `location_local`, `api_key`, `ship_description`) VALUES ($id, '$name', '$location_global', '$location_location', '$api_key', '$description')";
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();
}
}
function __toString () {
return $this->get_code();
}
- /*
+ /**
* Get ships at specified location
+ *
* @param string $location_global global location
* @param string $location_local local location
+ * @return array An array of Ship items, each one a ship at the specified location
*/
static function get_ships_at ($location_global, $location_local = null) {
global $db;
//Gets ships
$sql = "SELECT ship_id, location_global, location_local FROM " . TABLE_SHIPS . " WHERE location_global IS NOT NULL";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Can't get ships", '', __LINE__, __FILE__, $sql);
}
$ships = array();
$location = new GeoLocation($location_global, $location_local);
while ($row = $db->sql_fetchrow($result)) {
$shipLocation = new GeoLocation($row['location_global'], $row['location_local']);
if ($location->equals($shipLocation)) {
$ships[] = self::get($row['ship_id']);
}
}
return $ships;
}
/*
* ----------------------------------------------------------------------- *
* Helper methods
* ----------------------------------------------------------------------- *
*/
/*
* Gets ship code, e.g. S00001
* @return string the ship code
*/
function get_code () {
return sprintf("S%05d", $this->id);
}
/*
* Determines if the ship is at a spatioport (or assimilated)
* @return boolean true if the ship is at a spatioport ; false if the ship is in space
*/
function in_spatioport () {
return $this->location_local !== null;
}
/*
*
* @param string $location_local the spatioport location
*/
function fly_in ($location_local = null) {
//TODO: completes location global e.g. B00001 -> B00001003
$this->location_local = ($location_local == null) ? 0 : $location_local;
}
function fly_out () {
$this->location_local = null;
}
/*
* ----------------------------------------------------------------------- *
* Ship API methods
* ----------------------------------------------------------------------- *
*/
/*
* Requests the specified perso to authenticate to this ship
* @param mixed $perso_data the perso id or name
*/
function request_perso_authenticate ($perso_data) {
$perso = Perso::get($perso_data);
$flag = sprintf("request.api.ship.auth.%s", $this->get_code());
$perso->set_flag($flag);
$perso->set_flag("site.requests");
}
/*
* Determines if a perso is authenticated to this ship
* @param mixed $perso_data the perso id or name
* @return boolean true if the specified perso name is authenticated to this ship ; otherwise, false.
*/
function is_perso_authenticated ($perso_data) {
$flag = sprintf("api.ship.auth.%s", $this->get_code());
return Perso::get($perso_data)->flags[$flag] == 1;
}
/*
* Requests the specified perso to confirm the ship API session
* @param string $session_id a session ID provided by calling application
* @param mixed $perso_data the perso id or name
*/
function request_perso_confirm_session ($session_id, $perso_data) {
$perso = Perso::get($perso_data);
$flag = sprintf("request.api.ship.session.%s.%s", $this->get_code(), $session_id);
$perso->set_flag($flag);
$perso->set_flag("site.requests");
}
/*
* Cleans ship API temporary sessions
*/
static function clean_ship_sessions () {
//Cleans old sessions
global $db;
$sql = "DELETE FROM " . TABLE_REGISTRY . " WHERE registry_key LIKE 'api.ship.session.%' AND registry_updated < NOW() - 7200";
if (!$db->sql_query($sql))
message_die(SQL_ERROR, "Can't delete old ship API sessions", '', __LINE__, __FILE__, $sql);
}
/*
* Gets perso id from specified session
* @param string $session_id a session ID provided by calling application
* @return mixed the session
*/
function get_perso_from_session ($session_id) {
//Cleands old session
self::clean_ship_sessions();
//Reads api.ship.session.S00001.$session_id
//This registry key contains perso_id if it exists and valid
$key = sprintf("api.ship.session.%s.%s", $this->get_code(), $session_id);
return registry_get($key);
}
/*
* Loads a Ship object from its API key
* @param string $key API key GUID
* @return Ship the ship matching the API key
*/
static function from_api_key ($key) {
global $db;
$key = $db->sql_escape($key);
$sql = "SELECT * FROM ships WHERE api_key = '" . $key . "'";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Unable to query ships", '', __LINE__, __FILE__, $sql);
if (!$row = $db->sql_fetchrow($result))
return null;
//Fills ship information
$ship = new Ship();
$ship->id = $row['ship_id'];
$ship->name = $row['ship_name'];
$ship->location = $row['ship_location'];
$ship->api_key = $row['api_key'];
$ship->description = $row['ship_description'];
return $ship;
}
}
?>
diff --git a/includes/sessions.php b/includes/sessions.php
index 17d9d2c..933c075 100644
--- a/includes/sessions.php
+++ b/includes/sessions.php
@@ -1,125 +1,149 @@
<?php
+/**
+ * Sessions
+ *
+ * Zed. The immensity of stars. The HyperShip. The people.
+ *
+ * (c) 2010, Dereckson, some rights reserved.
+ * Released under BSD license.
+ *
+ * This file provides functions to manage sessions. It's not currently properly
+ * documented, as it's a temporary old session file, which will be updated soon.
+ *
+ * @package Zed
+ * @subpackage Keruald
+ * @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 Replaces this code by the unified Keruald session class.
+ */
+
function decode_ip ($int_ip) {
$hexipbang = explode('.', chunk_split($int_ip, 2, '.'));
return hexdec($hexipbang[0]). '.' . hexdec($hexipbang[1]) . '.' . hexdec($hexipbang[2]) . '.' . hexdec($hexipbang[3]);
}
function encode_ip ($dotquad_ip) {
$ip_sep = explode('.', $dotquad_ip);
return sprintf('%02x%02x%02x%02x', $ip_sep[0], $ip_sep[1], $ip_sep[2], $ip_sep[3]);
}
function session_update () {
global $db, $IP, $Config;
//Nettoyage de la session
/* Initialisation */
$time_online = 5 * 60; // Temps après lequel l'utilisateur n'est plus considéré comme online
$time_session = 2 * 60 * 60; // Durée de vie de la session
$heureActuelle = time(); //Timestamp UNIX et non MySQL
/* On fait le ménage */
$sql = "UPDATE " . TABLE_SESSIONS . " SET online=0 WHERE HeureLimite < $heureActuelle";
if (!$db->sql_query($sql)) message_die(SQL_ERROR, 'Impossible de mettre à jour les sessions (utilisateurs offline)', '', __LINE__, __FILE__, $sql);
$sql = "DELETE FROM " . TABLE_SESSIONS . " WHERE SessionLimite < $heureActuelle";
if (!$db->sql_query($sql)) message_die(SQL_ERROR, "Impossible d'effacer les sessions expirées", '', __LINE__, __FILE__, $sql);
/* Création / mise à jour de la session utilisateur */
if (!$_SESSION[ID]) {
$_SESSION[ID] = md5(generate_random_string("AAAA1234"));
}
$sql = "SELECT * FROM " . TABLE_SESSIONS . " WHERE session_id LIKE '$_SESSION[ID]'";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Problème critique avec les sessions.", '', __LINE__, __FILE__, $sql);
if ($db->sql_numrows($result) == 0) {
$sql = "INSERT INTO " . TABLE_SESSIONS . " (IP, session_id, `Where`, HeureLimite, SessionLimite) VALUES ('$IP', '$_SESSION[ID]', $Config[ResourceID], $heureActuelle + $time_online, $heureActuelle + $time_session)";
if (!$db->sql_query($sql)) message_die(SQL_ERROR, "Impossible de créer une nouvelle session", '', __LINE__, __FILE__, $sql);
} else {
$sql = "UPDATE " . TABLE_SESSIONS . " SET online=1, HeureLimite = $heureActuelle + $time_online, SessionLimite= $heureActuelle + $time_session WHERE session_id = '$_SESSION[ID]'";
if (!$db->sql_query($sql)) message_die(SQL_ERROR, "Impossible de mettre à jour la session", '', __LINE__, __FILE__, $sql);
}
}
function nbc () {
//Renvoi du nombre d'usagers connectés
global $db, $Config;
$sql = "SELECT count(*) FROM " . TABLE_SESSIONS . " WHERE online=1 AND `Where` = $Config[ResourceID]";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Impossible d'obtenir le nombre d'utilisateurs connectés sur le site web", '', __LINE__, __FILE__, $sql);
$row = $db->sql_fetchrow($result);
return $row[0];
}
function get_info ($info)
//Renvoie une variable de la session
{
global $db;
$sql = "SELECT $info FROM " . TABLE_SESSIONS . " WHERE session_id LIKE '$_SESSION[ID]'";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Impossible d'obtenir $info", '', __LINE__, __FILE__, $sql);
$row = $db->sql_fetchrow($result);
return $row[$info];
}
function get_logged_user ()
//Renvoie toutes les informations d'un utilisateur
{
global $db;
$sql = "SELECT * FROM " . TABLE_SESSIONS . " WHERE session_id LIKE '$_SESSION[ID]'";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Impossible d'obtenir les informations de l'utilisateur", '', __LINE__, __FILE__, $sql);
$row = $db->sql_fetchrow($result);
require_once('includes/objects/user.php');
$user = new User($row['user_id']);
$user->session = $row;
return $user;
}
function set_info ($info, $value)
//Définit une variable session
{
global $db;
$value = ($value === null) ? 'NULL' : "'" . $db->sql_escape($value) . "'";
$sql = "UPDATE " . TABLE_SESSIONS . " SET $info = $value WHERE session_id LIKE '$_SESSION[ID]'";
if (!$db->sql_query($sql)) message_die(SQL_ERROR, "Impossible de définir $info", '', __LINE__, __FILE__, $sql);
}
-/*
+/**
* Destroys $_SESSION array values, help ID
*/
function clean_session () {
foreach ($_SESSION as $key => $value) {
if ($key != 'ID') unset($_SESSION[$key]);
}
}
-/*
+/**
* Logs in user
*/
function login ($user_id, $username) {
global $db;
$sql = "UPDATE " . TABLE_SESSIONS . " SET user_id = '$user_id' WHERE session_id LIKE '$_SESSION[ID]'";
if (!$db->sql_query($sql)) message_die(SQL_ERROR, "Impossible de procéder à la connexion", '', __LINE__, __FILE__, $sql);
//We send a cookie to print automatically the last username on the login
//page during 30 days.
setcookie("LastUsername", $username, time() + 2592000);
}
-/*
+/**
* Logs out user
*/
function logout () {
//Anonymous user in session table
global $db;
$sql = "UPDATE " . TABLE_SESSIONS . " SET user_id = '-1', perso_id = NULL WHERE session_id LIKE '$_SESSION[ID]'";
if (!$db->sql_query($sql)) message_die(SQL_ERROR, "Impossible de procéder à la déconnexion", '', __LINE__, __FILE__, $sql);
clean_session();
}
?>
\ No newline at end of file
diff --git a/includes/story/choice.php b/includes/story/choice.php
index f8352ec..04b4b44 100644
--- a/includes/story/choice.php
+++ b/includes/story/choice.php
@@ -1,50 +1,107 @@
-<?php
-
-/*
- * Zed
- * (c) 2010, Dereckson, some rights reserved
- * Released under BSD license
- *
- * Story choice
- */
-
-class StoryChoice {
- public $goto;
- public $text;
- public $guid;
-
- function __construct () {
- //The guid allows to build temporary URLs to get to right choice
- $this->guid = new_guid();
- }
-
- function __toString () {
- return $this->text;
- }
-
- /*
- * Initializes a new instance of StoryChoice class from a XML element
- * @param SimpleXMLElement the xml element to parse
- * @return StoryChoice the story choice class
- */
- static function from_xml ($xml) {
- $choice = new StoryChoice();
-
- //Parses attribute
- foreach ($xml->attributes() as $key => $value) {
- switch ($key) {
- case 'goto':
- $choice->$key = (string)$value;
- break;
-
- default:
- message_die(GENERAL_ERROR, "Unknown attribute: $key = \"$value\"", "Story error");
- }
- }
-
- //Parses content
- $choice->text = (string)$xml;
-
- return $choice;
- }
+<?php
+
+/**
+ * Story choice.
+ *
+ * Zed. The immensity of stars. The HyperShip. The people.
+ *
+ * (c) 2010, Dereckson, some rights reserved.
+ * Released under BSD license.
+ *
+ * This class is a PHP mapping from the Story XML format's <choice> tag.
+ *
+ * <code>
+ * $xml = "<choice goto=\"city.entry\">Descendre vers le centre ville</choice>";
+ * $parser = new SimpleXmlElement($xml);
+ * $choice = StoryChoice::from_xml($parser);
+ *
+ * echo $choice->text; //That will output Descendre vers le centre ville
+ * echo $choice->goto; //That will output city.entry
+ * echo $choice->guid; //That will output any guid generated for this instance
+ *
+ * $thesamechoice = StoryChoice::from_xml($parser);
+ * echo $thesamechoice->guid; //That will ouput another guid
+ * </code>
+ *
+ * @package Zed
+ * @subpackage Story
+ * @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
+ */
+
+class StoryChoice {
+ /**
+ * The section key this choices links to
+ *
+ * @var string
+ */
+ public $goto;
+
+ /**
+ * The choice text
+ *
+ * @var string
+ */
+ public $text;
+
+ /**
+ * The choice GUID
+ *
+ * It will be automatically generated by the constructor, and so is an
+ * ephemere data for this StoryChoice instance.
+ *
+ * @see new_guid
+ *
+ * @var string
+ */
+ public $guid;
+
+ /**
+ * Constructor
+ */
+ function __construct () {
+ //The guid allows to build temporary URLs to get to right choice
+ $this->guid = new_guid();
+ }
+
+ /**
+ * Gets the story text as a string representation of the class
+ *
+ * @return string The story text
+ */
+ function __toString () {
+ return $this->text;
+ }
+
+ /**
+ * Initializes a new instance of StoryChoice class from a XML element
+ *
+ * @param SimpleXMLElement the xml element to parse
+ * @return StoryChoice the story choice class
+ */
+ static function from_xml ($xml) {
+ $choice = new StoryChoice();
+
+ //Parses attribute
+ foreach ($xml->attributes() as $key => $value) {
+ switch ($key) {
+ case 'goto':
+ $choice->$key = (string)$value;
+ break;
+
+ default:
+ message_die(GENERAL_ERROR, "Unknown attribute: $key = \"$value\"", "Story error");
+ }
+ }
+
+ //Parses content
+ $choice->text = (string)$xml;
+
+ return $choice;
+ }
}
\ No newline at end of file
diff --git a/includes/story/hook.php b/includes/story/hook.php
index 4c53cad..cee8fbd 100644
--- a/includes/story/hook.php
+++ b/includes/story/hook.php
@@ -1,63 +1,100 @@
-<?php
-
-/*
- * Zed
- * (c) 2010, Dereckson, some rights reserved
- * Released under BSD license
- *
- * Story hook
- */
-
-abstract class StoryHook {
- /*
- * @var Story the current story
- */
- public $story;
-
- /*
- * @var StorySection the current story section
- */
- public $section;
-
- /*
- * @var Perso the character involved in the story
- */
- public $perso;
-
- function __construct ($story, $section) {
- $this->story = $story;
- $this->section = $section;
- $this->perso = $GLOBALS['CurrentPerso'];
-
- $this->initialize();
- }
-
- /* Initializes hook. Called after constructor */
- abstract function initialize ();
-
- /*
- * Gets choices extra links
- * @param Array $links the hooks links array
- */
- function get_choices_links (&$links) {}
-
- /*
- * Updates description
- * @param string the description text (from section and previous hooks)
- */
- function update_description (&$description) {}
-
- /*
- * Adds HTML code *AT THE END* of the story content block
- * @return string HTML code to print
- */
- function add_content () {}
-
- /*
- * Adds HTML code *AFTER* the content block
- * @return string HTML code to print
- */
- function add_html () {}
-}
-
+<?php
+/**
+ * Story hook class
+ *
+ * Zed. The immensity of stars. The HyperShip. The people.
+ *
+ * (c) 2010, Dereckson, some rights reserved.
+ * Released under BSD license.
+ *
+ * This class allows to hook PHP code to a textual story.
+ *
+ * It allows the story to be completed by site elements.
+ *
+ * @example hook_demo.php for a class implementation example
+ *
+ * @package Zed
+ * @subpackage Story
+ * @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
+ */
+
+/**
+ * Story hook class
+ */
+abstract class StoryHook {
+ /**
+ * The current story
+ *
+ * @var Story
+ */
+ public $story;
+
+ /*
+ * The current story section
+ *
+ * @var StorySection
+ */
+ public $section;
+
+ /**
+ * The character involved in the story
+ *
+ * @var Perso
+ */
+ public $perso;
+
+ /**
+ * Constructor
+ *
+ * @param Story $story The story including this hook
+ * @param StorySection $section The section including this hook
+ */
+ function __construct ($story, $section) {
+ $this->story = $story;
+ $this->section = $section;
+ $this->perso = $GLOBALS['CurrentPerso'];
+
+ $this->initialize();
+ }
+
+ /**
+ * Initializes hook. Called after constructor.
+ */
+ abstract function initialize ();
+
+ /**
+ * Gets choices extra links
+ *
+ * @param Array $links the hooks links array
+ */
+ function get_choices_links (&$links) {}
+
+ /**
+ * Updates description
+ *
+ * @param string the description text (from section and previous hooks)
+ */
+ function update_description (&$description) {}
+
+ /**
+ * Adds HTML code *AT THE END* of the story content block
+ *
+ * @return string HTML code to print
+ */
+ function add_content () {}
+
+ /**
+ * Adds HTML code *AFTER* the content block
+ *
+ * @return string HTML code to print
+ */
+ function add_html () {}
+}
+
?>
\ No newline at end of file
diff --git a/includes/story/hook_demo.php b/includes/story/hook_demo.php
index c1cab5c..d5fefe5 100644
--- a/includes/story/hook_demo.php
+++ b/includes/story/hook_demo.php
@@ -1,34 +1,77 @@
-<?php
-
-/*
- * Zed
- * (c) 2010, Dereckson, some rights reserved
- * Released under BSD license
- *
- * Story hook example code
- */
-
-$class = "DemoStoryHook";
-
-class DemoStoryHook extends StoryHook {
- function initialize () {}
-
- function update_description (&$description) {
- //Performs the rot13 transform of the current description
- $description = str_rot13($description);
-
- //Appends a string to the current description
- $description .= "\n\nWazzzzzzzzzzzzzzzzaaaaaaaaaaaaaaaaaaaaaa";
- }
-
- function get_choices_links (&$links) {
- //Adds a link to /push
- $links[] = array(lang_get("PushMessage"), get_url('push'));
- }
-
- function add_html () {
- //Adds a html block
- return '<div class="black">Lorem ipsum dolor</div>';
- }
-}
+<?php
+
+/**
+ * Story hook class: example code
+ *
+ * Zed. The immensity of stars. The HyperShip. The people.
+ *
+ * (c) 2010, Dereckson, some rights reserved.
+ * Released under BSD license.
+ *
+ * This class illustrates how to use the StoryHook class.
+ *
+ * @package Zed
+ * @subpackage Story
+ * @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
+ */
+
+$class = "DemoStoryHook";
+
+/**
+ * Story hook demo class
+ */
+class DemoStoryHook extends StoryHook {
+ /**
+ * Initializes resources
+ *
+ * @see StoryHook::initialize
+ *
+ * The initialize method is called after the constructor and is mandatory,
+ * even if you've nothing to initialize, as it's an abstract method.
+ */
+ function initialize () {}
+
+ /**
+ * Updates the current section description.
+ *
+ * @see StoryHook::update_description
+ *
+ * @param string $description the description to update
+ */
+ function update_description (&$description) {
+ //Performs the rot13 transform of the current description
+ $description = str_rot13($description);
+
+ //Appends a string to the current description
+ $description .= "\n\nWazzzzzzzzzzzzzzzzaaaaaaaaaaaaaaaaaaaaaa";
+ }
+
+ /**
+ * Updates the current section choices
+ *
+ * @see StoryHook::get_choices_links
+ *
+ * @param Array $links the section links
+ */
+ function get_choices_links (&$links) {
+ //Adds a link to /push
+ $links[] = array(lang_get("PushMessage"), get_url('push'));
+ }
+
+ /**
+ * Adds content after our story content block
+ *
+ * @see StoryHook::add_html
+ */
+ function add_html () {
+ //Adds a html block
+ return '<div class="black">Lorem ipsum dolor</div>';
+ }
+}
?>
\ No newline at end of file
diff --git a/includes/story/hook_spatioport.php b/includes/story/hook_spatioport.php
index f9b385d..a5ff401 100644
--- a/includes/story/hook_spatioport.php
+++ b/includes/story/hook_spatioport.php
@@ -1,67 +1,130 @@
-<?php
-
-/*
- * Zed
- * (c) 2010, Dereckson, some rights reserved
- * Released under BSD license
- *
- * Spatioport story hook
- */
-
-require_once('includes/objects/ship.php');
-require_once('includes/geo/location.php');
-
-$class = "SpatioportStoryHook";
-
-class SpatioportStoryHook extends StoryHook {
- public $location;
- public $location_global;
- public $location_local;
-
- function get_choices_links (&$links) {
- //$links[] = array('Examiner les vaisseaux', get_url('port','ships'));
- }
-
- function initialize () {
- $this->location_global = $this->perso->location_global;
- $this->location_local = $this->section->location_local;
- $this->location = new GeoLocation($this->location_global, $this->location_local);
- }
-
- function add_content () {
- $ships = $this->get_ships();
- if (count($ships)) {
- echo "\n<h2>Ships</h2>";
- echo "<p>Amongst the ships are at the spatioport:</p>";
- echo "\n<ul>";
- foreach ($ships as $ship) {
- $url = get_url('ship', $ship);
- echo "\n\t<li><a href=\"$url\">$ship->name</a></li>";
- }
- echo "\n</ul>";
- }
-
- $ships = $this->get_ships_in_space();
- if (count($ships)) {
- echo "\n<h2>In orbit</h2>";
- $place = (string)$this->location->body;
- echo "<p>Those ships are in space around $place:</p>";
- echo "\n<ul>";
- foreach ($ships as $ship) {
- $url = get_url('ship', $ship);
- echo "\n\t<li><a href=\"$url\">$ship->name</a></li>";
- }
- echo "\n</ul>";
- }
- }
-
- private function get_ships () {
- return Ship::get_ships_at($this->location_global, $this->location_local);
- }
-
- private function get_ships_in_space () {
- return Ship::get_ships_at($this->location_global, null);
- }
-}
-
+<?php
+/**
+ * Story hook class :: spatioport
+ *
+ * Zed. The immensity of stars. The HyperShip. The people.
+ *
+ * (c) 2010, Dereckson, some rights reserved.
+ * Released under BSD license.
+ *
+ * This class allows to hook spatioport content to a story.
+ *
+ * It lists the ship inside the spatioport and in the surrounding space.
+ *
+ * @package Zed
+ * @subpackage Story
+ * @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 Adds spatioport services, like ship repair & co
+ * @todo Adds a map of the sky, with ship around
+ * @todo Consider to use the Port class instead and to move get_ships methods there.
+ */
+
+require_once('includes/objects/ship.php');
+require_once('includes/geo/location.php');
+
+/**
+ * Spatioport story hook class
+ */
+class SpatioportStoryHook extends StoryHook {
+ /**
+ * The spatioport location
+ *
+ * @var GeoLocation
+ */
+ public $location;
+
+ /**
+ * The spatioport global location
+ *
+ * @var string
+ */
+ public $location_global;
+
+ /**
+ * The spatioport local location
+ *
+ * @var string
+ */
+ public $location_local;
+
+
+ /**
+ * Updates and gets the current section choices
+ *
+ * @param Array $links The story links
+ */
+ function get_choices_links (&$links) {
+ //$links[] = array('Examiner les vaisseaux', get_url('port','ships'));
+ }
+
+ /**
+ * Initializes instance location properties
+ */
+ function initialize () {
+ $this->location_global = $this->perso->location_global;
+ $this->location_local = $this->section->location_local;
+ $this->location = new GeoLocation($this->location_global, $this->location_local);
+ }
+
+ /**
+ * Appends ship list to the story description
+ */
+ function add_content () {
+ $ships = $this->get_ships();
+ if (count($ships)) {
+ echo "\n<h2>Ships</h2>";
+ echo "<p>Amongst the ships are at the spatioport:</p>";
+ echo "\n<ul>";
+ foreach ($ships as $ship) {
+ $url = get_url('ship', $ship);
+ echo "\n\t<li><a href=\"$url\">$ship->name</a></li>";
+ }
+ echo "\n</ul>";
+ }
+
+ $ships = $this->get_ships_in_space();
+ if (count($ships)) {
+ echo "\n<h2>In orbit</h2>";
+ $place = (string)$this->location->body;
+ echo "<p>Those ships are in space around $place:</p>";
+ echo "\n<ul>";
+ foreach ($ships as $ship) {
+ $url = get_url('ship', $ship);
+ echo "\n\t<li><a href=\"$url\">$ship->name</a></li>";
+ }
+ echo "\n</ul>";
+ }
+ }
+
+ /**
+ * Get ships in the spatioports
+ *
+ * @param string $location_global global location
+ * @param string $location_local local location
+ * @return array The ships in the spatioport
+ */
+ private function get_ships () {
+ return Ship::get_ships_at($this->location_global, $this->location_local);
+ }
+
+
+ /**
+ * Get ships in the space surrounding the spatioport
+ *
+ * @param string $location_global global location
+ * @param string $location_local local location
+ * @return array The ships in the space around the spatioport
+ */
+ private function get_ships_in_space () {
+ return Ship::get_ships_at($this->location_global, null);
+ }
+}
+
?>
\ No newline at end of file
diff --git a/includes/story/section.php b/includes/story/section.php
index 440f562..bd66fa8 100644
--- a/includes/story/section.php
+++ b/includes/story/section.php
@@ -1,134 +1,160 @@
-<?php
-
-/*
- * Zed
- * (c) 2010, Dereckson, some rights reserved
- * Released under BSD license
- *
- * Story section
- */
-
-require_once('choice.php');
-require_once('hook.php');
-
-class StorySection {
- /*
- * @var string the section ID
- */
- public $id;
-
- /*
- * @var string the section title
- */
- public $title;
-
- /*
- * @var string the section description
- */
- public $description;
-
- /*
- * @var string the local location
- */
- public $location_local;
-
- /*
- * @var Array the section choices (array of StoryChoice items)
- */
- public $choices = array();
-
- /*
- * @var Array the section hooks (array of StoryHook items)
- */
- public $hooks = array();
-
- /*
- * @var boolean if true, it's the story start ; otherwise, false;
- */
- public $start;
-
- /*
- * @var Story the story calling the section
- */
- public $story;
-
- /*
- * Initializes a new instance of StorySection class
- */
- function __construct ($id, $story = null) {
- $this->id = $id;
- if ($story !== null) {
- $this->story = $story;
- }
- }
-
- /*
- * Gets choice from specified guid
- * @return StoryChoice the wanted choice, or null if it doesn't exist
- */
- function get_choice ($guid) {
- foreach ($this->choices as $choice) {
- if ($choice->guid == $guid)
- return $choice;
- }
-
- return null;
- }
-
- /*
- * Intializes a story section from an SimpleXMLElement XML fragment
- * @param SimpleXMLElement $xml the XML fragment
- * @param Story $story the calling story
- * @return StorySection the section instance
- */
- static function from_xml ($xml, $story = null) {
- //Reads attributes
- $id = '';
- $start = false;
- foreach ($xml->attributes() as $key => $value) {
- switch ($key) {
- case 'start':
- if ($value) $start = true;
- break;
-
- case 'id':
- $id = (string)$value;
- break;
-
- default:
- message_die(GENERAL_ERROR, "Unknown attribute: $key = \"$value\"", "Story error");
- }
- }
-
- if (!$id) {
- message_die(GENERAL_ERROR, "Section without id. Please add id='' in <section> tag", "Story error");
- }
-
- $section = new StorySection($id, $story);
- $section->title = (string)$xml->title;
- $section->description = (string)$xml->description;
- $section->location_local = (string)$xml->local;
- $section->start = $start;
-
- //Adds choices
- if ($xml->choices) {
- foreach ($xml->choices->choice as $choice) {
- $section->choices[] = StoryChoice::from_xml($choice);
- }
- }
-
- //Adds hooks
- if ($xml->hooks) {
- foreach ($xml->hooks->hook as $hook) {
- //<hook type="spatioport" /> will assign 'spatioport' to $hook;
- $hook = (string)$hook->attributes()->type;
- require_once("hook_$hook.php");
- $section->hooks[] = new $class($section->story, $section);
- }
- }
-
- return $section;
- }
-}
-
-?>
+<?php
+
+/**
+ * Story section class
+ *
+ * Zed. The immensity of stars. The HyperShip. The people.
+ *
+ * (c) 2010, Dereckson, some rights reserved.
+ * Released under BSD license.
+ *
+ * This class is a PHP mapping from the Story XML format's <section> tag.
+ *
+ * This class also a method to get the section where a specific choice links to.
+ *
+ * @package Zed
+ * @subpackage Story
+ * @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
+ */
+
+require_once('choice.php');
+require_once('hook.php');
+
+/**
+ * Story section class
+ */
+class StorySection {
+ /**
+ * The section ID
+ *
+ * @var string
+ */
+ public $id;
+
+ /**
+ * The section title
+ *
+ * @var string
+ */
+ public $title;
+
+ /**
+ * The section description
+ *
+ * @var string
+ */
+ public $description;
+
+ /**
+ * @var string the local location
+ */
+ public $location_local;
+
+ /**
+ * @var Array the section choices (array of StoryChoice items)
+ */
+ public $choices = array();
+
+ /*
+ * @var Array the section hooks (array of StoryHook items)
+ */
+ public $hooks = array();
+
+ /**
+ * @var boolean if true, it's the story start ; otherwise, false;
+ */
+ public $start;
+
+ /**
+ * @var Story the story calling the section
+ */
+ public $story;
+
+ /**
+ * Initializes a new instance of StorySection class
+ */
+ function __construct ($id, $story = null) {
+ $this->id = $id;
+ if ($story !== null) {
+ $this->story = $story;
+ }
+ }
+
+ /**
+ * Gets choice from specified guid
+ *
+ * @return StoryChoice the wanted choice, or null if it doesn't exist
+ */
+ function get_choice ($guid) {
+ foreach ($this->choices as $choice) {
+ if ($choice->guid == $guid)
+ return $choice;
+ }
+
+ return null;
+ }
+
+ /**
+ * Initializes a story section from an SimpleXMLElement XML fragment
+ *
+ * @param SimpleXMLElement $xml the XML fragment
+ * @param Story $story the calling story
+ * @return StorySection the section instance
+ */
+ static function from_xml ($xml, $story = null) {
+ //Reads attributes
+ $id = '';
+ $start = false;
+ foreach ($xml->attributes() as $key => $value) {
+ switch ($key) {
+ case 'start':
+ if ($value) $start = true;
+ break;
+
+ case 'id':
+ $id = (string)$value;
+ break;
+
+ default:
+ message_die(GENERAL_ERROR, "Unknown attribute: $key = \"$value\"", "Story error");
+ }
+ }
+
+ if (!$id) {
+ message_die(GENERAL_ERROR, "Section without id. Please add id='' in <section> tag", "Story error");
+ }
+
+ $section = new StorySection($id, $story);
+ $section->title = (string)$xml->title;
+ $section->description = (string)$xml->description;
+ $section->location_local = (string)$xml->local;
+ $section->start = $start;
+
+ //Adds choices
+ if ($xml->choices) {
+ foreach ($xml->choices->choice as $choice) {
+ $section->choices[] = StoryChoice::from_xml($choice);
+ }
+ }
+
+ //Adds hooks
+ if ($xml->hooks) {
+ foreach ($xml->hooks->hook as $hook) {
+ //<hook type="spatioport" /> will assign 'spatioport' to $hook;
+ $hook = (string)$hook->attributes()->type;
+ require_once("hook_$hook.php");
+ $section->hooks[] = new $class($section->story, $section);
+ }
+ }
+
+ return $section;
+ }
+}
+
+?>
diff --git a/includes/story/story.php b/includes/story/story.php
index 0d39a82..7a713a4 100644
--- a/includes/story/story.php
+++ b/includes/story/story.php
@@ -1,106 +1,133 @@
-<?php
-
-/*
- * Zed
- * (c) 2010, Dereckson, some rights reserved
- * Released under BSD license
- *
- * Story
- */
-
-require_once('section.php');
-
-/*
- * @package Zed
- * @subpackage story
- */
-class Story {
- /*
- * @var string the file path
- */
- public $file;
-
- /*
- * @var string the story title
- */
- public $title;
- /*
- * @var Array an array of StorySection elements
- */
- public $sections = array();
-
- /*
- * @var SimpleXMLElement the SimpleXML parser
- */
- private $xml;
-
- /*
- * @var string the index of start section in sections array
- */
- private $startSection = null;
-
- /*
- * @var Array an array of StorySection elements, indexed by location
- */
- private $sectionsByLocation = array();
-
- function __construct ($file) {
- //Opens .xml
- if (!file_exists($file)) {
- message_die(GENERAL_ERROR, "$file not found.", "Story loading error");
- }
-
- $this->file = $file;
- $this->parse();
- }
-
- /*
- * Gets start section
- * @return StorySection the section where the story starts, or null if not defined
- */
- function get_start_section () {
- return ($this->startSection != null) ? $this->sections[$this->startSection] : null;
- }
-
- /*
- * Gets section from local location
- * @return StorySection the default section at this location, or null if not defined
- */
- function get_section_from_location ($location) {
- return array_key_exists($location, $this->sectionsByLocation) ? $this->sectionsByLocation[$location] : null;
- }
-
- /*
- * Parses XML file
- */
- function parse () {
- //Parses it
- $this->xml = simplexml_load_file($this->file);
- $this->title = (string)$this->xml->title;
- foreach ($this->xml->section as $section) {
- //Gets section
- $section = StorySection::from_xml($section, $this);
-
- //Have we a start section?
- if ($section->start) {
- //Ensures we've only one start section
- if ($this->startSection != null) {
- message_die(GENERAL_ERROR, "Two sections have start=\"true\": $section->id and $this->startSection.", "Story error");
- }
- $this->startSection = $section->id;
- }
-
- //By location
- if ($section->location_local) {
- $this->sectionsByLocation[$section->location_local] = $section;
- }
-
- //Adds to sections array
- $this->sections[$section->id] = $section;
- }
- }
-}
-
-
-
+<?php
+
+/**
+ * Story class
+ *
+ * Zed. The immensity of stars. The HyperShip. The people.
+ *
+ * (c) 2010, Dereckson, some rights reserved.
+ * Released under BSD license.
+ *
+ * This class is a PHP mapping from the Story XML format.
+ *
+ * This class also provides a collection of helper methods to explore the story.
+ *
+ * @package Zed
+ * @subpackage Story
+ * @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
+ */
+
+/**
+ * Story class
+ */
+class Story {
+ /**
+ * The file path
+ *
+ * @var string
+ */
+ public $file;
+
+ /**
+ * The story title
+ *
+ * @var string
+ */
+ public $title;
+
+ /**
+ * An array of StorySection elements
+ *
+ * @var Array
+ */
+ public $sections = array();
+
+ /**
+ * The SimpleXML parser
+ *
+ * @var SimpleXMLElement
+ */
+ private $xml;
+
+ /**
+ * The index of start section in sections array
+ *
+ * @var string
+ */
+ private $startSection = null;
+
+ /**
+ * An array of StorySection elements, indexed by location
+ *
+ * @var Array
+ */
+ private $sectionsByLocation = array();
+
+ function __construct ($file) {
+ //Opens .xml
+ if (!file_exists($file)) {
+ message_die(GENERAL_ERROR, "$file not found.", "Story loading error");
+ }
+
+ $this->file = $file;
+ $this->parse();
+ }
+
+ /**
+ * Gets start section
+ *
+ * @return StorySection the section where the story starts, or null if not defined
+ */
+ function get_start_section () {
+ return ($this->startSection != null) ? $this->sections[$this->startSection] : null;
+ }
+
+ /**
+ * Gets section from local location
+ *
+ * @return StorySection the default section at this location, or null if not defined
+ */
+ function get_section_from_location ($location) {
+ return array_key_exists($location, $this->sectionsByLocation) ? $this->sectionsByLocation[$location] : null;
+ }
+
+ /**
+ * Parses XML file
+ */
+ function parse () {
+ //Parses it
+ $this->xml = simplexml_load_file($this->file);
+ $this->title = (string)$this->xml->title;
+ foreach ($this->xml->section as $section) {
+ //Gets section
+ $section = StorySection::from_xml($section, $this);
+
+ //Have we a start section?
+ if ($section->start) {
+ //Ensures we've only one start section
+ if ($this->startSection != null) {
+ message_die(GENERAL_ERROR, "Two sections have start=\"true\": $section->id and $this->startSection.", "Story error");
+ }
+ $this->startSection = $section->id;
+ }
+
+ //By location
+ if ($section->location_local) {
+ $this->sectionsByLocation[$section->location_local] = $section;
+ }
+
+ //Adds to sections array
+ $this->sections[$section->id] = $section;
+ }
+ }
+}
+
+
+
?>
\ No newline at end of file
diff --git a/includes/travel/place.php b/includes/travel/place.php
index 9a592e9..7ddc3ae 100644
--- a/includes/travel/place.php
+++ b/includes/travel/place.php
@@ -1,86 +1,122 @@
<?php
-/*
+/**
* TravelPlace class
- *
+ *
+ * Zed. The immensity of stars. The HyperShip. The people.
+ *
+ * (c) 2010, Dereckson, some rights reserved.
+ * Released under BSD license.
+ *
* 0.1 2010-07-19 22:10 DcK
+ *
+ * @package Zed
+ * @subpackage Travel
+ * @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
+ */
+
+/**
+ * TravelPlace class
*
- * @package Zed
- * @subpackage Travel
- * @copyright Copyright (c) 2010, Dereckson
- * @license Released under BSD license
- * @version 0.1
+ * The TravelPlace class is a set of rules determining which moves are valid
+ * in a specific place.
*
+ * @see GeoPlace
+ *
*/
class TravelPlace {
- /*
- * @var string the place code
+ /**
+ * The place code
+ *
+ * @var string
*/
public $code;
- /*
- * @var boolean determines if any local location move is valid
+ /**
+ * Determines if any local location move is valid
+ *
+ * @var bool
*/
public $freeLocalMove = false;
- /*
- * @var Array array of strings, each item another place reachable
+ /**
+ * Array of strings, each item another place reachable
+ *
+ * This matches GlobalTravelTo XML tags.
+ *
+ * @var Array
*/
public $globalTravelTo = array();
- /*
- * @var Array array of array, containing [location, alias, name] entries
+ /**
+ * Aray of array, containing [location, alias, name] entries
+ *
+ * This matches LocalMove XML tags.
+ *
+ * @var Array
*/
public $localMoves = array();
+ /**
+ * Initializes a new TravelPlace instance, from the specified XML fragment
+ *
+ * @param string $xml the XML fragment to parse
+ * @return TravelPlace the TravelPlace instance maching the specified XML fragment
+ */
static function from_xml ($xml) {
$travelPlace = new TravelPlace();
//Reads attributes: <TravelPlace code="B00001001" freeLocalMove="true">
foreach ($xml->attributes() as $key => $value) {
switch ($key) {
case 'code':
$travelPlace->code = (string)$value;
break;
case 'freeLocalMove':
$travelPlace->freeLocalMove = (boolean)$value;
break;
}
}
//<GlobalTravelTo code="B00001002" />
foreach ($xml->GlobalTravelTo as $globalTravelToXml) {
foreach ($globalTravelToXml->attributes() as $key => $value) {
if ($key == "code") {
$travelPlace->globalTravelTo[] = (string)$value;
}
}
}
//<LocalMove local_location="(0, 0, 0)" alias="C0" name="Core" />
foreach ($xml->LocalMove as $localMoveXml) {
$localMove = array(null, null, null);
foreach ($localMoveXml->attributes() as $key => $value) {
switch ($key) {
case 'local_location':
$localMove[0] = (string)$value;
break;
case 'alias':
$localMove[1] = (string)$value;
break;
case 'name':
$localMove[2] = (string)$value;
break;
}
}
$travelPlace->localMoves[] = $localMove;
}
return $travelPlace;
}
}
?>
\ No newline at end of file
diff --git a/includes/travel/travel.php b/includes/travel/travel.php
index e74018e..b927334 100644
--- a/includes/travel/travel.php
+++ b/includes/travel/travel.php
@@ -1,105 +1,134 @@
<?php
-/*
+/**
* Travel helper class
- *
+ *
+ * Zed. The immensity of stars. The HyperShip. The people.
+ *
+ * (c) 2010, Dereckson, some rights reserved.
+ * Released under BSD license.
+ *
* 0.1 2010-07-18 22:05 DcK
+ *
+ * @package Zed
+ * @subpackage Travel
+ * @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
+ */
+
+/**
+ * Travel helper class
*
- * @package Zed
- * @subpackage Travel
- * @copyright Copyright (c) 2010, Dereckson
- * @license Released under BSD license
- * @version 0.1
+ * The Travel class reads content/travel.xml to get travel special rules
*
- * This class implements a singleton pattern.
+ * It so be able to provide methods determining if a move is or not valid.
*
+ * This class implements a singleton pattern.
*/
-
class Travel {
- /*
- * @var Array array of TravelPlace, each one a custom travel rule
- * This array is indeed by TravelPlace code.
+ /**
+ * Array of TravelPlace, each one a custom travel rule
+ *
+ * This array is indexed by TravelPlace code.
+ *
+ * @var Array
*/
- public $globalTravelTo = array();
+ public $globalTravelTo;
+ /**
+ * Constructor
+ */
+ function __construct () {
+ //Initializes array
+ $this->globalTravelTo = array();
+ }
- /*
+ /**
* Gets and initializes if needed the Travel instance
+ *
+ * @return Travel the Travel instance
*/
static function load () {
require_once('includes/cache/cache.php');
$cache = Cache::load();
if (!$travel = $cache->get('zed_travel')) {
//Initializes resource and caches it
$travel = new Travel();
$travel->load_xml("content/travel.xml");
$cache->set('zed_travel', serialize($travel));
return $travel;
}
return unserialize($travel);
}
- /*
+ /**
* Loads a travel configuration XML file
+ *
* @param string the path to the travel XML file
*/
function load_xml ($file) {
require_once('place.php');
$xml = simplexml_load_file($file);
foreach ($xml->TravelPlace as $travelPlaceXml) {
$travelPlace = TravelPlace::from_xml($travelPlaceXml);
$this->globalTravelTo[$travelPlace->code] = $travelPlace;
}
}
- /*
+ /**
* Determines if a perso can travel from $from to $to
+ *
* If an alias have been used for $to local location, set correct location.
*
* @param GeoLocation the location where the perso is
* @param GeoLocation the location where the perso wants to go
- * @return true if the travel move is valid ; otherwise, false.
+ * @return boolean if the travel move is valid ; otherwise, false.
*/
function can_travel ($from, &$to) {
if ($from->global != $to->global) {
//Checks if we can locally from $from to $to place
if (!array_key_exists($from->global, $this->globalTravelTo)) {
return false;
}
$travelPlace = $this->globalTravelTo[$from->global];
if (!in_array($to->global, $travelPlace->globalTravelTo)) {
return false;
}
}
if ($to->containsLocalLocation) {
//Determines if we've custom rules about local moves in $to
if (!array_key_exists($to->global, $this->globalTravelTo)) {
return false;
}
$travelPlace = $this->globalTravelTo[$to->global];
//Is it's an especially allowed movement?
foreach ($travelPlace->localMoves as $move) {
//move is a [location, alias, name] array
//If any of those 3 parameters matches $to->local, it's okay
if (in_array($to->local, $move)) {
$to->local = $move[0];
return true;
}
}
if ($travelPlace->freeLocalMove) {
//We can move freely, perfect
return true;
}
}
return false;
}
}
?>
\ No newline at end of file
diff --git a/index.php b/index.php
index 864bfd7..e49b8d3 100644
--- a/index.php
+++ b/index.php
@@ -1,230 +1,230 @@
<?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)
*/
////////////////////////////////////////////////////////////////////////////////
///
/// Initialization
///
-//Pluton library
+//Keruald (formelly Pluton) library
include('includes/core.php');
//Session
$IP = encode_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 infos
//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
require('includes/Smarty/Smarty.class.php');
$smarty = new Smarty();
$current_dir = dirname(__FILE__);
$smarty->template_dir = $current_dir . '/skins/' . THEME;
$smarty->compile_dir = $current_dir . '/cache/compiled';
$smarty->cache_dir = $current_dir . '/cache';
$smarty->config_dir = $current_dir;
$smarty->config_vars['StaticContentURL'] = $Config['StaticContentURL'];
//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 selector
///
//Handles form
if ($_POST['form'] == 'perso.create') {
$perso = new Perso();
$perso->load_from_form();
$perso->user_id = $CurrentUser->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");
} else if (!Perso::is_available_nickname($perso->nickname)) {
$errors[] = lang_get("UnavailableNickname");
}
//Save or prints again forms
if (!$errors) {
//Saves perso, logs in
$perso->save_to_database();
$smarty->assign('NOTIFY', lang_get('NewCharacterCreated'));
$CurrentPerso = $perso;
set_info('perso_id', $perso->id);
$CurrentPerso->set_flag("site.lastlogin", $_SERVER['REQUEST_TIME']);
//Notifies inviter
require_once('includes/objects/message.php');
require_once('includes/objects/invite.php');
$message = new Message();
$message->from = 0;
$message->to = invite::who_invited($perso->id);
$message->text = sprintf(
lang_get('InvitePersoCreated'),
$perso->name,
get_server_url() . get_url('who', $perso->nickname)
);
$message->send();
} else {
$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 have selected a perso
$CurrentPerso = new Perso($_GET['perso_id']);
if ($CurrentPerso->user_id != $CurrentUser->id) {
//Hack
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);
////////////////////////////////////////////////////////////////////////////////
///
/// 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 'request':
case 'page':
case 'explore':
case 'ship':
case 'settings':
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 404 error
dieprint_r($url, 'Unknown URL');
}
?>
\ No newline at end of file

File Metadata

Mime Type
text/x-diff
Expires
Mon, Nov 11, 11:02 (2 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
21270
Default Alt Text
(131 KB)

Event Timeline