Page MenuHomeDevCentral

D1920.id4872.diff
No OneTemporary

D1920.id4872.diff

diff --git a/.gitignore b/.gitignore
new file mode 100644
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/vendor/
diff --git a/composer.json b/composer.json
new file mode 100644
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,20 @@
+{
+ "name": "keruald/keruald",
+ "description": "Bricks to build web sites",
+ "type": "library",
+ "require": {
+ "keruald/omnitools": "^0.2.0"
+ },
+ "license": "BSD-2-Clause",
+ "authors": [
+ {
+ "name": "Sébastien Santoro",
+ "email": "dereckson@espace-win.org"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Keruald\\Core\\": "src/",
+ }
+ },
+}
diff --git a/includes/config.php b/includes/config.php
--- a/includes/config.php
+++ b/includes/config.php
@@ -1,5 +1,7 @@
<?php
+use Keruald\OmniTools\HTTP\Requests\Request;
+
/**
* Keruald, core libraries for Pluton and Xen engines.
* (c) 2010, Sébastien Santoro aka Dereckson, some rights reserved
@@ -96,14 +98,14 @@
*
*
* If you don't want to specify the server domain, you can use get_server_url:
- * $Config['SiteURL'] = get_server_url() . '/application';
- * $Config['SiteURL'] = get_server_url();
+ * $Config['SiteURL'] = Request::getServerURL() . '/application';
+ * $Config['SiteURL'] = Request::getServerURL();
*
* !!! No trailing slash !!!
*
*/
-$Config['SiteURL'] = get_server_url();
+$Config['SiteURL'] = Request::getServerURL();
$Config['BaseURL'] = '';
//xmlHttpRequest callbacks URL
diff --git a/includes/core.php b/includes/core.php
--- a/includes/core.php
+++ b/includes/core.php
@@ -10,23 +10,16 @@
* 0.1 2010-02-27 2:04 DcK
*/
+use Keruald\OmniTools\HTTP\Requests\Request;
+
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Configures PHP and loads site-wide used libraries ///
/// ///
////////////////////////////////////////////////////////////////////////////////
-//Disables register globals
-ini_set('register_globals', 'off');
-
-//Reports all errors, help notices (including STRICT in PHP 6)
-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("session.php"); // Sessions handler
////////////////////////////////////////////////////////////////////////////////
/// ///
@@ -40,7 +33,7 @@
* @param string $user_id the user ID
* @return string the username
*/
-function get_username ($user_id) {
+function get_username ($user_id) : string {
global $db;
$user_id = $db->sql_escape($user_id);
@@ -64,136 +57,13 @@
return $db->sql_query_express($sql, "Can't get user id from specified username");
}
-////////////////////////////////////////////////////////////////////////////////
-/// ///
-/// Misc helper functions ///
-/// ///
-////////////////////////////////////////////////////////////////////////////////
-
-// Plural management
-
-/**
- * Gets a "s" if the specified amount requests the plural
- *
- * @param mixed $amount the quantity (should be numeric)
- * @return string 's' if the amount is greater or equal than 2 ; otherwise, ''
- */
-function s ($amount) {
- if ($amount >= 2 || $amount <= -2 ) return 's';
-}
-
-/**
- * Prints human-readable information about a variable, wrapped in a <pre> block
- *
- * @param mixed $mixed the variable to dump
- */
-function dprint_r ($mixed) {
- echo '<pre>';
- print_r($mixed);
- echo '</pre>';
-}
-
-/**
- * Generates a new GUID
- *
- * @return string a guid (without {})
- */
-function new_guid () {
- //The guid chars
- $chars = explode(',', 'a,b,c,d,e,f,0,1,2,3,4,5,6,7,8,9');
-
- //Let's build our 36 characters string
- //e.g. 68ed40c6-f5bb-4a4a-8659-3adf23536b75
- $guid = "";
- for ($i = 0 ; $i < 36 ; $i++) {
- if ($i == 8 || $i == 13 || $i == 18 || $i == 23) {
- //Dashes at position 9, 14, 19 and 24
- $guid .= "-";
- } else {
- //0-f hex digit elsewhere
- $guid .= $chars[mt_rand() % sizeof($characters)];
- }
- }
- return $guid;
-}
-
-/**
- * Determines if the expression is a valid guid (in uuid notation, without {})
- *
- * @param string $expression the guid to check
- * @return true if the expression is a valid guid ; 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 hex 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;
-}
-
////////////////////////////////////////////////////////////////////////////////
/// ///
/// URL helpers functions ///
/// ///
////////////////////////////////////////////////////////////////////////////////
-/**
- * Gets URL
- *
- * @return string URL
- */
-function get_url () {
+function get_url () : string {
global $Config;
if (func_num_args() > 0) {
$pieces = func_get_args();
@@ -205,12 +75,7 @@
}
}
-/**
- * Gets page URL
- *
- * @return string URL
- */
-function get_page_url () {
+function get_page_url () : string {
$url = $_SERVER['SCRIPT_NAME'] . $_SERVER['PATH_INFO'];
if (substr($url, -10) == "/index.php") {
return substr($url, 0, -9);
@@ -218,30 +83,12 @@
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 () {
+function get_current_url () : string {
global $Config;
//Gets relevant URL part from relevant $_SERVER variables
@@ -252,20 +99,21 @@
}
//In other cases, we'll need to get the relevant part of the URL
- $current_url = get_server_url() . $_SERVER['REQUEST_URI'];
+ $server_url = Request::getServerURL();
+ $current_url = $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");
+ 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 $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);
+ return substr($server_url. $_SERVER["REDIRECT_URL"], $len);
}
//Last possibility: use REQUEST_URI, but remove QUERY_STRING
@@ -273,7 +121,7 @@
//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);
+ $url = substr($server_url . $_SERVER["REQUEST_URI"], $len);
//But if there are a query string (?action=... we need to discard it)
if ($_SERVER['QUERY_STRING']) {
@@ -285,13 +133,11 @@
/**
* Gets an array of url fragments to be processed by controller
- *
- * @return array an array containing URL fragments
*/
-function get_current_url_fragments () {
+function get_current_url_fragments () : array {
$url_source = get_current_url();
if ($url_source == '/index.php') {
- return array();
+ return [];
}
return explode('/', substr($url_source, 1));
diff --git a/includes/error.php b/includes/error.php
--- a/includes/error.php
+++ b/includes/error.php
@@ -34,25 +34,14 @@
* consider Advanced PHP debugger: www.php.net/manual/en/book.apd.php
*/
+use Keruald\OmniTools\Debug\Debugger;
+
//Error code constants
define ("SQL_ERROR", 65);
define ("HACK_ERROR", 99);
define ("GENERAL_ERROR", 117);
-/**
- * Prints human-readable information about a variable
- * wrapped in a general error and dies
- *
- * @param mixed $mixed the variable to dump
- */
-function dieprint_r ($var, $title = '') {
- if (!$title) {
- $title = 'Debug';
- }
-
- //GENERAL_ERROR with print_r call as message
- message_die(GENERAL_ERROR, '<pre>' . print_r($var, true) .'</pre>', $title);
-}
+Debugger::register();
/**
* Prints an error message and dies
diff --git a/includes/login.php b/includes/login.php
deleted file mode 100644
--- a/includes/login.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-
-/**
- * Keruald, core libraries for Pluton and Xen engines.
- * (c) 2010, Sébastien Santoro aka Dereckson, some rights reserved
- * Released under BSD license
- *
- * Login and logout handler.
- *
- * 0.1 2010-02-27 1:52 DcK
- *
- */
-
-if ($_POST['LogIn']) {
- // User have submitted login form
- $username = $db->sql_escape($_POST['username']);
- $sql = "SELECT user_password, user_id FROM " . TABLE_USERS . " WHERE username = '$username'";
- if ( !($result = $db->sql_query($sql)) ) {
- message_die(SQL_ERROR, "Can't get user information", '', __LINE__, __FILE__, $sql);
- }
- if ($row = $db->sql_fetchrow($result)) {
- if (!$row['user_password']) {
- // No password set
- $LoginError = "This account exists but haven't a password defined. Contact the site administrator.";
- } elseif ($row['user_password'] != md5($_POST['password'])) {
- // The password doesn't match
- $LoginError = "Incorrect password.";
- } else {
- // Login successful
- Session::load()->user_login($row['user_id']);
- $LoginSuccessful = true;
- }
- }
-} elseif ($_POST['LogOut'] || $_GET['action'] == "user.logout") {
- // User have submitted logout form or clicked a logout link
- Session::load()->user_logout();
-}
diff --git a/includes/mysql.php b/includes/mysql.php
deleted file mode 100644
--- a/includes/mysql.php
+++ /dev/null
@@ -1,157 +0,0 @@
-<?php
-
-/*
- * Keruald, core libraries for Pluton and Xen engines.
- * (c) 2010, Sébastien Santoro aka Dereckson, some rights reserved
- * Released under BSD license
- *
- * MySQL layer and helper class
- *
- * 0.1 2010-02-27 1:52 DcK
- *
- */
-
-if (!defined('SQL_LAYER')) {
- define('SQL_LAYER', 'MySQL');
-
- /**
- * SQL layer and helper class: MySQL
- *
- * @package Keruald
- * @subpackage Keruald
- * @copyright Copyright (c) 2010, Sébastien Santoro aka Dereckson
- * @license Released under BSD license
- * @version 0.1
- */
- class sql_db {
- /**
- * @var int the connection identifier
- */
- private $id;
-
- /**
- * Initializes a new instance of the database abstraction class, for MySQL engine
- */
- function __construct($host = 'localhost', $username = '', $password = '', $database = '') {
- //Connects to MySQL server
- $this->id = @mysql_connect($host, $username, $password) or $this->sql_die();
-
- //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
- */
- private 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.");
- }
-
- /**
- * Sends a unique query to the database
- *
- * @return mixed if the query is successful, a result identifier ; otherwise, false
- */
- function sql_query ($query) {
- return mysql_query($query, $this->id);
- }
-
- /**
- * Fetches a row of result into an associative array
- *
- * @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 === '' || $query === false || $query === null) {
- //No query, no value
- return '';
- } elseif (!$result = $this->sql_query($query)) {
- //An error have occured
- message_die(SQL_ERROR, $error_message, '', '', '', $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
- * @return string The escaped expression
- */
- function sql_escape ($expression) {
- return mysql_real_escape_string($expression);
- }
-
- /**
- * Sets charset
- */
- function set_charset ($encoding) {
- if (function_exists('mysql_set_charset')) {
- //>PHP 5.2.3
- mysql_set_charset($encoding, $this->id);
- } else {
- //TODO: set connection variables to utf8
- }
- }
- }
-
- // Creates an instance of this database class with configuration values
- $db = new sql_db($Config['sql']['host'], $Config['sql']['username'], $Config['sql']['password'], $Config['sql']['database']);
-
- // To improve security, we unset sql parameters
- unset($Config['sql']);
-
- // Sets SQL connexion in UTF8. PHP 5.2.3+
- $db->set_charset('utf8');
-}
diff --git a/index.php b/index.php
--- a/index.php
+++ b/index.php
@@ -1,9 +1,9 @@
<?php
-/*
+/**
* Keruald, core libraries for Pluton and Xen engines.
-* (c) 2010, Sébastien Santoro aka Dereckson, some rights reserved
-* Released under BSD license
+ * (c) 2010, Sébastien Santoro aka Dereckson, some rights reserved
+ * Released under BSD license
*
* Application entry point
*
@@ -14,30 +14,36 @@
*
*/
+use Keruald\Core\Database\Database;
+use Keruald\Core\Login;
+use Keruald\Core\Session;
+
////////////////////////////////////////////////////////////////////////////////
///
/// Initialization
///
-//Keruald libraries
+// Keruald libraries
include('includes/core.php');
+$db = Database::load($Config['sql']);
+
////////////////////////////////////////////////////////////////////////////////
///
/// Session
///
-//[TODO] If your session contains classes, and you don't implement __autoload,
-//you've to require those items before session_start();
-//You can implement this here or in _includes/sessions.php
+// [TODO] If your session contains classes, and you don't implement __autoload,
+// you've to require those items before session_start();
+// You can implement this here or in _includes/sessions.php
-//Starts a new session or recovers current session
+// Starts a new session or recovers current session
$Session = Session::load();
-//Handles login or logout
-include("includes/login.php");
+// Handles login or logout
+$LoginManager = Login::handle();
-//Gets current user information
+// Gets current user information
$CurrentUser = $Session->get_logged_user();
////////////////////////////////////////////////////////////////////////////////
@@ -45,20 +51,20 @@
/// Your application initialization logic
///
-//[TODO] Loads your template engine or prepares the document to print
-//[TODO] Loads languages file if you're into L10n
+// [TODO] Loads your template engine or prepares the document to print
+// [TODO] Loads languages file if you're into L10n
////////////////////////////////////////////////////////////////////////////////
///
/// Serves the requested page
///
-//[TODO] Understand the URL if not done yet and calls relevant script
-//[TODO] As a MVC sample, here a Xen-like approach.
+// [TODO] Understand the URL if not done yet and calls relevant script
+// [TODO] As a MVC sample, here a Xen-like approach.
// For a content-or iented, see the Pluton index.php
//
-//Tip: to understand the url, get_current_url_fragments will output an array:
-//www.yourdomain.tld/planet/mars/sat?name=demios -> {'planet', 'mars', 'sat'}
+// Tip: to understand the url, get_current_url_fragments will output an array:
+// www.yourdomain.tld/planet/mars/sat?name=demios -> {'planet', 'mars', 'sat'}
/*
$url = get_current_url_fragments();
@@ -67,18 +73,16 @@
//Calls homepage controller
include("controllers/home.php");
break;
-
+
case 'planet':
case 'user':
case 'anotherstuff':
//Calls requested controller
include("controllers/$controller.php");
break;
-
+
default:
header("HTTP/1.0 404 Not Found");
dieprint_r($url, 'Unknown URL');
}
*/
-
-?>
diff --git a/src/Database/Database.php b/src/Database/Database.php
new file mode 100644
--- /dev/null
+++ b/src/Database/Database.php
@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * Database calling class.
+ *
+ * Zed. The immensity of stars. The HyperShip. The people.
+ *
+ * (c) 2015, Dereckson, some rights reserved.
+ * Released under BSD license.
+ *
+ * This file provides a calling class, which read the configuration, ensures
+ * the database class for the db engine given in config exists and initializes
+ * it.
+ *
+ * The class to call is determined from the following preference:
+ * <code>
+ * $Config['database']['engine'] = 'MySQL'; //will use DatabaseMySQL class.
+ * </code>
+ *
+ * @package Zed
+ * @subpackage Database
+ * @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
+ * @copyright 2015 Sébastien Santoro aka Dereckson
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD
+ * @link http://scherzo.dereckson.be/doc/zed
+ * @link http://zed.dereckson.be/
+ * @filesource
+ */
+
+namespace Keruald\Core\Database;
+
+use Exception;
+
+/**
+ * Databasecaller
+ */
+class Database {
+ /**
+ * Gets the database instance, initializing it if needed
+ *
+ * The correct database instance to initialize will be determined from the
+ * $Config['database']['product'] preference.
+ *
+ * The database class to use will be Database + (preference engine, capitalized)
+ *
+ * This method will creates an instance of the specified object,
+ * calling the load static method from this object class.
+ *
+ * Example:
+ *
+ * <code>
+ * $Config['database']['engine'] = 'quux';
+ * $db = Database::load($Config['database']);
+ * </code>
+ *
+ * Database:load() will call DatabaseQuux:load();
+ *
+ * @return Database the database instance
+ */
+ static function load ($config) {
+ if (!isset($config['product'])) {
+ throw new Exception("A database engine (a MySQL variant is recommended) should be configured. Please ensure you have a database block with an [\"engine\"] value in the configuration.");
+ }
+
+ $engine_class = self::getProductClass($config['product']);
+
+ return call_user_func([$engine_class, 'load'], $config);
+ }
+
+ static private function getProductClass (string $product) : string {
+ return 'Database' . $product;
+ }
+}
diff --git a/src/Database/DatabaseMySQLi.php b/src/Database/DatabaseMySQLi.php
new file mode 100644
--- /dev/null
+++ b/src/Database/DatabaseMySQLi.php
@@ -0,0 +1,168 @@
+<?php
+
+/**
+ * MySQLi layer and helper class
+ *
+ * Zed. The immensity of stars. The HyperShip. The people.
+ *
+ * (c) 2010, 2014, Dereckson, some rights reserved.
+ * Released under BSD license.
+ *
+ * @package Zed
+ * @subpackage Keruald
+ * @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
+ * @copyright 2014 Sébastien Santoro aka Dereckson
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD
+ * @link http://scherzo.dereckson.be/doc/zed
+ * @link http://zed.dereckson.be/
+ * @filesource
+ */
+
+namespace Keruald\Core\Database;
+
+use mysqli;
+use mysqli_result;
+
+/**
+ * SQL layer and helper class: MySQLi
+ *
+ * @package Keruald
+ * @subpackage Keruald
+ * @copyright Copyright (c) 2010, Sébastien Santoro aka Dereckson
+ * @license Released under BSD license
+ * @version 0.1
+ */
+class DatabaseMySQLi {
+ /**
+ * @var int the connection identifier
+ */
+ private $db;
+
+ /**
+ * Initializes a new instance of the database abstraction class, for MySQLi engine
+ */
+ function __construct($host = 'localhost', $username = '', $password = '', $database = '') {
+ //Checks extension requirement
+ if (!class_exists("mysqli")) {
+ message_die(GENERAL_ERROR, "You've chosen to use a MySQLi database engine, but the MySQLi extension is missing.", "Setup issue");
+ }
+
+ //Connects to MySQL server
+ $this->db = new mysqli($host, $username, $password) or $this->sql_die();
+
+ //Selects database
+ if ($database != '') {
+ $this->db->select_db($database);
+ }
+ }
+
+ /**
+ * Outputs a can't connect to the SQL server message and exits.
+ * It's called on connect failure
+ */
+ private function sql_die () : void {
+ //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.");
+ }
+
+ /**
+ * Sends a unique query to the database
+ *
+ * @return mixed if the query is successful, a mysqli_result instance ; otherwise, false
+ */
+ function sql_query (string $query) {
+ return $this->db->query($query);
+ }
+
+ /**
+ * Fetches a row of result into an associative array
+ *
+ * @return mixed an array of strings that corresponds to the fetched row or null if there
+ * are no more rows in resultset.
+ */
+ function sql_fetchrow (mysqli_result $result) {
+ return $result->fetch_array();
+ }
+
+ /**
+ * Gets last SQL error information
+ *
+ * @return array an array with two keys, error code (int) and message (string)
+ */
+ function sql_error () : array {
+ return [
+ 'code' => $this->db->errno,
+ 'message' => $this->db->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 (mysqli_result $result) : int {
+ return $result->num_rows;
+ }
+
+ /**
+ * Gets the primary key value of the last query (works only in INSERT context)
+ *
+ * @return mixed the primary key value
+ */
+ function sql_nextid () {
+ return $this->db->insert_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 = '', string $error_message = "Impossible d'exécuter cette requête.", bool $return_as_string = true) {
+ if ($query === '' || $query === false || $query === null) {
+ //No query, no value
+ return '';
+ } elseif (!$result = $this->sql_query($query)) {
+ //An error have occurred
+ message_die(SQL_ERROR, $error_message, '', '', '', $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;
+ }
+ }
+
+ function sql_escape (string $expression) : string {
+ return $this->db->real_escape_string($expression);
+ }
+
+
+ function set_charset ($encoding) : bool {
+ return $this->db->set_charset($encoding);
+ }
+
+ /**
+ * Loads a database instance, connected and ready to process queries.
+ */
+ static function load (array $config) : DatabaseMySQLi {
+ //Creates an instance of this database class with configuration values
+ $db = new self(
+ $config['host'],
+ $config['username'],
+ $config['password'],
+ $config['database']
+ );
+
+ //Sets SQL connexion in UTF-8.
+ $db->set_charset('utf8');
+
+ return $db;
+ }
+}
diff --git a/src/Login.php b/src/Login.php
new file mode 100644
--- /dev/null
+++ b/src/Login.php
@@ -0,0 +1,118 @@
+<?php
+
+/**
+ * Keruald, core libraries for Pluton and Xen engines.
+ * (c) 2010, Sébastien Santoro aka Dereckson, some rights reserved
+ * Released under BSD license
+ *
+ * Login and logout handler.
+ *
+ * 0.1 2010-02-27 1:52 DcK
+ *
+ */
+
+namespace Keruald\Core;
+
+use Keruald\Core\Objects\User;
+
+class Login {
+
+ /**
+ * @var string
+ */
+ private $loginError = '';
+
+ /**
+ * @var string Generic error message if login isn't found or if password
+ * doesn't match. The goal is to avoid to guess which one.
+ */
+ private $defaultErrorMessage = 'Username or password not found.';
+
+ /**
+ * @var bool
+ */
+ private $loginSucessful = false;
+
+ public static function handle () {
+ if (self::isLoginRequest()) {
+ self::login();
+ } elseif (self::isLogoutRequest()) {
+ self::logout();
+ }
+ }
+
+ public static function isLoginRequest () : bool {
+ return !empty($_POST['LogIn']);
+ }
+
+ public static function isLogoutRequest () : bool {
+ if (!empty($_POST['LogIn'])) {
+ // Logout form/button
+ return true;
+ }
+
+ // Logout link
+ return isset($_GET['action']) && $_GET['action'] == "user.logout";
+ }
+
+ public static function login () : void {
+ $username = $db->sql_escape($_POST['username']);
+
+ $sql = "SELECT user_password, user_id FROM " . TABLE_USERS . " WHERE username = '$username'";
+ if ( !($result = $db->sql_query($sql)) ) {
+ message_die(SQL_ERROR, "Can't get user information", '', __LINE__, __FILE__, $sql);
+ }
+
+ if (!$row = $db->sql_fetchrow($result)) {
+ $this->setLoginErrorToDefaultMessage();
+ return;
+ }
+
+ if (!$row['user_password']) {
+ // No password set
+ $this->loginError =
+ "This account exists but the password is undefined. Contact the site administrator.";
+
+ return;
+ }
+
+ $user = new User();
+ $user->load_from_row($row);
+
+ if (!$user->checkPassword($_POST['password'], $row['user_password'])) {
+ $this->setLoginErrorToDefaultMessage();
+ return;
+ }
+
+ $this->loginSucessful = true;
+ Session::load()->user_login($user->id);
+ }
+
+ public static function logout () : void {
+ Session::load()->user_logout();
+ }
+
+ public function getLoginError () : string {
+ return $this->loginError;
+ }
+
+ public function getDefaultErrorMessage () : string {
+ return $this->defaultErrorMessage;
+ }
+
+ public function setDefaultErrorMessage (string $defaultErrorMessage) : void {
+ $this->defaultErrorMessage = $defaultErrorMessage;
+ }
+
+ public function setLoginErrorToDefaultMessage () : void {
+ $this->loginError = $this->defaultErrorMessage;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isLoginSucessful () : bool {
+ return $this->loginSucessful;
+ }
+}
+
diff --git a/includes/objects/README b/src/Objects/README
rename from includes/objects/README
rename to src/Objects/README
diff --git a/includes/objects/user.php b/src/Objects/User.php
rename from includes/objects/user.php
rename to src/Objects/User.php
--- a/includes/objects/user.php
+++ b/src/Objects/User.php
@@ -1,5 +1,7 @@
<?php
+namespace Keruald\Core\Objects;
+
/**
* Keruald, core libraries for Pluton and Xen engines.
* (c) 2010, Sébastien Santoro aka Dereckson, some rights reserved
@@ -18,6 +20,10 @@
*/
class User {
+ // use WithLegacyAuthentication; // MD5 for 200x sites
+ use WithMigrationAuthentication; // v
+ // use WithAuthentication; // Modern hashes
+
public $id;
public $name;
public $password;
@@ -40,7 +46,7 @@
/**
* Loads the object User (ie fill the properties) from the $_POST array
*/
- function load_from_form () {
+ function load_from_form () : void {
if (array_key_exists('name', $_POST)) $this->name = $_POST['name'];
if (array_key_exists('password', $_POST)) $this->password = $_POST['password'];
if (array_key_exists('active', $_POST)) $this->active = $_POST['active'];
@@ -52,7 +58,7 @@
/**
* Loads the object User (ie fill the properties) from the database
*/
- function load_from_database () {
+ function load_from_database () : bool {
global $db;
$sql = "SELECT * FROM " . TABLE_USERS . " WHERE user_id = '" . $this->id . "'";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Unable to query users", '', __LINE__, __FILE__, $sql);
@@ -69,7 +75,7 @@
/**
* Loads the object User (ie fill the properties) from the database row
*/
- function load_from_row ($row) {
+ function load_from_row (array $row) : void {
$this->id = $row['user_id'];
$this->name = $row['username'];
$this->password = $row['user_password'];
@@ -81,7 +87,7 @@
/**
* Saves to database
*/
- function save_to_database () {
+ function save_to_database () : void {
global $db;
$id = $this->id ? "'" . $db->sql_escape($this->id) . "'" : 'NULL';
@@ -106,7 +112,7 @@
/**
* Updates the specified field in the database record
*/
- function save_field ($field) {
+ function save_field (string $field) : void {
global $db;
if (!$this->id) {
message_die(GENERAL_ERROR, "You're trying to update a record not yet saved in the database");
@@ -122,7 +128,7 @@
/**
* Generates a unique user id
*/
- function generate_id () {
+ function generate_id () : int {
global $db;
do {
@@ -132,15 +138,15 @@
message_die(SQL_ERROR, "Can't check if a user id is free", '', __LINE__, __FILE__, $sql);
}
$row = $db->sql_fetchrow($result);
- } while ($row[0]);
+ } while ((int)$row[0]);
}
/**
* Fills password field with encrypted version
* of the specified clear password
*/
- public function set_password ($newpassword) {
- $this->password = md5($newpassword);
+ public function set_password ($newPassword) {
+ $this->password = $this->computePasswordHash($newPassword);
}
/**
@@ -149,7 +155,7 @@
* @param string $login the login to check
* @return boolean true if the login is avaiable ; otherwise, false.
*/
- public static function is_available_login ($login) {
+ public static function is_available_login (string $login) : bool {
global $db;
$sql = "SELECT COUNT(*) FROM " . TABLE_USERS . " WHERE username = '$login'";
if (!$result = $db->sql_query($sql)) {
@@ -164,7 +170,7 @@
*
* @return User the new user instance
*/
- public static function create () {
+ public static function create () : User {
$user = new User();
$user->generate_id();
$user->active = true;
@@ -176,7 +182,7 @@
*
* @return User the user matching the specified e-mail ; null, if the mail were not found.
*/
- public static function get_user_from_email ($mail) {
+ public static function get_user_from_email (string $mail) : ?User {
global $db;
$sql = "SELECT username FROM " . TABLE_USERS . " WHERE user_email = '$mail'";
if (!$result = $db->sql_query($sql)) {
diff --git a/src/Objects/WithAuthentication.php b/src/Objects/WithAuthentication.php
new file mode 100644
--- /dev/null
+++ b/src/Objects/WithAuthentication.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace Keruald\Core\Objects;
+
+trait WithAuthentication {
+
+ public function check_password (string $passwordToCheck, string $hash) : bool {
+ return password_verify($passwordToCheck, $hash);
+ }
+
+ public function compute_password_hash (string $password) : string {
+ return password_hash($password, PASSWORD_ARGON2I)
+ }
+
+}
diff --git a/src/Objects/WithLegacyAuthentication.php b/src/Objects/WithLegacyAuthentication.php
new file mode 100644
--- /dev/null
+++ b/src/Objects/WithLegacyAuthentication.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace Keruald\Core\Objects;
+
+trait WithLegacyAuthentication {
+
+ /**
+ * @deprecated Migrate through the WithMigrationAuthentication trait to modern hashes
+ */
+ public function check_password (string $passwordToCheck, string $hash) : bool {
+ return md5($passwordToCheck) === $hash;
+ }
+
+ /**
+ * @deprecated Migrate through the WithMigrationAuthentication trait to modern hashes
+ */
+ public function compute_password_hash (string $password) : string {
+ return md5($password);
+ }
+
+}
diff --git a/src/Objects/WithMigrationAuthentication.php b/src/Objects/WithMigrationAuthentication.php
new file mode 100644
--- /dev/null
+++ b/src/Objects/WithMigrationAuthentication.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Keruald\Core\Objects;
+
+trait WithMigrationAuthentication {
+
+ public function checkPassword (string $passwordToCheck, string $hash) : bool {
+ if (self::isLegacyPassword($hash)) {
+ return $this->validateAndMigratePassword($passwordToCheck, $hash);
+ }
+
+ return password_verify($passwordToCheck, $hash);
+ }
+
+ public function computePasswordHash (string $password) : string {
+ return password_hash($password, PASSWORD_ARGON2I)
+ }
+
+ public static function isLegacyPassword (string $hash) : bool {
+ return len($hash) > 0 && $hash[0] !== '$';
+ }
+
+ private function validateAndMigratePassword (string $password, string $hash) : bool {
+ if (md5($passwordToCheck) !== $hash) {
+ return false;
+ }
+
+ $this->migratePassword($password);
+
+ return true;
+ }
+
+ private function migratePassword (string $password) : void {
+ $this->set_password($password);
+ $this->save_field("user_password");
+ }
+
+}
diff --git a/includes/session.php b/src/Session.php
rename from includes/session.php
rename to src/Session.php
--- a/includes/session.php
+++ b/src/Session.php
@@ -1,5 +1,9 @@
<?php
+namespace Keruald\Core;
+
+use Keruald\Core\Objects\User;
+
/**
* Keruald, core libraries for Pluton and Xen engines.
* (c) 2010, Sébastien Santoro aka Dereckson, some rights reserved
@@ -29,7 +33,7 @@
*
* @return Session current session instance
*/
- public static function load () {
+ public static function load () : self {
if (!isset(self::$instance)) {
//Creates new session instance
$c = __CLASS__;
@@ -70,7 +74,7 @@
*
* @return string IP
*/
- public static function get_ip () {
+ public static function get_ip () : string {
//mod_proxy + mod_rewrite (old pluton url scheme) will define 127.0.0.1
//in REMOTE_ADDR, and will store ip in HTTP_X_FORWARDED_FOR variable.
//Some ISP/orgz proxies also use this setting.
@@ -87,13 +91,13 @@
* i. deletes expired session
* ii. sets offline relevant sessions
*/
- public static function clean_old_sessions () {
+ public static function clean_old_sessions () : void {
global $db, $Config;
//Gets session and online status lifetime (in seconds)
//If not specified in config, sets default 5 and 120 minutes values
- $onlineDuration = array_key_exists('OnlineDuration', $Config) ? $Config['OnlineDuration'] : 300;
- $sessionDuration = array_key_exists('SessionDuration', $Config) ? $Config['SessionDuration'] : 7200;
+ $onlineDuration = $Config['OnlineDuration'] ?: 300;
+ $sessionDuration = $Config['SessionDuration'] ?: 7200;
$resource = array_key_exists('ResourceID', $Config) ? '\'' . $db->sql_escape($Config['ResourceID']) . '\'' : 'default';
@@ -114,7 +118,7 @@
/*
* Updates or creates a session in the database
*/
- public function update () {
+ public function update () : void {
global $db, $Config;
//Cleans up session
@@ -138,7 +142,7 @@
* Gets the number of online users
* @return int the online users count
*/
- public function count_online () {
+ public function count_online () : int {
//Keeps result for later method call
static $count = -1;
@@ -161,7 +165,7 @@
* @param string $info the field to get
* @return string the session specified field's value
*/
- public function get_info ($info) {
+ public function get_info (string $info) : string {
global $db;
$id = $db->sql_escape($this->id);
@@ -175,7 +179,7 @@
* @param string $info the field to update
* @param string $value the value to set
*/
- public function set_info ($info, $value) {
+ public function set_info (string $info, string $value) : void {
global $db;
$value = ($value === null) ? 'NULL' : "'" . $db->sql_escape($value) . "'";
@@ -190,7 +194,7 @@
* Gets logged user information
* @return User the logged user information
*/
- public function get_logged_user () {
+ public function get_logged_user () : User {
global $db;
//Gets session information
@@ -202,7 +206,6 @@
$row = $db->sql_fetchrow($result);
//Gets user instance
- require_once('includes/objects/user.php');
$user = new User($row['user_id']);
//Adds session property to this user instance
@@ -216,7 +219,7 @@
* Cleans session
* This method is to be called when an event implies a session destroy
*/
- public function clean () {
+ public function clean () : void {
//Destroies $_SESSION array values, help ID
foreach ($_SESSION as $key => $value) {
if ($key != 'ID') {
@@ -229,7 +232,7 @@
* Updates the session in an user login context
* @param string $user_id the user ID
*/
- public function user_login ($user_id) {
+ public function user_login (string $user_id) : void {
global $db;
//Sets specified user ID in sessions table
@@ -244,7 +247,7 @@
/**
* Updates the session in an user logout context
*/
- public function user_logout () {
+ public function user_logout () : void {
global $db;
//Sets anonymous user in sessions table

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 23, 13:10 (18 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2257479
Default Alt Text
D1920.id4872.diff (42 KB)

Event Timeline