diff --git a/do.php b/do.php index 015c2a3..ff034a1 100644 --- a/do.php +++ b/do.php @@ -1,471 +1,471 @@ * @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); +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 /// 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 //Gets current perso require_once('includes/objects/perso.php'); $CurrentUser = get_logged_user(); //Gets current user infos 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 print 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 whether 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 move 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 $location_local = urldecode($location_local); $CurrentPerso->move_to(null, $location_local); //Returns GeoLocation relevant instance return $CurrentPerso->location; } /** * Moves the current perso's, setting a new local location. * * We don't require a security hash. If the users want to play with it, no problem. * You generally move inside a global location as you wish. * So, if you write a story capturing a perso, use flags to handle this escape! * * @param string $move the move (coordinates or direction) * @param int $factor a number multiplying the specified move [optional] * @return GeoLocation the current perso's GeoLocation object * * e.g. to move from 2 units to east, you can use one of those instructions: * local_move('east', 2); * local_move('2,0,0'); * local_move('1,0,0', 2); * * Valid moves string are north, east, south, west, up and down. * Valid moves coordinates are x,y,z (3 integers, comma as separator) */ static function local_move ($move, $factor = 1) { global $CurrentPerso; //Ensures we've the correct amount of arguments if (func_num_args() < 1) { return null; } //Parses $move switch ($move) { case 'north': $move = [0, 1, 0]; break; case 'east': $move = [1, 0, 0]; break; case 'south': $move = [0, -1, 0]; break; case 'west': $move = [-1, 0, 0]; break; case 'up': $move = [0, 0, 1]; break; case 'down': $move = [0, 0, -1]; break; default: $move = split(',', $move, 3); foreach ($move as $coordinate) { if (!is_numeric($coordinate)) { return null; } } } //Moves current perso to specified location if ($location_local = GeoPoint3D::fromString($CurrentPerso->location->local)) { $location_local->translate($move[0] * $factor, $move[1] * $factor, $move[2] * $factor); $CurrentPerso->move_to(null, $location_local->sprintf("(%d, %d, %d)")); //Returns GeoLocation relevant instance return $CurrentPerso->location; } //Old local location weren't a GeoPoint3D return null; } /** * Moves the current perso's, setting a new local location, using polar+z coordinates. * Polar+z coordinates are polar coordinates, plus a cartesian z dimension. * * We don't require a security hash. If the users want to play with it, no problem. * You generally move inside a global location as you wish. * So, if you write a story capturing a perso, use flags to handle this escape! * * @param string $move the move (coordinates or direction) * @param int $factor a number multiplying the specified move [optional] * @return GeoLocation the current perso's GeoLocation object * * Valid moves string are cw, ccw, out, in, up and down. * r: out = +12 in = -12 * °: cw = +20° ccw = -20 * Valid moves coordinates are r,°,z (3 integers, comma as separator) * (the medium value can also be integer + °) * * e.g. to move of two units (the unit is 20°) clockwise: * polarz_local_move('cw', 2); * polarz_local_move('(0, 20°, 0)', 2); * polarz_local_move('(0, 40°, 0)'); * Or if you really want to use radians (PI/9 won't be parsed): * polarz_local_move('(0, 0.6981317007977318, 0)'; * */ static function polarz_local_move ($move, $factor = 1) { global $CurrentPerso; //Ensures we've the correct amount of arguments if (func_num_args() < 1) { return null; } //Parses $move $move = urldecode($move); switch ($move) { case 'cw': $move = [0, '20°', 0]; break; case 'ccw': $move = [0, '-20°', 0]; break; case 'in': $move = [+12, 0, 0]; break; case 'out': $move = [-12, 0, 0]; break; case 'up': $move = [0, 0, 1]; break; case 'down': $move = [0, 0, -1]; break; default: $move = split(',', $move, 3); foreach ($move as $coordinate) { if (!is_numeric($coordinate) && !preg_match("/^[0-9]+ *°$/", $coordinate)) { return null; } } } dieprint_r($move); //Moves current perso to specified location if ($location_local = GeoPoint3D::fromString($CurrentPerso->location->local)) { $location_local->translate($move[0] * $factor, $move[1] * $factor, $move[2] * $factor); $CurrentPerso->move_to(null, $location_local->sprintf("(%d, %d, %d)")); //Returns GeoLocation relevant instance return $CurrentPerso->location; } //Old local location weren't a GeoPoint3D return null; } /** * Moves the current perso's, setting a new global and local location. * * @param string $location_global The global location * @param string $location_local The local location * @return GeoLocation the current perso's GeoLocation object */ static function global_move ($location_global, $location_local = null) { //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; } //Moves global $CurrentPerso; $CurrentPerso->move_to($location_global, $location_local); 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(); $content->load_from_form(); $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 /// //Parses URL $Config['SiteURL'] = get_server_url() . $_SERVER["PHP_SELF"]; $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(['Actions', $method], $args); echo json_encode($result); } else { echo "

Method doesn't exist: $method

"; } if (array_key_exists('redirectTo', $_REQUEST)) { //If user JS disabled, you can add ?redirectTo= followed by an URL echo "

Instead to print a callback value, redirects to $_REQUEST[redirectTo]

"; } } else { //Prod version doesn't prints warning <== silence operator if (method_exists('Actions', $method)) { $result = @call_user_func_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); } } } diff --git a/includes/SmartLine/SmartLine.php b/includes/SmartLine/SmartLine.php index df86aba..31fcf2c 100755 --- a/includes/SmartLine/SmartLine.php +++ b/includes/SmartLine/SmartLine.php @@ -1,537 +1,537 @@ * @copyright 2007 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/ * @link http://bitbucket.org/dereckson/smartline * @filesource /////////////////////////////////////////////////////////////////////////////// // SECTION I - INITIALIZATION /////////////////////////////////////////////////////////////////////////////// //Constants /** * The standard, regular output (like STDOUT on POSIX systems) */ if (!defined('STDOUT')) { - define('STDOUT', 1, true); + define('STDOUT', 1, true); } /** * The error output (like STDERR on POSIX systems) */ if (!defined('STDERR')) { define('STDERR', -1, true); } /////////////////////////////////////////////////////////////////////////////// // SECTION Ibis - L10n /////////////////////////////////////////////////////////////////////////////// //Ensures $lang is a standard array if (empty($lang) || !is_array($lang)) { $lang = []; } $lang = array_merge($lang, [ //Errors 'InvalidCommand' => "Invalid command %s. Use showcommands to show all commands.", 'RegisteredButNotExistingCommand' => "[CRITICAL ERROR] The command %s has correctly been registered but its method or class doesn't exist.", 'NotYetHelpForThiscommand' => "This command hasn't been documented yet.", //Help 'DefaultHelp' => "This SmartLine is a command line interface.

showcommands prints the list.
help <command> prints help for this command.", 'Help' => [ 'help' => "help <command> prints command help.", 'showcommands' => 'show available commands' ] ]); /////////////////////////////////////////////////////////////////////////////// // SECTION II - HELPERS FUNCTIONS /////////////////////////////////////////////////////////////////////////////// /** * Error handler called during SmartLine command execution. * * Any error occurring during command execution will be set in STDERR. * * To get an array with all the errors: * $errors = $yourSmartLine->gets_all(STDERR) * * Or to prints all the error: * $yourSmartLine->prints_all(STDERR) * * Or to pops (gets and deletes) only the last error: * $lastError = $yourSmartLine->gets(STDERR) * * @link http://www.php.net/manual/en/function.set-error-handler.php set_error_handler, PHP manual * @link http://www.php.net/manual/en/errorfunc.examples.php Error handling examples, PHP manual * * @param int $level The PHP error level * @param string $error The error description * @param string $file The script where the error occurred * @param int $line The line where the error occurred */ function SmartLineHandler($level, $error, $file, $line) { switch ($level) { case E_NOTICE: $type = 'Notice'; break; CASE E_WARNING: $type = 'Warning'; break; CASE E_ERROR: $type = 'Error'; break; default: $type = "#$level"; } $_SESSION['SmartLineOutput'][STDERR][] = "[PHP $type] $error in $file line $line."; return true; } /////////////////////////////////////////////////////////////////////////////// // SECTION III - BASE CLASSES /////////////////////////////////////////////////////////////////////////////// //SmartLineCommand is a class implementing a SmartLine command. //If you want to create a more complex command, extends this class. /** * The SmartLine command base class. * * To add a command, create an instance of the class, like: * * class HelloWorldSmartLineCommand extends SmartLineCommand { * public function run ($argv, $argc) { * $this->SmartLine->puts('Hello World!'); * } * } * * * Then, registers your command: * * $yourSmartLine->register_object('hello', 'HelloWorldSmartLineCommand'); * * * @see SmartLine::register_object */ class SmartLineCommand { /** * Initializes a new instance of the SmartLine Command * * @param SmartLine $SmartLine the SmartLine the command belongs */ public function __construct ($SmartLine) { $this->SmartLine = $SmartLine; } /** * Gets the command help text or indicates help should be fetched from $lang array * * @return string|bool a string containing the command help or the bool value false, to enable the default behavior (ie prints $lang['help']['nameOfTheCommand']) */ public function help () { return false; } /** * Runs the command * * @param array $argv an array of string, each item a command argument * @param int $argc the number of arguments */ public function run ($argv, $argc) { } /** * The SmartLine where this instance of the command is registered * * @var SmartLine */ public $SmartLine; } /** * This class represents a SmartLine instance * * If you use only register_object, you can use it directly. * If you use register_method, extends this class in your SmartLine. */ class SmartLine { /** * Initializes a new instance of the SmartLine object. */ public function __construct () { //Assumes we've an empty array where store registered commands. $this->commands = []; //Let's register standard commands $this->register_object('showcommands', 'ShowCommandsSmartLineCommand'); $this->register_object('help', 'HelpSmartLineCommand'); } /** * Registers a private method as command. * * @param string $command The name of the command to register * @param string $method The method to register [OPTIONAL]. If omitted, the method registered will be the method having the same name as the command. * @param bool $useArgvArgc If true, indicates the method uses $argv, $argc as parameters. If false, indicates the method uses its parameters (default behavior). [OPTIONAL] * * @return bool true if the command have successfully been registered ; otherwise, false. */ public function register_method ($command, $method = null, $useArgvArgc = false) { if (is_null($function)) $method = $command; if (!method_exists($this, $method)) { $this->lastError = "Registration failed. Unknown method $method"; return false; } $className = ucfirst($method) . 'SmartLineCommand'; //If class exists, add a uniqid after function while (class_exists($method)) { $className = uniqid(ucfirst($method)) . 'SmartLineCommand'; } //Creates the class if ($useArgvArgc) { $call = "$this->SmartLine->$method(\$argv, \$argc);"; } else { //We don't know how many args we've, so we use call_user_func_array $call = "array_shift(\$argv); call_user_func_array( array(&\$this->SmartLine, '$method'), \$argv );"; } $code = "class $className extends SmartLineCommand { public function run (\$argv, \$argc) { $call } }"; eval($code); $this->register_object($command, $className); return true; } /** * Registers an object extending SmartLineCommand as command. * * @param string $command The name of the command to register * @param SmartLineCommand|string $object The object extending SmartLineCommand. This can be the name of the class (string) or an instance already initialized of the object (SmartLineCommand). * @return bool true if the command have successfully been registered ; otherwise, false. */ public function register_object ($command, $object) { if (is_object($object)) { //Sets SmartLine property $object->SmartLine = $this; } elseif (is_string($object) && class_exists($object)) { //Creates a new instance of $object $object = new $object($this); } else { $this->lastError = "Registration failed. register_object second parameter must be a class name (string) or an already initialized instance of such class (object) and not a " . gettype($object); return false; } if (!$this->caseSensitive) { $command = strtolower($command); } $this->commands[$command] = $object; return true; } /** * Determines whether the specified command have been registered. * * @param string $command The name of the command to check * @return true if the specified command have been registered ; otherwise, false. */ public function isRegistered ($command) { if (!$this->caseSensitive) { $command = strtolower($command); } return array_key_exists($command, $this->commands); } /** * Executes the specified expression. * * If an error occurs during the command execution: * the STDERR output will contains the errors, * the value returned by this methods will be false. * * To execute the command and prints error: * * $fooSmartLine = new SmartLine(); * //... * $result = $fooSmartLine->execute($expression); * $fooSmartLine->prints_all(); * if (!$result) { * //Errors! * echo "

Errors

"; * $fooSmartLine->prints_all(STDERR); * } *
* * @param string $expression The expression containing the command to execute * @return bool true if the command have been successfully executed ; otherwise, false. */ public function execute ($expression) { //Does nothing if blank line if (!$expression) return; //Prepares $argv and $argc $argv = $this->expression2argv($expression); $argc = count($argv); //Gets command $command = $this->caseSensitive ? $argv[0] : strtolower($argv[0]); //If command doesn't exist, throws an error if (!array_key_exists($command, $this->commands)) { global $lang; $this->puts(sprintf($lang['InvalidCommand'], $command), STDERR); return false; } //Executes command, intercepting error and returns result set_error_handler("SmartLineHandler"); try { $result = $this->commands[$command]->run($argv, $argc); } catch (Exception $ex) { $this->puts("
$ex
", STDERR); } restore_error_handler(); return $result; } /** * Adds a message to the specified output queue. * * @param string $message the message to queue * @param int $output The output queue (common values are STDERR and STDOUT constants). It's an optional parameter ; if omitted, the default value will be STDOUT. */ public function puts ($message, $output = STDOUT) { // $_SESSION['SmartLineOutput'][$output][] = $message; } /** * Truncates the specified output queue. * * @param int $output The output queue (common values are STDERR and STDOUT constants). It's an optional parameter ; if omitted, the default value will be STDOUT. */ public function truncate ($output = STDOUT) { unset($_SESSION['SmartLineOutput'][$output]); } /** * Pops (gets and clears) the first message from the specified output queue. * * @param int $output The output queue (common values are STDERR and STDOUT constants). It's an optional parameter ; if omitted, the default value will be STDOUT. * @return string the message */ public function gets ($output = STDOUT) { if (count($_SESSION['SmartLineOutput'][$output] > 0)) { return array_pop($_SESSION['SmartLineOutput'][$output]); } } /** * Gets the number of messages in the specified output queue. * * @param int $output The output queue (common values are STDERR and STDOUT constants). It's an optional parameter ; if omitted, the default value will be STDOUT. */ public function count ($output = STDOUT) { return count($_SESSION['SmartLineOutput'][$output]); } /** * Gets all the message from the specified output queue. * * @param int $output The output queue (common values are STDERR and STDOUT constants). It's an optional parameter ; if omitted, the default value will be STDOUT. * @param string $prefix The string to prepend each message with. It's an optional parameter ; if omitted, '

'. * @param string $suffix The string to append each message with. It's an optional parameter ; if omitted, '

'. * @return Array an array of string, each item a message from the specified output queue */ public function gets_all ($output = STDOUT, $prefix = '

', $suffix = '

') { $count = count($_SESSION['SmartLineOutput'][$output]); if ($count == 0) { return; } for ($i = 0 ; $i < $count ; $i++) { $buffer .= $prefix . $_SESSION['SmartLineOutput'][$output][$i] . $suffix; } unset ($_SESSION['SmartLineOutput'][$output]); return $buffer; } /** * Prints all the message from the specified output queue. * * @param int $output The output queue (common values are STDERR and STDOUT constants). It's an optional parameter ; if omitted, the default value will be STDOUT. * @param string $prefix The string to prepend each message with. It's an optional parameter ; if omitted, '

'. * @param string $suffix The string to append each message with. It's an optional parameter ; if omitted, '

'. */ public function prints_all ($output = STDOUT, $prefix = '

', $suffix = '

') { $count = count($_SESSION['SmartLineOutput'][$output]); if ($count == 0) { return; } for ($i = 0 ; $i < $count ; $i++) { echo $prefix, $_SESSION['SmartLineOutput'][$output][$i], $suffix; } unset ($_SESSION['SmartLineOutput'][$output]); } /** * Gets the command help * * @param string $command The command to get help from * @param string The command help */ public function gethelp ($command) { return $this->commands[$command]->help(); } /** * Gets an an argv array from the specified expression * * @param string $expression The expression to transform into a argv array * @return Array An array of string, the first item the command, the others those arguments. */ private function expression2argv ($expression) { //Checks if expression contains " $pos1 = strpos($expression, '"'); //We isolate "subexpression" if ($pos1 !== false) { $pos2 = $pos1; do { $pos2 = strpos($expression, '"', $pos2 + 1); } while ($pos2 !== false && ($expression[$pos2 - 1] == "\\" && $expression[$pos2 - 2] != "\\")); if ($pos2 === false) { //If final quote is missing, throws a warning and autoadds it. $this->puts("[Warning] Final \" missing in $expression.", STDERR); $argv = $this->expression2argv(substr($expression, 0, $pos1)); $argv[] = substr($expression, $pos1 + 1); return $argv; } return array_merge( $this->expression2argv(substr($expression, 0, $pos1)), [substr($expression, $pos1 + 1, $pos2 - $pos1 - 1)], $this->expression2argv(substr($expression, $pos2 + 1)) ); } //Standard expression (ie without ") $argv = []; $items = explode(' ', $expression); foreach ($items as $item) { $item = trim($item); if (!$item) { //blank, we ignore continue; } $argv[] = $item; } return $argv; } //Contains last error public $lastError = ''; //If true, command isn't equal to Command public $caseSensitive = true; } /////////////////////////////////////////////////////////////////////////////// // SECTION IV - STANDARD COMMANDS /////////////////////////////////////////////////////////////////////////////// /* * These commands are available in all default smartlines instance */ /** * The standard command "showcommands" * * This command returns a list, with all the available commands */ class ShowCommandsSmartLineCommand extends SmartLineCommand { /** * Runs the command * * @param array $argv an array of string, each item a command argument * @param int $argc the number of arguments */ public function run ($argv, $argc) { $commands = array_keys($this->SmartLine->commands); sort($commands); $this->SmartLine->puts(implode(' ', $commands)); } } /** * The standard command "help" * * This command prints command help. * * Help could be defined * in the command classes, as a return value from the help method ; * in the $lang['Help'] array, at the command key (e.g. $lang['Help']['quux'] for the quux command). */ class HelpSmartLineCommand extends SmartLineCommand { /** * Runs the command * * @param array $argv an array of string, each item a command argument * @param int $argc the number of arguments */ public function run ($argv, $argc) { global $lang; if ($argc == 1) { $this->SmartLine->puts($lang['DefaultHelp']); } elseif (!$this->SmartLine->isRegistered($argv[1])) { $this->SmartLine->puts(sprintf($lang['InvalidCommand'], str_replace(' ', ' ', $argv[1])), STDERR); } else { $command = strtolower($argv[1]); if (!$help = $this->SmartLine->gethelp($command)) { if (array_key_exists($command, $lang['Help'])) { $help = $lang['Help'][$command]; } else { $help = $lang['NotYetHelpForThiscommand']; } } $this->SmartLine->puts($help); } } } /////////////////////////////////////////////////////////////////////////////// diff --git a/includes/api/api_helpers.php b/includes/api/api_helpers.php index ad2df47..c4b4019 100755 --- a/includes/api/api_helpers.php +++ b/includes/api/api_helpers.php @@ -1,171 +1,171 @@ * @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 */ /** * The main function for converting to an XML document. * * Pass in a multi dimensional array and this recursively loops through * and builds up an XML document. * * @param mixed $data * @param string $rootNodeName What you want the root node to be - defaultsto data. * @param SimpleXMLElement $xml Should only be used recursively * @param string $unknownNodeName Name to give to unknown (numeric) keys * @return string XML */ function toXml($data, $rootNodeName = 'data', $xml = null, $unknownNodeName = 'unknownNode') { if (!$rootNodeName) { $rootNodeName = 'data'; } if (!$unknownNodeName) { $unknownNodeName = 'unknownNode'; } // turn off compatibility mode as simple xml throws a wobbly if you don't. if (ini_get('zend.ze1_compatibility_mode') == 1) { ini_set('zend.ze1_compatibility_mode', 0); } if ($xml == null) { if (!is_array($data) && !is_object($data)) { //We've a singleton if (is_bool($data)) { $data = $data ? 'true' : 'false'; } return "<$rootNodeName>$data"; } //Starts with simple document $xml = simplexml_load_string("<$rootNodeName />"); } // loop through the data passed in. foreach ($data as $key => $value) { // no numeric keys in our xml please! if (is_numeric($key)) { // make string key... $key = $unknownNodeName . '_'. (string)$key; } // replace anything not alpha numeric $key = preg_replace('/[^a-z]/i', '', $key); //If there is another array found recursively call this function if (is_array($value)) { $node = $xml->addChild($key); //Recursive call. toXml($value, $rootNodeName, $node, $unknownNodeName); } elseif (is_object($value)) { $node = $xml->addChild($key); foreach ($value as $subkey => $subvalue) { if ($subkey == "lastError") { continue; } if ($subvalue === null) { //Ignore null values continue; } elseif (is_array($subvalue) || is_object($subvalue)) { //TODO: test this //Recursive call. $subnode = $node->addChild($subkey); toXml($subvalue, $rootNodeName, $subnode, $unknownNodeName); } elseif (is_bool($subvalue)) { $node->addChild($subkey, $subvalue ? 'true' : 'false'); } else { $node->addChild($subkey, htmlentities($subvalue)); } } //die(); //$array = array(); //$node = $xml->addChild($key); //toXml($value, $rootNodeName, $node, $unknownNodeName); } elseif (is_bool($value)) { $xml->addChild($key, $value ? 'true' : 'false'); } else { //Adds single node. if ($value || $value === 0) { $value = htmlentities($value); - $xml->addChild($key,$value); + $xml->addChild($key, $value); } } } // pass back as string. or simple xml object if you want! return $xml->asXML(); } /** * Outputs API reply, printing it in the specified format. * * The format will be read form $_REQUEST['format']. * * @param mixed $reply the reply to format * @param string $xmlRoot the XML root element name (optional, default value is 'data'). * @param string $xmlChildren the XML children elements name (optional, will be deducted from the context if omitted, or, if not possible, will be unknownNode) */ function api_output ($reply, $xmlRoot = null, $xmlChildren = null) { $format = isset($_REQUEST['format']) ? $_REQUEST['format'] : 'preview'; switch ($format) { case 'preview': echo '
';
             print_r($reply);
             echo '
'; break; case 'php': echo serialize($reply); break; case 'wddx': require_once('BeautyXML.class.php'); $bc = new BeautyXML(); echo $bc->format(wddx_serialize_value($reply)); break; case 'json': echo json_encode($reply); break; case 'xml': require_once('BeautyXML.class.php'); $bc = new BeautyXML(); echo ''; echo "\n"; echo $bc->format(toXml($reply, $xmlRoot, null, $xmlChildren)); break; case 'string': echo $reply; break; default: echo "Unknown API format: $_GET[format]"; break; } } diff --git a/includes/config.php b/includes/config.php index a98f5a3..3ce85f9 100755 --- a/includes/config.php +++ b/includes/config.php @@ -1,270 +1,270 @@ * @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 */ //////////////////////////////////////////////////////////////////////////////// /// /// /// I. SQL configuration /// /// /// //////////////////////////////////////////////////////////////////////////////// //SQL configuration $Config['database']['engine'] = 'MySQLi'; //MySQL, MySQLi $Config['database']['host'] = 'localhost'; $Config['database']['username'] = 'zed'; $Config['database']['password'] = 'zed'; $Config['database']['database'] = 'zed'; //SQL tables $prefix = ''; define('TABLE_API_KEYS', $prefix . 'api_keys'); define('TABLE_COMMENTS', $prefix . 'comments'); -define('TABLE_CONTENT_FILES', $prefix . 'content_files'); -define('TABLE_CONTENT_LOCATIONS', $prefix . 'content_locations'); -define('TABLE_CONTENT_ZONES', $prefix . 'content_zones'); +define('TABLE_CONTENT_FILES', $prefix . 'content_files'); +define('TABLE_CONTENT_LOCATIONS', $prefix . 'content_locations'); +define('TABLE_CONTENT_ZONES', $prefix . 'content_zones'); define('TABLE_CONTENT_ZONES_LOCATIONS', $prefix . 'content_zones_locations'); define('TABLE_LOG', $prefix . 'log'); define('TABLE_LOG_SMARTLINE', $prefix . 'log_smartline'); define('TABLE_MESSAGES', $prefix . 'messages'); define('TABLE_MOTD', $prefix . 'motd'); define('TABLE_PAGES', $prefix . 'pages'); define('TABLE_PAGES_EDITS', $prefix . 'pages_edits'); define('TABLE_PERSOS', $prefix . 'persos'); define('TABLE_PERSOS_FLAGS', $prefix . 'persos_flags'); define('TABLE_PERSOS_NOTES', $prefix . 'persos_notes'); define('TABLE_PORTS', $prefix . 'ports'); define('TABLE_PROFILES', $prefix . 'profiles'); define('TABLE_PROFILES_COMMENTS', $prefix . 'profiles_comments'); define('TABLE_PROFILES_PHOTOS', $prefix . 'profiles_photos'); define('TABLE_PROFILES_TAGS', $prefix . 'profiles_tags'); define('TABLE_REGISTRY', $prefix . 'registry'); define('TABLE_REQUESTS', $prefix . 'requests'); define('TABLE_REQUESTS_REPLIES', $prefix . 'requests_replies'); define('TABLE_SESSIONS', $prefix . 'sessions'); define('TABLE_SHIPS', $prefix . 'ships'); define('TABLE_USERS', $prefix . 'users'); define('TABLE_USERS_INVITES', $prefix . 'users_invites'); define('TABLE_USERS_AUTH', $prefix . 'users_auth'); //Geo tables define('TABLE_BODIES', $prefix . 'geo_bodies'); define('TABLE_LOCATIONS', $prefix . 'geo_locations'); //Well... it's a view define('TABLE_PLACES', $prefix . 'geo_places'); //////////////////////////////////////////////////////////////////////////////// /// /// /// II. Site configuration /// /// /// //////////////////////////////////////////////////////////////////////////////// //Default theme $Config['DefaultTheme'] = "Zed"; //Dates date_default_timezone_set("UTC"); //Secret key, used for some verification hashes in URLs or forms. $Config['SecretKey'] = 'Lorem ipsum dolor'; //When reading files, buffer size define('BUFFER_SIZE', 4096); //////////////////////////////////////////////////////////////////////////////// /// /// /// III. Script URLs /// /// /// //////////////////////////////////////////////////////////////////////////////// /* * Apache httpd, without mod_rewrite: * * Subdirectory: * - $Config['SiteURL'] = 'http://zed.dereckson.be/hypership/index.php'; * - $Config['BaseURL'] = '/hypership/index.php'; * * Root directory: * - $Config['SiteURL'] = 'http://zed.dereckson.be/index.php'; * - $Config['BaseURL'] = '/index.php'; * * Apache httpd, with mod_rewrite: * * Subdirectory: * - $Config['SiteURL'] = 'http://zed.dereckson.be/hypership'; * - $Config['BaseURL'] = '/hypership'; * * In .htaccess or your vhost definition: * RewriteEngine On * RewriteBase /hypership/ * RewriteCond %{REQUEST_FILENAME} !-f * RewriteCond %{REQUEST_FILENAME} !-d * RewriteRule . /hypership/index.php [L] * * Root directory: * - $Config['SiteURL'] = 'http://zed.dereckson.be'; * - $Config['BaseURL'] = ''; * * In .htaccess or your vhost definition: * RewriteEngine On * RewriteBase / * RewriteCond %{REQUEST_FILENAME} !-f * RewriteCond %{REQUEST_FILENAME} !-d * RewriteRule . /index.php [L] * * nginx: * * Use same config.php settings than Apache httpd, with mod_rewrite. * * In your server block: * location / { * #Serves static files if they exists, with one month cache * if (-f $request_filename) { * expires 30d; * break; * } * * #Sends all non existing file or directory requests to index.php * if (!-e request_filename) { * rewrite ^(.+)$ /index.php last; * #Or if you use a subdirectory: * #rewrite ^(.+)$ /hypership/index.php last; * } * } * * location ~ \.php$ { * #Your instructions to pass query to your FastCGI process, like: * fastcgi_pass 127.0.0.1:9000; * fastcgi_param SCRIPT_FILENAME /var/www/zed$fastcgi_script_name; * include fastcgi_params; * } * * * If you don't want to specify the server domain, you can use get_server_url: * $Config['SiteURL'] = get_server_url() . '/hypership'; * $Config['SiteURL'] = get_server_url(); * * * * !!! No trailing slash !!! * */ $Config['SiteURL'] = get_server_url(); $Config['BaseURL'] = ''; //AJAX callbacks URL $Config['DoURL'] = $Config['SiteURL'] . "/do.php"; //////////////////////////////////////////////////////////////////////////////// /// /// /// IV. Static content /// /// /// //////////////////////////////////////////////////////////////////////////////// //Where the static content is located? //Static content = 4 directories: js, css, img and content //On default installation, those directories are at site root. //To improve site performance, you can use a CDN for that. // //Recommended setting: $Config['StaticContentURL'] = $Config['SiteURL']; //Or if Zed is the site root: $Config['StaticContentURL'] = ''; //With CoralCDN: $Config['StaticContentURL'] = . '.nyud.net'; // $Config['StaticContentURL'] = ''; //$Config['StaticContentURL'] = get_server_url() . '.nyud.net'; //Scenes define('SCENE_DIR', 'content/scenes'); define('SCENE_URL', $Config['StaticContentURL'] . '/' . SCENE_DIR); //Stories define('STORIES_DIR', "content/stories"); //Profile's photos define('PHOTOS_DIR', 'content/users/_photos'); define('PHOTOS_URL', $Config['StaticContentURL'] . '/' . PHOTOS_DIR); //ImageMagick paths //Be careful on Windows platform convert could match the NTFS convert command. $Config['ImageMagick']['convert'] = 'convert'; $Config['ImageMagick']['mogrify'] = 'mogrify'; $Config['ImageMagick']['composite'] = 'composite'; $Config['ImageMagick']['identify'] = 'identify'; //////////////////////////////////////////////////////////////////////////////// /// /// /// V. Caching /// /// /// //////////////////////////////////////////////////////////////////////////////// /* * Some data (Smarty, OpenID and sessions) are cached in the cache directory. * * Security tip: you can move this cache directory outside the webserver tree. */ define('CACHE_DIR', 'cache'); /* * Furthermore, you can also enable a cache engine, like memcached, to store * data from heavy database queries, or frequently accessed stuff. * * To use memcached: * - $Config['cache']['engine'] = 'memcached'; * - $Config['cache']['server'] = 'localhost'; * - $Config['cache']['port'] = 11211; * * To disable cache: * - $Config['cache']['engine'] = 'void'; * (or don't write nothing at all) */ $Config['cache']['engine'] = 'void'; //////////////////////////////////////////////////////////////////////////////// /// /// /// VI. Sessions and authentication code /// /// /// //////////////////////////////////////////////////////////////////////////////// //If you want to use a common table of sessions / user handling //with several websites, specify a different resource id for each site. $Config['ResourceID'] = 21; //Enable OpenID authentication //$Config['OpenID'] = true; //Enable YubiKey authentication //API 12940 //For YubiCloud API key - create yours at https://upgrade.yubico.com/getapikey/ //$Config['YubiCloud']['ClientID'] = 12345; //$Config['YubiCloud']['SecretKey'] = 'Base64SecretKeyHere'; //PHP variables ini_set('session.serialize_handler', 'wddx'); ini_set('session.save_path', CACHE_DIR . '/sessions'); ini_set('session.gc_maxlifetime', 345600); //4 days, for week-end story pause and continue url //////////////////////////////////////////////////////////////////////////////// /// /// /// VII. Builder /// /// /// //////////////////////////////////////////////////////////////////////////////// //Zed can invoke a slightly modified version of HOTGLUE to build zones. $Config['builder']['hotglue']['enable'] = true; $Config['builder']['hotglue']['URL'] = '/apps/hotglue/index.php'; diff --git a/includes/core.php b/includes/core.php index 1ece7e1..858003f 100755 --- a/includes/core.php +++ b/includes/core.php @@ -1,664 +1,664 @@ * @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 /// /// /// //////////////////////////////////////////////////////////////////////////////// error_reporting(E_ALL & ~E_NOTICE); include_once("config.php"); include_once("error.php"); include_once("db/Database.php"); $db = Database::load(); Database::cleanupConfiguration(); include_once("sessions.php"); include_once("autoload.php"); //////////////////////////////////////////////////////////////////////////////// /// /// /// 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. * * * echo generate_random_string('AAA111'); //this could output SDQ245. * * * @author Pierre Habart * * @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"); + $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= 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 $expression The expression to be printed */ function dprint_r ($expression) { echo '
';
     print_r($expression);
     echo '
'; } //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"); + $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 check * @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 from the specified file */ 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[] = [1, $language]; } else { $userlangs[] = [$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->configLoad("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->configLoad('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 integer 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: * * $url = get_url('ship', $ship); * echo $url; //if $ship contains S00001, this should print /ship/S00001 * * * @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'] == $_SERVER["PHP_SELF"]) { 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) == $_SERVER["PHP_SELF"]) { 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
Current value: $Config[SiteURL]
Expected value: 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 == $_SERVER["PHP_SELF"]) return []; 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 parameter 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/error.php b/includes/error.php index bfdae33..577f5b7 100755 --- a/includes/error.php +++ b/includes/error.php @@ -1,195 +1,195 @@ * @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 delete old_message_die method and write alternative HTML textual output * in the message_die method */ /// /// Error constants /// /** * SQL_ERROR is the constant meaning the error is a SQL error. * * As a message_die function parameter, it allows to add SQL specific debug information. */ -define ("SQL_ERROR", 65); +define ("SQL_ERROR", 65); /** * HACK_ERROR is the constant meaning access is non authorized to the resource. * * It encompasses two problematics: * the URL points to a resource belonging to another user or for the current user have no access right (for malformed URL, pick instead GENERAL_ERROR) ; * the user is anonymous, instead to be logged in. * * A suggested way to handle the second problematic is to store in hidden input * fields or better in the session the previous form data, and to print a login * form. * * If you implement this, you don't even need to distinguishes between the two * cases, as once logged in, the regular HACK_ERROR could also be printed. */ define ("HACK_ERROR", 99); /** * GENERAL_ERROR is the constant meaning the error is general, ie not covered by * another more specific error constant. */ define ("GENERAL_ERROR", 117); /// /// Error helper functions /// /** * Output a general error, with human-readable information about the specified * expression as error message ; terminates the current script. * * @see message_die * * @param mixed $expression the expression to be printed * @param string $title the message title (optional, default will be 'Debug') */ function dieprint_r ($expression, $title = '') { if (!$title) { $title = 'Debug'; //if title is omitted or false/null, default title } message_die(GENERAL_ERROR, '
' . print_r($expression, true) .'
', $title); } /** * Outputs an error message and terminates the current script. * * Error will be output through Smarty one of the following templates : * error_block.tpl if the header have already been printed ; * error.tpl if the error occurred before the header were called and printed. * * If smarty couldn't be loaded, old_message_die method will be called, which * produces a table output. * * @param int $msg_code an integer constant identifying the error (HACK_ERROR, SQL_ERROR, GENERAL_ERROR) * @param string $msg_text the error message text (optional, but recommended) * @param string $msg_title the error message title (optional) * @param int $err_line the line number of the file where the error occurred (optional, suggested value is __LINE__) * @param string $err_line the path of file where the error occurred (optional, suggested value is __FILE__) * @param string $sql the SQL query (optional, used only if msg_code is SQL_ERROR) */ function message_die ($msg_code, $msg_text = '', $msg_title = '', $err_line = '', $err_file = '', $sql = '') { global $smarty, $db; if ($smarty) { $debug_text = $msg_text; if ($err_line && $err_file) $debug_text .= ' — ' . $err_file. ', ' . lang_get('line') . ' ' . $err_line ; switch ($msg_code) { case HACK_ERROR: $smarty->assign('TITLE', lang_get('UnauthorizedAccess')); break; case SQL_ERROR: $smarty->assign('TITLE', lang_get('SQLError')); $sql_error = $db->sql_error(); if ($sql_error['message'] != '') { $debug_text .= '
' . lang_get('Error') . ' n° ' . $sql_error['code'] . lang_get('_t') . ' ' .$sql_error['message']; } $debug_text .= "

Query:

$sql"; break; default: $smarty->assign('WAP', "Message code error.
Expected: HACK_ERROR, SQL_ERROR, GENERAL_ERROR"); //Falls to GENERAL_ERROR case GENERAL_ERROR: if ($msg_title) $smarty->assign('TITLE', $msg_title); else $smarty->assign('TITLE', lang_get('GeneralError')); break; } $smarty->assign('ERROR_TEXT', $debug_text); $template = (defined('HEADER_PRINTED') && HEADER_PRINTED) ? "error_block.tpl" : "error.tpl"; $smarty->display($template); exit; } else { old_message_die($msg_code, $msg_text, $msg_title, $err_line, $err_file, $sql); } } /** * Outputs an error message and terminates the current script. * * This is the message_die method from Espace Win, used on Zed as fallback if Smarty isn't initialized yet. * Former "german style" error HTML markups have been removed. * * @param int $msg_code an integer constant identifying the error (HACK_ERROR, SQL_ERROR, GENERAL_ERROR) * @param string $msg_text the error message text (optional, but recommended) * @param string $msg_title the error message title (optional) * @param int $err_line the line number of the file where the error occurred (optional, suggested value is __LINE__) * @param string $err_line the path of file where the error occurred (optional, suggested value is __FILE__) * @param string $sql the SQL query (optional, used only if msg_code is SQL_ERROR) * * @deprecated since 0.1 */ function old_message_die($msg_code, $msg_text = '', $msg_title = '', $err_line = '', $err_file = '', $sql = '') { global $db, $Utilisateur; $sql_store = $sql; if ($msg_code == HACK_ERROR && $Utilisateur[user_id] < 1000) { die("You must be logged in to access to this resource."); } elseif ($msg_code == HACK_ERROR) { $title = "You aren't allowed to access this resource."; $debug_text = $msg_text; } elseif ($msg_code == SQL_ERROR) { $title = "SQL error"; $sql_error = $db->sql_error(); $debug_text = $msg_text; if ($err_line != '' && $err_file != '') { $debug_text .= ' in ' . $err_file. ', line ' . $err_line ; } if ($sql_error['message'] != '') { $debug_text .= '
Error #' . $sql_error['code'] . ': ' . $sql_error['message']; } if ($sql_store != '') { $debug_text .= "
$sql_store"; } } elseif ($msg_code == GENERAL_ERROR) { $title = $msg_title; $debug_text = $msg_text; if ($err_line && $err_file) { $debug_text .= "
$err_file, line $err_line"; } } echo '

'; echo $title; echo '

'; echo $debug_text; echo '