From 38bd8ab8c9eb362eeeb94be8cfe82cf0b3c654a3 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Fri, 24 Feb 2017 19:18:28 -0600 Subject: [PATCH] Progress: continuing development, database work, use c_base_return on more classes, and fix inconsistencies Further work on building the database structure. Added some missing roles: - Requester - Editor A number of inconsistencies have been identified and resolved. After reviewing my use of c_base_cookie as extending the class c_base_return, I have decided that to do that everywhere possible. This simplifies the return structure that I complicated when I decided to use the c_base_return return type development design. I noticed that there is still some cookie functionality that I could implement. This adds support for 'same site' and 'host only'. These are functionally equivalent except that I think 'same site' is a little more granular. This also adds one of my test scripts under examples. It is very likely not completely up to date with the database changes. Many other changes. --- common/base/classes/base_access.php | 146 ++- common/base/classes/base_cookie.php | 215 ++-- common/base/classes/base_database.php | 242 +++-- common/base/classes/base_debug.php | 27 +- common/base/classes/base_email.php | 25 +- common/base/classes/base_error.php | 24 +- .../base/classes/base_error_messages_english.php | 2 +- common/base/classes/base_form.php | 205 ++++ common/base/classes/base_html.php | 113 +- common/base/classes/base_http.php | 197 ++-- common/base/classes/base_ldap.php | 29 +- common/base/classes/base_log.php | 33 +- common/base/classes/base_markup.php | 103 +- common/base/classes/base_rfc_char.php | 24 +- common/base/classes/base_rfc_string.php | 21 + common/base/classes/base_session.php | 536 +++++++--- common/theme/classes/theme_dom.php | 2 +- common/theme/classes/theme_html.php | 43 +- database/sql/reservation/base-associations.sql | 28 +- database/sql/reservation/base-fields.sql | 2 +- database/sql/reservation/base-first.sql | 10 + database/sql/reservation/base-groups.sql | 76 +- database/sql/reservation/base-log_groups.sql | 44 +- database/sql/reservation/base-log_problems.sql | 10 +- database/sql/reservation/base-log_types.sql | 12 +- database/sql/reservation/base-log_users.sql | 20 +- database/sql/reservation/base-main.sql | 10 +- database/sql/reservation/base-paths.sql | 111 +- database/sql/reservation/base-requests.sql | 66 +- database/sql/reservation/base-statistics.sql | 2 +- database/sql/reservation/base-users.sql | 9 +- documentation/access_roles.txt | 9 + examples/test.php | 1122 ++++++++++++++++++++ program/reservation/index.php | 131 ++- program/reservation/reservation_database.php | 127 ++- program/reservation/reservation_paths.php | 289 +++-- program/reservation/reservation_session.php | 141 ++- 37 files changed, 3324 insertions(+), 882 deletions(-) create mode 100644 common/base/classes/base_form.php create mode 100755 examples/test.php diff --git a/common/base/classes/base_access.php b/common/base/classes/base_access.php index 162d190..5812b23 100644 --- a/common/base/classes/base_access.php +++ b/common/base/classes/base_access.php @@ -28,22 +28,28 @@ require_once('common/base/classes/base_ldap.php'); * - Drafter: account is for making templates, drafts, ideas, etc.. (this is a lesser form of "editer"). * - Editer: account is for editors who add/manage/create content. * - Reviewer: account is for users who review something (such as a user who approves content for publishing). + * - Insurer: account is for users who deal with insurance related information. + * - Financer: account is for users who deal with financial related information. * - Publisher: account is for users who perform publishing (marking content available and complete). + * - Auditor: account is for users who perform auditing. This account has read access to almost all data on the system. * - Manager: account is for users who manager the entire system. This is a non-technical administration account. * - Administer: account is for users who have full administrative access to the system. This is a technical administration account and supercedes Manager. */ -class c_base_roles { +class c_base_roles extends c_base_return { const NONE = 0; const PUBLIC = 1; const SYSTEM = 2; const USER = 3; const REQUESTER = 4; const DRAFTER = 5; - const EDITER = 6; + const EDITOR = 6; const REVIEWER = 7; - const PUBLISHER = 8; - const MANAGER = 9; - const ADMINISTER = 10; + const INSURER = 8; + const FINANCER = 9; + const PUBLISHER = 10; + const AUDITOR = 11; + const MANAGER = 12; + const ADMINISTER = 13; private $public; private $system; @@ -52,7 +58,10 @@ class c_base_roles { private $drafter; private $editer; private $reviewer; + private $insurer; + private $financer; private $publisher; + private $auditor; private $manager; private $administer; @@ -60,6 +69,8 @@ class c_base_roles { * Class constructor. */ public function __construct() { + parent::__construct(); + $this->public = TRUE; $this->system = FALSE; $this->user = FALSE; @@ -67,7 +78,10 @@ class c_base_roles { $this->drafter = FALSE; $this->editer = FALSE; $this->reviewer = FALSE; + $this->financer = FALSE; + $this->insurer = FALSE; $this->publisher = FALSE; + $this->auditor = FALSE; $this->manager = FALSE; $this->administer = FALSE; } @@ -83,9 +97,35 @@ class c_base_roles { unset($this->drafter); unset($this->editer); unset($this->reviewer); + unset($this->financer); + unset($this->insurer); unset($this->publisher); + unset($this->auditor); unset($this->manager); unset($this->administer); + + parent::__destruct(); + } + + /** + * @see: t_base_return_value::p_s_new() + */ + public static function s_new($value) { + return self::p_s_new($value, __CLASS__); + } + + /** + * @see: t_base_return_value::p_s_value() + */ + public static function s_value($return) { + return self::p_s_value($return, __CLASS__); + } + + /** + * @see: t_base_return_value_exact::p_s_value_exact() + */ + public static function s_value_exact($return) { + return self::p_s_value_exact($return, __CLASS__, array()); } /** @@ -124,6 +164,7 @@ class c_base_roles { $this->editer = FALSE; $this->reviewer = FALSE; $this->publisher = FALSE; + $this->auditor = FALSE; $this->manager = FALSE; $this->administer = FALSE; } @@ -143,15 +184,24 @@ class c_base_roles { elseif ($role === self::DRAFTER) { $this->drafter = $value; } - elseif ($role === self::EDITER) { + elseif ($role === self::EDITOR) { $this->editer = $value; } elseif ($role === self::REVIEWER) { $this->reviewer = $value; } + elseif ($role === self::FINANCER) { + $this->financer = $value; + } + elseif ($role === self::INSURER) { + $this->insurer = $value; + } elseif ($role === self::PUBLISHER) { $this->publisher = $value; } + elseif ($role === self::AUDITOR) { + $this->auditor = $value; + } elseif ($role === self::MANAGER) { $this->manager = $value; } @@ -185,7 +235,7 @@ class c_base_roles { } if ($role === self::NONE) { - if (!($this->public || $this->system || $this->user || $this->requester || $this->drafter || $this->editer || $this->reviewer || $this->publisher || $this->manager || $this->administer)) { + if (!($this->public || $this->system || $this->user || $this->requester || $this->drafter || $this->editer || $this->reviewer || $this->publisher || $this->auditor || $this->manager || $this->administer)) { return new c_base_return_true(); } } @@ -214,7 +264,7 @@ class c_base_roles { return new c_base_return_true(); } } - elseif ($role === self::EDITER) { + elseif ($role === self::EDITOR) { if ($this->editer) { return new c_base_return_true(); } @@ -224,11 +274,26 @@ class c_base_roles { return new c_base_return_true(); } } + elseif ($role === self::FINANCER) { + if ($this->financer) { + return new c_base_return_true(); + } + } + elseif ($role === self::INSURER) { + if ($this->insurer) { + return new c_base_return_true(); + } + } elseif ($role === self::PUBLISHER) { if ($this->publisher) { return new c_base_return_true(); } } + elseif ($role === self::AUDITOR) { + if ($this->auditor) { + return new c_base_return_true(); + } + } elseif ($role === self::MANAGER) { if ($this->manager) { return new c_base_return_true(); @@ -242,4 +307,69 @@ class c_base_roles { return new c_base_return_false(); } + + /** + * Get an array of all currently assigned roles. + * + * @return c_base_return_array + * An array of roles are returned. + * An array with error bit set is returned on error. + */ + public function get_roles() { + $roles = array(); + + if ($this->public) { + $roles[self::PUBLIC] = self::PUBLIC; + } + + if ($this->system) { + $roles[self::SYSTEM] = self::SYSTEM; + } + + if ($this->user) { + $roles[self::USER] = self::USER; + } + + if ($this->requester) { + $roles[self::REQUESTER] = self::REQUESTER; + } + + if ($this->drafter) { + $roles[self::DRAFTER] = self::DRAFTER; + } + + if ($this->editer) { + $roles[self::EDITOR] = self::EDITOR; + } + + if ($this->reviewer) { + $roles[self::REVIEWER] = self::REVIEWER; + } + + if ($this->financer) { + $roles[self::FINANCER] = self::FINANCER; + } + + if ($this->insurer) { + $roles[self::INSURER] = self::INSURER; + } + + if ($this->publisher) { + $roles[self::PUBLISHER] = self::PUBLISHER; + } + + if ($this->auditor) { + $roles[self::AUDITOR] = self::AUDITOR; + } + + if ($this->manager) { + $roles[self::MANAGER] = self::MANAGER; + } + + if ($this->administer) { + $roles[self::ADMINISTER] = self::ADMINISTER; + } + + return c_base_return_array::s_new($roles); + } } diff --git a/common/base/classes/base_cookie.php b/common/base/classes/base_cookie.php index 4b08163..91f20a8 100644 --- a/common/base/classes/base_cookie.php +++ b/common/base/classes/base_cookie.php @@ -16,10 +16,12 @@ require_once('common/base/classes/base_return.php'); * This class overrides c_base_return_array() such that some of its return values are in a different form than expected. * This will utilize c_base_return_* as return values. * - * @todo: review this class, for some reason I decided to use c_base_return_array as this class supertype. - * Is that a good idea, because it feels a bit abusive? + * @todo: there seems to be a non-standard cookie flag called 'storeid'. + * I cannot find any decent documentation, so I will not implement it at this time. * * @see: http://us.php.net/manual/en/features.cookies.php + * @see: https://tools.ietf.org/html/rfc6265 + * @see: https://tools.ietf.org/html/draft-west-first-party-cookies * @see: setcookie() */ class c_base_cookie extends c_base_return_array { @@ -28,6 +30,11 @@ class c_base_cookie extends c_base_return_array { const DEFAULT_JSON_ENCODE_DEPTH = 512; const CHECKSUM_ALGORITHM = 'sha256'; + const SAME_SITE_NONE = 0; + const SAME_SITE_RELAXED = 1; + const SAME_SITE_STRICT = 2; + + private $name; private $secure; private $max_age; @@ -36,7 +43,8 @@ class c_base_cookie extends c_base_return_array { private $domain; private $http_only; private $first_only; - private $data; + private $host_only; + private $same_site; private $json_encode_depth; @@ -44,6 +52,8 @@ class c_base_cookie extends c_base_return_array { * Class constructor. */ public function __construct() { + parent::__construct(); + $this->name = NULL; $this->secure = TRUE; $this->max_age = NULL; @@ -52,12 +62,11 @@ class c_base_cookie extends c_base_return_array { $this->domain = NULL; $this->http_only = FALSE; $this->first_only = TRUE; - $this->data = array(); + $this->host_only = TRUE; + $this->same_site = TRUE; $this->json_encode_depth = self::DEFAULT_JSON_ENCODE_DEPTH; $this->p_set_lifetime_default(); - - parent::__construct(); } /** @@ -72,7 +81,8 @@ class c_base_cookie extends c_base_return_array { unset($this->domain); unset($this->http_only); unset($this->first_only); - unset($this->data); + unset($this->host_only); + unset($this->same_site); unset($this->json_encode_depth); parent::__destruct(); @@ -366,13 +376,13 @@ class c_base_cookie extends c_base_return_array { } /** - * Assigns the cookie http only flag. + * Assigns the cookie httponly flag. * * Set this to TRUE to only allow http protocol to utilize this cookie. * According to the PHP documentation, this prohibits javascript from accessing the cookie. * * @param bool $http_only - * The http-only status for the cookie. + * The httponly status for the cookie. * * @return c_base_return_status * TRUE on success, FALSE otherwise. @@ -388,10 +398,10 @@ class c_base_cookie extends c_base_return_array { } /** - * Returns the stored cookie http only flag. + * Returns the stored cookie httponly flag. * * @return c_base_return_bool - * The cookie http only flag. + * The cookie httponly flag. */ public function get_http_only() { // this flag should never be undefined, if it is NULL, then force the default. @@ -403,13 +413,13 @@ class c_base_cookie extends c_base_return_array { } /** - * Assigns the cookie http firsty-party flag. + * Assigns the cookie http first-party flag. * * Set this to TRUE to only allow the cookie to be used as first party only. * According to the PHP documentation, this tells browsers to never allow this to be used as a thirdy-party cookie. * * @param bool $first_only - * The first-only status for the cookie. + * The first-party status for the cookie. * * @return c_base_return_status * TRUE on success, FALSE otherwise. @@ -425,59 +435,106 @@ class c_base_cookie extends c_base_return_array { } /** - * Returns the stored cookie http only flag. + * Returns the stored cookie first-party flag. * * @return c_base_return_bool - * The cookie http only flag. + * The cookie first-party flag. */ public function get_first_only() { // this flag should never be undefined, if it is NULL, then force the default. - if (is_null($this->http_only)) { - $this->http_only = FALSE; + if (is_null($this->first_only)) { + $this->first_only = FALSE; } - return c_base_return_bool::s_new($this->http_only); + return c_base_return_bool::s_new($this->first_only); } /** - * Assign the data. + * Assigns the cookie hostyonly flag. * - * Cookies values associated with this class are only stored as an array. - * Be sure to wrap your values in an array. - * The array key 'checksum' will be created if one does not already exist when building the cookie. + * Set this to TRUE to only allow the cookie to be used as host party only. * - * @param array $data - * Any value so long as it is an array. - * NULL is not allowed. - * FALSE with the error bit set is returned on error. + * @param bool $host_only + * The hostonly status for the cookie. * * @return c_base_return_status * TRUE on success, FALSE otherwise. + * + * @see: https://tools.ietf.org/html/rfc6265#section-5.4 */ - public function set_data($data) { - if (!is_array($data)) { - $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'data', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + public function set_host_only($host_only) { + if (!is_bool($host_only)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'host_only', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); return c_base_return_error::s_false($error); } - $this->data = $data; + $this->host_only = $host_only; return new c_base_return_true(); } /** - * Return the data. + * Returns the stored cookie hostonly flag. * - * @return c_base_return_array - * The value array stored within this class. - * NULL may be returned if there is no defined valid array. - * FALSE with the error bit set is returned on error. + * @return c_base_return_bool + * The cookie hostonly flag. + */ + public function get_host_only() { + // this flag should never be undefined, if it is NULL, then force the default. + if (is_null($this->host_only)) { + $this->host_only = FALSE; + } + + return c_base_return_bool::s_new($this->host_only); + } + + /** + * Assigns the cookie samesite flag. + * + * This also assignes the 'samesite' cookie setting which is functionality similar to hostonly. + * + * @param bool $same_site + * The samesite status for the cookie. + * + * @return c_base_return_status + * TRUE on success, FALSE otherwise. + * + * @see: https://tools.ietf.org/html/draft-west-first-party-cookies + */ + public function set_same_site($same_site) { + if (!is_int($same_site)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'same_site', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + + switch ($same_site) { + case self::SAME_SITE_NONE: + case self::SAME_SITE_RELAXED: + case self::SAME_SITE_STRICT: + $this->same_site = $same_site; + break; + default: + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'same_site', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + + return new c_base_return_true(); + } + + /** + * Returns the stored cookie samesite flag. + * + * @return c_base_return_bool + * The cookie hostonly flag. + * + * @see: https://tools.ietf.org/html/draft-west-first-party-cookies */ - public function get_data() { - if (!is_null($this->data) && !is_array($this->data)) { - $this->data = array(); + public function get_same_site() { + // this flag should never be undefined, if it is NULL, then force the default. + if (is_null($this->same_site)) { + $this->same_site = self::SAME_SITE_RELAXED; } - return c_base_return_array::s_new($this->data); + return c_base_return_int::s_new($this->same_site); } /** @@ -498,17 +555,17 @@ class c_base_cookie extends c_base_return_array { return c_base_return_error::s_false($error); } - if (is_null($this->data)) { - $error = c_base_error::s_log(NULL, array('arguments' => array(':variable_name' => 'this->data', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_VARIABLE); + if (is_null($this->value)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':variable_name' => 'this->value', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_VARIABLE); return c_base_return_error::s_false($error); } - $cookie = $this->p_build_cookie($checksum); - if ($cookie instanceof c_base_return_false) { - return c_base_return_error::s_false($cookie->get_error()); + $set_cookie = $this->p_build_set_cookie($checksum); + if ($set_cookie instanceof c_base_return_false) { + return c_base_return_error::s_false($set_cookie->get_error()); } - return $cookie; + return $set_cookie; } /** @@ -584,13 +641,13 @@ class c_base_cookie extends c_base_return_array { return c_base_return_error::s_false($error); } - if (is_null($this->data)) { - $error = c_base_error::s_log(NULL, array('arguments' => array(':variable_name' => 'this->data', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_VARIABLE); + if (is_null($this->value)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':variable_name' => 'this->value', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_VARIABLE); return c_base_return_error::s_false($error); } - $cookie = $this->p_build_cookie($checksum); - if ($cookie instanceof c_base_return_false) { + $set_cookie = $this->p_build_set_cookie($checksum); + if ($set_cookie instanceof c_base_return_false) { return c_base_return_error::s_false($cookie->get_error()); } @@ -598,9 +655,9 @@ class c_base_cookie extends c_base_return_array { return new c_base_return_false(); } - header($cookie->get_value_exact(), FALSE); + header($set_cookie->get_value_exact(), FALSE); - unset($cookie); + unset($set_cookie); unset($data); return new c_base_return_true(); @@ -616,7 +673,7 @@ class c_base_cookie extends c_base_return_array { * TRUE on success, FALSE otherwise. */ public function do_pull() { - if (!isset($_COOKIE) || !array_key_exists($this->name, $_COOKIE)) { + if (!isset($_COOKIE) || !is_array($_COOKIE) || !array_key_exists($this->name, $_COOKIE)) { // This is not an error, but there is no cookie to pull. // simply return false without the error flag set. return new c_base_return_false(); @@ -631,7 +688,7 @@ class c_base_cookie extends c_base_return_array { return c_base_return_error::s_false($error); } - $this->data = $data; + $this->value = $data; unset($data); return new c_base_return_true(); @@ -651,17 +708,17 @@ class c_base_cookie extends c_base_return_array { * On error FALSE is returned with the error bit set. */ public function validate() { - if (!is_array($this->data)) { + if (!is_array($this->value)) { $error = c_base_error::s_log(NULL, array('arguments' => array(':variable_name' => 'this->data')), i_base_error_messages::INVALID_VARIABLE); return c_base_return_error::s_false($error); } - if (!array_key_exists('checksum', $this->data)) { + if (!array_key_exists('checksum', $this->value)) { return new c_base_return_false(); } $checksum = $this->p_build_checksum(); - if ($this->data['checksum'] == $checksum) { + if ($this->value['checksum'] == $checksum) { unset($checksum); return new c_base_return_true(); } @@ -744,21 +801,21 @@ class c_base_cookie extends c_base_return_array { * @see: hash() */ private function p_build_checksum() { - if (!is_array($this->data)) { - $this->data = array(); + if (!is_array($this->value)) { + $this->value = array(); } - $has_checksum = array_key_exists('checksum', $this->data); + $has_checksum = array_key_exists('checksum', $this->value); $checksum = NULL; if ($has_checksum) { - $checksum = $this->data['checksum']; - unset($this->data['checksum']); + $checksum = $this->value['checksum']; + unset($this->value['checksum']); } - $json = json_encode($this->data, 0, $this->json_encode_depth); + $json = json_encode($this->value, 0, $this->json_encode_depth); if ($json === FALSE) { if ($has_checksum) { - $this->data['checksum'] = $checksum; + $this->value['checksum'] = $checksum; } unset($has_checksum); @@ -770,7 +827,7 @@ class c_base_cookie extends c_base_return_array { $generated = hash(c_base_cookie::CHECKSUM_ALGORITHM, $json); if ($has_checksum) { - $this->data['checksum'] = $checksum; + $this->value['checksum'] = $checksum; } unset($has_checksum); @@ -807,19 +864,19 @@ class c_base_cookie extends c_base_return_array { * @see: header() * @see: headers_sent(). */ - private function p_build_cookie($checksum = TRUE) { + private function p_build_set_cookie($checksum = TRUE) { if ($checksum) { - unset($this->data['checksum']); - $this->data['checksum'] = $this->p_build_checksum(); + unset($this->value['checksum']); + $this->value['checksum'] = $this->p_build_checksum(); - if (is_null($this->data['checksum'])) { - unset($this->data['checksum']); + if (is_null($this->value['checksum'])) { + unset($this->value['checksum']); $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'this->p_build_checksum', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::OPERATION_FAILURE); return c_base_return_error::s_false($error); } } - $json = json_encode($this->data, 0, $this->json_encode_depth); + $json = json_encode($this->value, 0, $this->json_encode_depth); if ($json === FALSE) { unset($json); $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'json_encode', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::OPERATION_FAILURE); @@ -864,6 +921,24 @@ class c_base_cookie extends c_base_return_array { $cookie .= ' first-party;'; } + // the rfc is unclear as it calls the hostonly flag by the name of host-only-flag. + // it does not seem to directly state that the host-only-flag should be defined as 'hostonly' and not 'host-only-flag'. + if ($this->host_only) { + $cookie .= ' hostonly;'; + } + + switch ($this->same_site) { + case self::SAME_SITE_NONE: + $cookie .= ' samesite=no_restriction;'; + break; + case self::SAME_SITE_RELAXED: + $cookie .= ' samesite=lax;'; + break; + case self::SAME_SITE_STRICT: + $cookie .= ' samesite=strict;'; + break; + } + return c_base_return_string::s_new($cookie); } } diff --git a/common/base/classes/base_database.php b/common/base/classes/base_database.php index 327fb4f..2d66eeb 100644 --- a/common/base/classes/base_database.php +++ b/common/base/classes/base_database.php @@ -42,7 +42,7 @@ class c_base_connection_string extends c_base_return_string { private $host; private $host_addr; private $port; - private $database_name; + private $database; private $user; private $password; private $connect_timeout; @@ -56,10 +56,12 @@ class c_base_connection_string extends c_base_return_string { * Class destructor. */ public function __construct() { + parent::__construct(); + $this->host = NULL; $this->host_addr = NULL; $this->port = NULL; - $this->database_name = NULL; + $this->database = NULL; $this->user = NULL; $this->password = NULL; $this->connect_timeout = NULL; @@ -68,8 +70,6 @@ class c_base_connection_string extends c_base_return_string { $this->service = NULL; $this->error = NULL; - - parent::__construct(); } /** @@ -81,7 +81,7 @@ class c_base_connection_string extends c_base_return_string { unset($this->host); unset($this->host_addr); unset($this->port); - unset($this->database_name); + unset($this->database); unset($this->user); unset($this->password); unset($this->connect_timeout); @@ -232,20 +232,20 @@ class c_base_connection_string extends c_base_return_string { /** * Assign database name. * - * @param string $database_name + * @param string $database * The database name string. * * @return c_base_return_status * TRUE on success, FALSE otherwise. * FALSE with the error bit set is returned on error. */ - public function set_database_name($database_name) { - if (!is_string($database_name)) { - $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'database_name', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + public function set_database($database) { + if (!is_string($database)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'database', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); return c_base_return_error::s_false($error); } - $this->database_name = $database_name; + $this->database = $database; return new c_base_return_true(); } @@ -256,12 +256,12 @@ class c_base_connection_string extends c_base_return_string { * The database name string on success. * The error bit set is on error. */ - public function get_database_name() { - if (!is_string($this->database_name)) { - $this->database_name = ''; + public function get_database() { + if (!is_string($this->database)) { + $this->database = ''; } - return c_base_return_string::s_new($this->database_name); + return c_base_return_string::s_new($this->database); } /** @@ -513,8 +513,8 @@ class c_base_connection_string extends c_base_return_string { $this->value .= ' port=' . $this->p_escape_string($this->port); } - if (!empty($this->database_name)) { - $this->value .= ' database_name=' . $this->p_escape_string($this->database_name); + if (!empty($this->database)) { + $this->value .= ' dbname=' . $this->p_escape_string($this->database); } if (!empty($this->user)) { @@ -579,20 +579,10 @@ class c_base_connection_string extends c_base_return_string { /** * A generic class for managing database connections. * - * errata: - * There are a number of cases where PHP's postgresql documentation is unclear on what 'failure' is. - * In certain cases, it mentions failure as an error. - * In other cases, it just says failure. - * If failure happens as a part of normal, expected behavior, then it should not be construed as an error because failure is expected behavior. - * If failure happens due to something unexpected or invalid, then it should be construed as an error. - * This is a context issue and I may be overthinking it. - * I will need to come back later and review my return results. - * For now, I am assuming failure means error as that seems like the most obvious interpretation. - * * @require class c_base_return * @require class c_base_session */ -class c_base_database { +class c_base_database extends c_base_return { private $session; private $persistent; private $database; @@ -605,6 +595,8 @@ class c_base_database { * Class constructor. */ public function __construct() { + parent::__construct(); + $this->session = NULL; $this->persistent = NULL; $this->database = NULL; @@ -632,6 +624,29 @@ class c_base_database { unset($this->connection_string); unset($this->connected); + + parent::__destruct(); + } + + /** + * @see: t_base_return_value::p_s_new() + */ + public static function s_new($value) { + return self::p_s_new($value, __CLASS__); + } + + /** + * @see: t_base_return_value::p_s_value() + */ + public static function s_value($return) { + return self::p_s_value($return, __CLASS__); + } + + /** + * @see: t_base_return_value_exact::p_s_value_exact() + */ + public static function s_value_exact($return) { + return self::p_s_value_exact($return, __CLASS__, array()); } /** @@ -657,7 +672,7 @@ class c_base_database { /** * Returns the session information. * - * @return c_base_session_return + * @return c_base_session * A session object on success. * The error bit set is on error. */ @@ -666,7 +681,7 @@ class c_base_database { $this->session = new c_base_session(); } - return c_base_session_return::s_value_exact($this->session); + return $this->session; } /** @@ -853,7 +868,7 @@ class c_base_database { if ($database === FALSE) { unset($database); - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $this->connection_string->get_database_name()->get_value_exact(), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_CONNECTION_FAILURE); + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $this->connection_string->get_database()->get_value_exact(), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_CONNECTION_FAILURE); return c_base_return_error::s_false($error); } @@ -881,9 +896,9 @@ class c_base_database { */ public function do_disconnect() { if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -907,9 +922,9 @@ class c_base_database { */ public function do_flush() { if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1025,9 +1040,9 @@ class c_base_database { */ public function do_reset() { if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1067,9 +1082,9 @@ class c_base_database { */ public function do_ping() { if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1107,9 +1122,9 @@ class c_base_database { } if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1138,9 +1153,9 @@ class c_base_database { } if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1169,9 +1184,9 @@ class c_base_database { } if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1200,9 +1215,9 @@ class c_base_database { } if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1228,9 +1243,9 @@ class c_base_database { } if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1255,9 +1270,9 @@ class c_base_database { */ public function get_client_encoding() { if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1288,9 +1303,9 @@ class c_base_database { */ public function consume_input() { if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1337,9 +1352,9 @@ class c_base_database { } if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1390,9 +1405,9 @@ class c_base_database { } if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1452,9 +1467,9 @@ class c_base_database { } if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1532,9 +1547,9 @@ class c_base_database { } if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1566,9 +1581,9 @@ class c_base_database { */ public function get_result() { if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1619,9 +1634,9 @@ class c_base_database { */ public function do_cancel() { if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1695,9 +1710,9 @@ class c_base_database { } if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1784,9 +1799,9 @@ class c_base_database { } if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1869,9 +1884,9 @@ class c_base_database { } if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -1953,9 +1968,9 @@ class c_base_database { } if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -2011,9 +2026,9 @@ class c_base_database { } if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -2044,9 +2059,9 @@ class c_base_database { */ public function set_error_verbosity($verbosity) { if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -2069,9 +2084,9 @@ class c_base_database { */ public function get_last_error() { if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -2097,9 +2112,9 @@ class c_base_database { */ public function get_last_notice() { if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -2132,9 +2147,9 @@ class c_base_database { */ public function get_transaction_status() { if (!is_resource($this->database)) { - $database_name = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database_name()->get_value_exact() : ''; - $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); - unset($database_name); + $database = ($this->connection_string instanceof c_base_connection_string) ? $this->connection_string->get_database()->get_value_exact() : ''; + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database); return c_base_return_error::s_false($error); } @@ -2187,6 +2202,13 @@ class c_base_database { class c_base_database_result extends c_base_return_resource { /** + * Class constructor. + */ + public function __construct() { + parent::__construct(); + } + + /** * Class destructor. */ public function __destruct() { @@ -2909,9 +2931,9 @@ class c_base_database_query extends c_base_return_array { * Class constructor. */ public function __construct() { - $this->p_initialize(); - parent::__construct(); + + $this->p_initialize(); } /** diff --git a/common/base/classes/base_debug.php b/common/base/classes/base_debug.php index 6092260..50020de 100644 --- a/common/base/classes/base_debug.php +++ b/common/base/classes/base_debug.php @@ -11,7 +11,7 @@ require_once('common/base/classes/base_return.php'); /** * A generic class for performing debugging. */ -class c_base_debug { +class c_base_debug extends c_base_return { private static $ps_debugging = FALSE; private $time_start; @@ -29,6 +29,8 @@ class c_base_debug { * Class constructor. */ public function __construct() { + parent::__construct(); + $this->time_start = NULL; $this->time_stop = NULL; @@ -53,6 +55,29 @@ class c_base_debug { unset($this->memory_allocated_start); unset($this->memory_allocated_stop); unset($this->memory_allocated_peak); + + parent::__destruct(); + } + + /** + * @see: t_base_return_value::p_s_new() + */ + public static function s_new($value) { + return self::p_s_new($value, __CLASS__); + } + + /** + * @see: t_base_return_value::p_s_value() + */ + public static function s_value($return) { + return self::p_s_value($return, __CLASS__); + } + + /** + * @see: t_base_return_value_exact::p_s_value_exact() + */ + public static function s_value_exact($return) { + return self::p_s_value_exact($return, __CLASS__, ''); } /** diff --git a/common/base/classes/base_email.php b/common/base/classes/base_email.php index 7cd98a6..fdfe709 100644 --- a/common/base/classes/base_email.php +++ b/common/base/classes/base_email.php @@ -34,6 +34,27 @@ class c_base_email extends c_base_rfc_string { /** + * @see: t_base_return_value::p_s_new() + */ + public static function s_new($value) { + return self::p_s_new($value, __CLASS__); + } + + /** + * @see: t_base_return_value::p_s_value() + */ + public static function s_value($return) { + return self::p_s_value($return, __CLASS__); + } + + /** + * @see: t_base_return_value_exact::p_s_value_exact() + */ + public static function s_value_exact($return) { + return self::p_s_value_exact($return, __CLASS__, ''); + } + + /** * Decode and check that the given e-mail address is valid. * * Validation is done according to rfc5322, rfc6854, and rfc7231. @@ -374,7 +395,7 @@ class c_base_email extends c_base_rfc_string { // there may be multiple comments, so do not break at this point. } elseif (!$this->pr_rfc_char_is_fws($code)) { - // the first non-comment, non-fws char should be the start of the [machine_name]. + // the first non-comment, non-fws char should be the start of the [name_machine]. break; } } @@ -388,7 +409,7 @@ class c_base_email extends c_base_rfc_string { return $result; } - // process [machine_name]. + // process [name_machine]. $started = FALSE; $stopped = FALSE; $comments = FALSE; diff --git a/common/base/classes/base_error.php b/common/base/classes/base_error.php index 185c3f1..6d4b749 100644 --- a/common/base/classes/base_error.php +++ b/common/base/classes/base_error.php @@ -499,17 +499,19 @@ interface i_base_error_messages { const INVALID_ARGUMENT = 1; const INVALID_FORMAT = 2; const INVALID_VARIABLE = 3; - const OPERATION_FAILURE = 4; - const OPERATION_UNECESSARY = 5; - const FUNCTION_FAILURE = 6; - const NOT_FOUND_ARRAY_INDEX = 7; - const NOT_FOUND_DIRECTORY = 8; - const NOT_FOUND_FILE = 9; - const NO_CONNECTION = 10; - const NO_SUPPORT = 11; - const POSTGRESQL_CONNECTION_FAILURE = 12; - const POSTGRESQL_NO_CONNECTION = 13; - const POSTGRESQL_NO_RESOURCE = 14; + const INVALID_SESSION = 4; + const OPERATION_FAILURE = 5; + const OPERATION_UNECESSARY = 6; + const FUNCTION_FAILURE = 7; + const NOT_FOUND_ARRAY_INDEX = 8; + const NOT_FOUND_DIRECTORY = 9; + const NOT_FOUND_FILE = 10; + const NO_CONNECTION = 11; + const NO_SUPPORT = 12; + const NO_SESSION = 13; + const POSTGRESQL_CONNECTION_FAILURE = 14; + const POSTGRESQL_NO_CONNECTION = 15; + const POSTGRESQL_NO_RESOURCE = 16; /** diff --git a/common/base/classes/base_error_messages_english.php b/common/base/classes/base_error_messages_english.php index d2e8f3c..9ec232e 100644 --- a/common/base/classes/base_error_messages_english.php +++ b/common/base/classes/base_error_messages_english.php @@ -10,7 +10,7 @@ require_once('common/base/classes/base_languages.php'); /** * English language version of common error messages. */ -class c_base_error_messages_eng extends i_base_error_messages { +final class c_base_error_messages_english extends i_base_error_messages { /** * Returns a standard error message associated with the given code. diff --git a/common/base/classes/base_form.php b/common/base/classes/base_form.php new file mode 100644 index 0000000..bb7889e --- /dev/null +++ b/common/base/classes/base_form.php @@ -0,0 +1,205 @@ +fields = NULL; + $this->arguments = NULL; + } + + /** + * Class destructor. + */ + public function __destruct() { + unset($this->fields); + unset($this->arguments); + + parent::__destruct(); + } + + /** + * @see: t_base_return_value::p_s_new() + */ + public static function s_new($value) { + return self::p_s_new($value, __CLASS__); + } + + /** + * @see: t_base_return_value::p_s_value() + */ + public static function s_value($return) { + return self::p_s_value($return, __CLASS__); + } + + /** + * @see: t_base_return_value_exact::p_s_value_exact() + */ + public static function s_value_exact($return) { + return self::p_s_value_exact($return, __CLASS__, array()); + } + + /** + * Associations a field via the field name with this problem. + * + * @param string $field_name + * The field name to assign. + * + * @return c_base_return_status + * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. + * + * @see: c_base_session::save() + */ + public function set_field($field_name) { + if (!is_string($field_name) && !empty($field_name)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'field_name', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + + if (!is_array($this->fields)) { + $this->fields = array(); + } + + $this->fields[$field_name] = $field_name; + return new c_base_return_true(); + } + + /** + * Unassociates a field via the field name with this problem. + * + * @param string $field_name + * The field name to assign. + * + * @return c_base_return_status + * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. + * FALSE without error bit set is returned if the field name is not assigned. + * + * @see: c_base_session::save() + */ + public function unset_field($field_name) { + if (!is_string($field_name) && !empty($field_name)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'field_name', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + + if (is_null($this->fields) || !array_key_exists($field_name, $this->fields)) { + return new c_base_return_false(); + } + + unset($this->fields[$field_name]); + return new c_base_return_true(); + } + + /** + * Returns all fields associated with this problem. + * + * @return c_base_return_array|c_base_return_status + * An array of field names. + * FALSE with the error bit set is returned on error. + */ + public function get_fields() { + if (!is_array($this->fields)) { + $this->fields = array(); + } + + return c_base_return_array::s_new($this->fields); + } + + /** + * Associations a field via the field name with this problem. + * + * @param string $index + * The index name to be associated with this message. + * @param string $value + * A string representing the value to be associated with the index. + * + * @return c_base_return_status + * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. + * + * @see: c_base_session::save() + */ + public function set_argument($index, $value) { + if (!is_string($index) && !empty($index)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'index', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + + if (!is_string($value)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'value', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + + if (!is_array($this->arguments)) { + $this->arguments = array(); + } + + $this->arguments[$index] = $value; + return new c_base_return_true(); + } + + /** + * Gets the argument value assigned at the specified index. + * + * @return c_base_return_value|c_base_return_status + * An array of field names. + * FALSE with the error bit set is returned on error. + * FALSE without error bit set is returned if the index is not assigned. + */ + public function get_argument($index) { + if (!is_string($index) && !empty($index)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'index', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + + if (!is_array($this->arguments)) { + $this->arguments = array(); + } + + if (!array_key_exists($index, $this->arguments)) { + return new c_base_return_false(); + } + + return c_base_return_value::s_new($this->fields); + } + + /** + * Returns all arguments associated with this problem. + * + * @return c_base_return_array|c_base_return_status + * An array of field names. + * FALSE with the error bit set is returned on error. + */ + public function get_arguments() { + if (!is_array($this->arguments)) { + $this->arguments = array(); + } + + return c_base_return_array::s_new($this->arguments); + } +} diff --git a/common/base/classes/base_html.php b/common/base/classes/base_html.php index d1c7dac..51da35c 100644 --- a/common/base/classes/base_html.php +++ b/common/base/classes/base_html.php @@ -20,7 +20,7 @@ require_once('common/base/classes/base_markup.php'); * * @todo: add support for non-standard tag attributes, which will just be a string or NULL. */ -class c_base_html { +class c_base_html extends c_base_return { private $id; private $attributes; private $attributes_body; @@ -33,6 +33,8 @@ class c_base_html { * Class constructor. */ public function __construct() { + parent::__construct(); + $this->id = NULL; $this->attributes = array(); $this->attributes_body = array(); @@ -49,6 +51,29 @@ class c_base_html { unset($this->attributes_body); unset($this->headers); unset($this->body); + + parent::__destruct(); + } + + /** + * @see: t_base_return_value::p_s_new() + */ + public static function s_new($value) { + return self::p_s_new($value, __CLASS__); + } + + /** + * @see: t_base_return_value::p_s_value() + */ + public static function s_value($return) { + return self::p_s_value($return, __CLASS__); + } + + /** + * @see: t_base_return_value_exact::p_s_value_exact() + */ + public static function s_value_exact($return) { + return self::p_s_value_exact($return, __CLASS__, ''); } /** @@ -231,7 +256,7 @@ class c_base_html { * @param int $delta * The position in the array of the tag to get. * - * @return c_base_markup_tag_return|c_base_return_status + * @return c_base_markup_tag|c_base_return_status * The tag, if found at delta. * FALSE is returned if no tag is at delta. * FALSE with error bit set is returned on error. @@ -246,7 +271,7 @@ class c_base_html { return new c_base_return_false(); } - return c_base_markup_tag_return::s_new($this->body[$delta]); + return $this->body[$delta]; } /** @@ -322,7 +347,7 @@ class c_base_html { * @param int $delta * The position in the array of the header to get. * - * @return c_base_markup_tag_return|c_base_return_status + * @return c_base_markup_tag|c_base_return_status * The header, if found at delta. * FALSE is returned if no header is at delta. * FALSE with error bit set is returned on error. @@ -337,7 +362,7 @@ class c_base_html { return new c_base_return_false(); } - return c_base_markup_tag_return::s_new($this->headers[$delta]); + return $this->headers[$delta]; } /** @@ -483,8 +508,6 @@ class c_base_html { return TRUE; } - - /** * Get the value of a single attribute assigned to this object. * @@ -1303,79 +1326,3 @@ class c_base_html { return new c_base_return_true(); } } - -/** - * A return class whose value is represented as a generic c_base_markup_tag_return. - */ -class c_base_html_return extends c_base_return_object { - use t_base_return_value_exact; - - /** - * @see: t_base_return_value::p_s_new() - */ - public static function s_new($value) { - return self::p_s_new($value, __CLASS__); - } - - /** - * @see: t_base_return_value::p_s_value() - */ - public static function s_value($return) { - return self::p_s_value($return, __CLASS__); - } - - /** - * @see: t_base_return_value_exact::p_s_value_exact() - */ - public static function s_value_exact($return) { - return self::p_s_value_exact($return, __CLASS__, new c_base_html()); - } - - /** - * Assign the value. - * - * @param c_base_html $value - * Any value so long as it is an resource. - * NULL is not allowed. - * - * @return bool - * TRUE on success, FALSE otherwise. - */ - public function set_value($value) { - if (!($value instanceof c_base_html)) { - return FALSE; - } - - $this->value = $value; - return TRUE; - } - - /** - * Return the value. - * - * @return c_base_html|null $value - * The value c_base_html stored within this class. - * NULL may be returned if there is no defined valid c_base_markup_tag. - */ - public function get_value() { - if (!is_null($this->value) && !($this->value instanceof c_base_html)) { - $this->value = NULL; - } - - return $this->value; - } - - /** - * Return the value of the expected type. - * - * @return c_base_html $value - * The value c_base_html stored within this class. - */ - public function get_value_exact() { - if (!($this->value instanceof c_base_html)) { - $this->value = new c_base_html(); - } - - return $this->value; - } -} diff --git a/common/base/classes/base_http.php b/common/base/classes/base_http.php index f3fb081..7da3494 100644 --- a/common/base/classes/base_http.php +++ b/common/base/classes/base_http.php @@ -230,6 +230,8 @@ class c_base_http extends c_base_rfc_string { * Class constructor. */ public function __construct() { + parent::__construct(); + $this->headers = NULL; $this->headers_sent = FALSE; $this->request = array(); @@ -258,6 +260,29 @@ class c_base_http extends c_base_rfc_string { unset($this->buffer_enabled); unset($this->language_class); + + parent::__destruct(); + } + + /** + * @see: t_base_return_value::p_s_new() + */ + public static function s_new($value) { + return self::p_s_new($value, __CLASS__); + } + + /** + * @see: t_base_return_value::p_s_value() + */ + public static function s_value($return) { + return self::p_s_value($return, __CLASS__); + } + + /** + * @see: t_base_return_value_exact::p_s_value_exact() + */ + public static function s_value_exact($return) { + return self::p_s_value_exact($return, __CLASS__, ''); } /** @@ -267,18 +292,45 @@ class c_base_http extends c_base_rfc_string { * * @param int|null $header_name * (optional) The numeric id of the request or NULL to load all requests. + * @param int|string|null $delta + * (optional) For headers that have an array of data, this represents and index position within that array. + * For all other headers, this does nothing. * - * @return c_base_return_array|c_base_return_status + * @return c_base_return_array|c_base_return_value|c_base_return_status * The HTTP request array or an array containing the request field information. + * FALSE without error bit set is returned when the requested header name is undefined. * FALSE with error bit set is returned on error. */ - public function get_request($header_name = NULL) { + public function get_request($header_name = NULL, $delta = NULL) { + if (!is_null($header_name) && !is_int($header_name)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'header_name', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + + if (!is_null($delta) && !is_int($delta) && !is_string($delta)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'delta', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + if (is_null($header_name)) { return c_base_return_array::s_new($this->request); } - if (!is_int($header_name) || !array_key_exists($header_name, $this->request)) { - $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'header_name', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + if (!array_key_exists($header_name, $this->request)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':index_name' => $header_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::NOT_FOUND_ARRAY_INDEX); + return c_base_return_error::s_false($error); + } + + if (!is_null($delta)) { + if (isset($this->request[$header_name]['data']) && is_array($this->request[$header_name]['data']) && array_key_exists($delta, $this->request[$header_name]['data'])) { + if ($this->request[$header_name]['data'][$delta] instanceof c_base_return) { + return $this->request[$header_name]['data'][$delta]; + } + + return c_base_return_value::s_new($this->request[$header_name]['data'][$delta]); + } + + $error = c_base_error::s_log(NULL, array('arguments' => array(':index_name' => $delta, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::NOT_FOUND_ARRAY_INDEX); return c_base_return_error::s_false($error); } @@ -288,13 +340,57 @@ class c_base_http extends c_base_rfc_string { /** * Get the HTTP response array. * - * Load the entire HTTP response array. + * Load the entire HTTP response array or a specific response field. * - * @return c_base_return_array - * The HTTP response array. + * @param int|null $header_name + * (optional) The numeric id of the response or NULL to load all responses. + * @param int|string|null $delta + * (optional) For headers that have an array of data, this represents and index position within that array. + * For all other headers, this does nothing. + * + * @return c_base_return_array|c_base_return_string|c_base_return_value|c_base_return_status + * The HTTP response array or string for a given field or the entire HTTP response array. + * FALSE without error bit set is returned when the requested header name is undefined. + * FALSE with error bit set is returned on error. */ - public function get_response() { - return c_base_return_array::s_new($this->response); + public function get_response($header_name = NULL, $delta = NULL) { + if (!is_null($header_name) && !is_int($header_name)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'header_name', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + + if (!is_null($delta) && !is_int($delta) && !is_string($delta)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'delta', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + + if (is_null($header_name)) { + return c_base_return_array::s_new($this->response); + } + + if (!array_key_exists($header_name, $this->response)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':index_name' => $header_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::NOT_FOUND_ARRAY_INDEX); + return c_base_return_error::s_false($error); + } + + if (is_array($this->response[$header_name])) { + if (is_null($delta)) { + return c_base_return_array::s_new($this->response[$header_name]); + } + + if (isset($this->response[$header_name]) && is_array($this->response[$header_name]) && array_key_exists($delta, $this->response[$header_name])) { + if ($this->response[$header_name][$delta] instanceof c_base_return) { + return $this->response[$header_name][$delta]; + } + + return c_base_return_value::s_new($this->response[$header_name][$delta]); + } + + $error = c_base_error::s_log(NULL, array('arguments' => array(':index_name' => $delta, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::NOT_FOUND_ARRAY_INDEX); + return c_base_return_error::s_false($error); + } + + return c_base_return_string::s_new($this->response[$header_name]); } /** @@ -305,6 +401,7 @@ class c_base_http extends c_base_rfc_string { * * @return c_base_return_status * TRUE on success, FALSE otherwise. + * FALSE with error bit set is returned on error. */ public function set_language_class($class_name) { if (!is_string($class_name) || !is_subclass_of('i_base_language', $class_name) ) { @@ -321,6 +418,7 @@ class c_base_http extends c_base_rfc_string { * * @return c_base_return_string * The language class string. + * FALSE with error bit set is returned on error. */ public function get_language_class() { if (is_null($this->language_class)) { @@ -337,6 +435,7 @@ class c_base_http extends c_base_rfc_string { * @return c_base_return_float|c_base_return_status * The HTTP request time. * FALSE without error bit is returned when the request timestamp has not yet been loaded + * FALSE with error bit set is returned on error. */ public function get_request_time() { if (is_null($this->request_time)) { @@ -348,6 +447,10 @@ class c_base_http extends c_base_rfc_string { /** * Load, process, and interpret all of the supported http request headers. + * + * @return c_base_return_status + * TRUE on success, FALSE otherwise. + * FALSE with error bit set is returned on error. */ public function do_load_request() { if (!is_array($this->headers)) { @@ -8279,79 +8382,3 @@ class c_base_http extends c_base_rfc_string { return FALSE; } } - -/** - * A return class whose value is represented as a generic c_base_markup_tag_return. - */ -class c_base_http_return extends c_base_return_object { - use t_base_return_value_exact; - - /** - * @see: t_base_return_value::p_s_new() - */ - public static function s_new($value) { - return self::p_s_new($value, __CLASS__); - } - - /** - * @see: t_base_return_value::p_s_value() - */ - public static function s_value($return) { - return self::p_s_value($return, __CLASS__); - } - - /** - * @see: t_base_return_value_exact::p_s_value_exact() - */ - public static function s_value_exact($return) { - return self::p_s_value_exact($return, __CLASS__, new c_base_http()); - } - - /** - * Assign the value. - * - * @param c_base_http $value - * Any value so long as it is an resource. - * NULL is not allowed. - * - * @return bool - * TRUE on success, FALSE otherwise. - */ - public function set_value($value) { - if (!($value instanceof c_base_http)) { - return FALSE; - } - - $this->value = $value; - return TRUE; - } - - /** - * Return the value. - * - * @return c_base_http|null $value - * The value c_base_http stored within this class. - * NULL may be returned if there is no defined valid c_base_markup_tag. - */ - public function get_value() { - if (!is_null($this->value) && !($this->value instanceof c_base_http)) { - $this->value = NULL; - } - - return $this->value; - } - - /** - * Return the value of the expected type. - * - * @return c_base_http $value - * The value c_base_html stored within this class. - */ - public function get_value_exact() { - if (!($this->value instanceof c_base_http)) { - $this->value = new c_base_html(); - } - - return $this->value; - } -} diff --git a/common/base/classes/base_ldap.php b/common/base/classes/base_ldap.php index 04e642e..81c90e0 100644 --- a/common/base/classes/base_ldap.php +++ b/common/base/classes/base_ldap.php @@ -13,7 +13,7 @@ require_once('common/base/classes/base_return.php'); /** * A class for managing ldap connections. */ -class c_base_ldap { +class c_base_ldap extends c_base_return { private $ldap; private $name; @@ -25,6 +25,8 @@ class c_base_ldap { * Class constructor. */ public function __construct() { + parent::__construct(); + $this->ldap = NULL; $this->name = NULL; @@ -41,6 +43,29 @@ class c_base_ldap { unset($this->bind_name); unset($this->bind_password); + + parent::__destruct(); + } + + /** + * @see: t_base_return_value::p_s_new() + */ + public static function s_new($value) { + return self::p_s_new($value, __CLASS__); + } + + /** + * @see: t_base_return_value::p_s_value() + */ + public static function s_value($return) { + return self::p_s_value($return, __CLASS__); + } + + /** + * @see: t_base_return_value_exact::p_s_value_exact() + */ + public static function s_value_exact($return) { + return self::p_s_value_exact($return, __CLASS__, ''); } /** @@ -623,6 +648,8 @@ class c_base_ldap_result extends c_base_return_resource { * Class constructor. */ public function __construct() { + parent::__construct(); + $this->ldap = NULL; $this->entry = NULL; } diff --git a/common/base/classes/base_log.php b/common/base/classes/base_log.php index 6be9bb4..8242bf9 100644 --- a/common/base/classes/base_log.php +++ b/common/base/classes/base_log.php @@ -7,7 +7,7 @@ /** * A generic class for managing the logs. */ -class c_base_log { +class c_base_log extends c_base_return { const TYPE_NONE = 0; const TYPE_BASE = 1; // for low-level entries. const TYPE_REQUEST = 2; // accessing the site (generally page requests). @@ -75,6 +75,8 @@ class c_base_log { * Class constructor. */ public function __construct() { + parent::__construct(); + $this->type = self::TYPE_NONE; $this->data = array(); } @@ -85,6 +87,29 @@ class c_base_log { public function __destruct() { unset($this->type); unset($this->data); + + parent::__destruct(); + } + + /** + * @see: t_base_return_value::p_s_new() + */ + public static function s_new($value) { + return self::p_s_new($value, __CLASS__); + } + + /** + * @see: t_base_return_value::p_s_value() + */ + public static function s_value($return) { + return self::p_s_value($return, __CLASS__); + } + + /** + * @see: t_base_return_value_exact::p_s_value_exact() + */ + public static function s_value_exact($return) { + return self::p_s_value_exact($return, __CLASS__, ''); } /** @@ -212,7 +237,7 @@ class c_base_log { if (is_int($key)) { if ($key < 0) { $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'key', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); - return c_base_return_error::s_false($error); + return c_base_return_error::s_false($error); } } elseif (!is_string($key)) { @@ -225,6 +250,10 @@ class c_base_log { return c_base_return_error::s_false($error); } + if ($this->data[$key] instanceof c_base_return) { + return $this->data[$key]; + } + return c_base_return_value::s_new($this->data[$key]); } } diff --git a/common/base/classes/base_markup.php b/common/base/classes/base_markup.php index 0601c28..2ee90f0 100644 --- a/common/base/classes/base_markup.php +++ b/common/base/classes/base_markup.php @@ -352,7 +352,7 @@ class c_base_markup_attributes { * * @todo: add support for non-standard tag attributes, which will just be a string or NULL. */ -class c_base_markup_tag { +class c_base_markup_tag extends c_base_return { const TYPE_NONE = 0; const TYPE_A = 1; const TYPE_ABBR = 2; @@ -524,6 +524,8 @@ class c_base_markup_tag { * Class constructor. */ public function __construct() { + parent::__construct(); + $this->attributes = array(); $this->tags = array(); $this->tags_total = 0; @@ -540,6 +542,29 @@ class c_base_markup_tag { unset($this->tags_total); unset($this->text); unset($this->type); + + parent::__destruct(); + } + + /** + * @see: t_base_return_value::p_s_new() + */ + public static function s_new($value) { + return self::p_s_new($value, __CLASS__); + } + + /** + * @see: t_base_return_value::p_s_value() + */ + public static function s_value($return) { + return self::p_s_value($return, __CLASS__); + } + + /** + * @see: t_base_return_value_exact::p_s_value_exact() + */ + public static function s_value_exact($return) { + return self::p_s_value_exact($return, __CLASS__, ''); } /** @@ -1818,79 +1843,3 @@ class c_base_markup_tag { return TRUE; } } - -/** - * A return class whose value is represented as a generic c_base_markup_tag_return. - */ -class c_base_markup_tag_return extends c_base_return_value { - use t_base_return_value_exact; - - /** - * @see: t_base_return_value::p_s_new() - */ - public static function s_new($value) { - return self::p_s_new($value, __CLASS__); - } - - /** - * @see: t_base_return_value::p_s_value() - */ - public static function s_value($return) { - return self::p_s_value($return, __CLASS__); - } - - /** - * @see: t_base_return_value_exact::p_s_value_exact() - */ - public static function s_value_exact($return) { - return self::p_s_value_exact($return, __CLASS__, new c_base_markup_tag()); - } - - /** - * Assign the value. - * - * @param resource $value - * Any value so long as it is an resource. - * NULL is not allowed. - * - * @return bool - * TRUE on success, FALSE otherwise. - */ - public function set_value($value) { - if (!($value instanceof c_base_markup_tag)) { - return FALSE; - } - - $this->value = $value; - return TRUE; - } - - /** - * Return the value. - * - * @return c_base_markup_tag|null $value - * The value c_base_markup_tag stored within this class. - * NULL may be returned if there is no defined valid c_base_markup_tag. - */ - public function get_value() { - if (!is_null($this->value) && !($this->value instanceof c_base_markup_tag)) { - $this->value = NULL; - } - - return $this->value; - } - - /** - * Return the value of the expected type. - * - * @return c_base_markup_tag $value - * The value c_base_markup_tag stored within this class. - */ - public function get_value_exact() { - if (!($this->value instanceof c_base_markup_tag)) { - $this->value = new c_base_markup_tag(); - } - - return $this->value; - } -} diff --git a/common/base/classes/base_rfc_char.php b/common/base/classes/base_rfc_char.php index 99e682b..f163bb2 100644 --- a/common/base/classes/base_rfc_char.php +++ b/common/base/classes/base_rfc_char.php @@ -5,6 +5,7 @@ */ // include required files. +require_once('common/base/classes/base_return.php'); require_once('common/base/classes/base_ascii.php'); require_once('common/base/classes/base_utf8.php'); @@ -41,7 +42,28 @@ require_once('common/base/classes/base_utf8.php'); * @require class c_base_ascii * @require class c_base_utf8 */ -abstract class c_base_rfc_char { +abstract class c_base_rfc_char extends c_base_return { + + /** + * @see: t_base_return_value::p_s_new() + */ + public static function s_new($value) { + return self::p_s_new($value, __CLASS__); + } + + /** + * @see: t_base_return_value::p_s_value() + */ + public static function s_value($return) { + return self::p_s_value($return, __CLASS__); + } + + /** + * @see: t_base_return_value_exact::p_s_value_exact() + */ + public static function s_value_exact($return) { + return self::p_s_value_exact($return, __CLASS__, ''); + } /** * Check to see if character is: text. diff --git a/common/base/classes/base_rfc_string.php b/common/base/classes/base_rfc_string.php index c65fdb7..a26e931 100644 --- a/common/base/classes/base_rfc_string.php +++ b/common/base/classes/base_rfc_string.php @@ -45,6 +45,27 @@ abstract class c_base_rfc_string extends c_base_rfc_char { const STOP_AT_CLOSING_CHARACTER = -1; /** + * @see: t_base_return_value::p_s_new() + */ + public static function s_new($value) { + return self::p_s_new($value, __CLASS__); + } + + /** + * @see: t_base_return_value::p_s_value() + */ + public static function s_value($return) { + return self::p_s_value($return, __CLASS__); + } + + /** + * @see: t_base_return_value_exact::p_s_value_exact() + */ + public static function s_value_exact($return) { + return self::p_s_value_exact($return, __CLASS__, ''); + } + + /** * Converts a string into a ordinals array and a characters array. * * The ordinals and characters returned by this are utf8-friendly such that the caller need only use a counter to navigate. diff --git a/common/base/classes/base_session.php b/common/base/classes/base_session.php index 6d5c9e9..28b57c3 100644 --- a/common/base/classes/base_session.php +++ b/common/base/classes/base_session.php @@ -7,6 +7,7 @@ // include required files. require_once('common/base/classes/base_error.php'); require_once('common/base/classes/base_return.php'); +require_once('common/base/classes/base_form.php'); /** * A class for managing sessions. @@ -16,18 +17,21 @@ require_once('common/base/classes/base_return.php'); * This session key can be used to retrieve a password between requests and to access the database. * The database can then be used to retrieve any session variables. */ -class c_base_session { +class c_base_session extends c_base_return { const PACKET_MAX_LENGTH = 8192; const SOCKET_PATH_PREFIX = '/programs/sockets/sessionize_accounts/'; const SOCKET_PATH_SUFFIX = '/sessions.socket'; const PASSWORD_CLEAR_TEXT_LENGTH = 2048; private $socket; + private $socket_directory; private $socket_path; private $socket_timeout; private $system_name; + private $cookie; + private $name; private $id_user; private $host; @@ -35,20 +39,25 @@ class c_base_session { private $session_id; private $settings; - private $error; - private $timeout_expire; private $timeout_max; + private $problems; + /** * Class constructor. */ public function __construct() { + parent::__construct(); + $this->socket = NULL; + $this->socket_directory = NULL; $this->socket_path = NULL; $this->socket_timeout = NULL; + $this->cookie = NULL; + $this->system_name = NULL; $this->name = NULL; @@ -58,10 +67,10 @@ class c_base_session { $this->session_id = NULL; $this->settings = NULL; - $this->error = NULL; - $this->timeout_expire = NULL; $this->timeout_max = NULL; + + $this->problems = NULL; } /** @@ -75,9 +84,12 @@ class c_base_session { } unset($this->socket); + unset($this->socket_directory); unset($this->socket_path); unset($this->socket_timeout); + unset($this->cookie); + unset($this->system_name); unset($this->name); @@ -88,29 +100,146 @@ class c_base_session { unset($this->special); unset($this->settings); - unset($this->error); - unset($this->timeout_expire); unset($this->timeout_max); + + unset($this->problems); + + parent::__destruct(); + } + + /** + * @see: t_base_return_value::p_s_new() + */ + public static function s_new($value) { + return self::p_s_new($value, __CLASS__); + } + + /** + * @see: t_base_return_value::p_s_value() + */ + public static function s_value($return) { + return self::p_s_value($return, __CLASS__); + } + + /** + * @see: t_base_return_value_exact::p_s_value_exact() + */ + public static function s_value_exact($return) { + return self::p_s_value_exact($return, __CLASS__, array()); + } + + /** + * Assigns the socket directory name, which is used to create the socket path. + * + * If not specified, then self::SOCKET_PATH_PREFIX will be used. + * + * @param string|null $socket_directory + * A directory name. + * Set to NULL to remove any existing values. + * + * @return c_base_return_status + * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. + */ + public function set_socket_directory($socket_directory) { + if (!is_null($socket_directory) && (!is_string($socket_directory) || empty($socket_directory))) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'socket_directory', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + + if (is_null($socket_directory)) { + $this->socket_directory = NULL; + return new c_base_return_true(); + } + + if (!is_dir($socket_directory)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':direction_name' => $socket_directory, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::NOT_FOUND_DIRECTORY); + return c_base_return_error::s_false($error); + } + + // require a single closing '/' at the end of the path. + $this->socket_directory = preg_replace('@/*$@i', '', $socket_directory) . '/'; + + return new c_base_return_true(); + } + + /** + * Returns the stored socket directory name. + * + * @return c_base_return_string|c_base_return_null + * The system name string or NULL if undefined. + * FALSE with the error bit set is returned on error. + */ + public function get_socket_directory() { + if (is_null($this->socket_directory)) { + return new c_base_return_null(); + } + + return c_base_return_string::s_new($this->socket_directory); + } + + /** + * Assigns the cookie associated with this session. + * + * @param c_base_cookie|null $cookie + * The session cookie. + * Set to NULL to remove any existing values. + * + * @return c_base_return_status + * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. + */ + public function set_cookie($cookie) { + if (!is_null($cookie) && !($cookie instanceof c_base_cookie)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'cookie', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + + $this->cookie = $cookie; + + return new c_base_return_true(); + } + + /** + * Returns the stored system name. + * + * @return c_base_cookie|c_base_return_null + * The session cookie or NULL if undefined. + * FALSE with the error bit set is returned on error. + */ + public function get_cookie() { + if (is_null($this->cookie)) { + return new c_base_return_null(); + } + + return $this->cookie; } /** * Assigns the system name, which is used to create the socket path. * - * @param string $system_name + * @param string|null $system_name * A system name string. + * Set to NULL to remove any existing values. * * @return c_base_return_status * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. */ public function set_system_name($system_name) { - if (!is_string($system_name) || empty($system_name)) { + if (!is_null($system_name) && (!is_string($system_name) || empty($system_name))) { $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'system_name', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); return c_base_return_error::s_false($error); } + if (is_null($this->socket_directory)) { + $this->socket_directory = NULL; + return new c_base_return_true(); + } + $this->system_name = basename($system_name); - $this->socket_path = self::SOCKET_PATH_PREFIX . $this->system_name . self::SOCKET_PATH_SUFFIX; + $this->socket_path = $this->socket_directory . $this->system_name . self::SOCKET_PATH_SUFFIX; return new c_base_return_true(); } @@ -120,26 +249,38 @@ class c_base_session { * * @return c_base_return_string * The system name string or NULL if undefined. + * FALSE with the error bit set is returned on error. */ public function get_system_name() { + if (is_null($this->system_name)) { + return new c_base_return_null(); + } + return c_base_return_string::s_new($this->system_name); } /** * Assigns the user name associated with the session. * - * @param string $name + * @param string|null $name * The user name. + * Set to NULL to remove any existing values. * * @return c_base_return_status * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. */ public function set_name($name) { - if (!is_string($name) || empty($name)) { + if (!is_null($name) && (!is_string($name) || empty($name))) { $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'name', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); return c_base_return_error::s_false($error); } + if (is_null($name)) { + $this->name = NULL; + return new c_base_return_true(); + } + if (mb_strlen($name) == 0 || preg_match('/^(\w|-)+$/i', $name) != 1) { $error = c_base_error::s_log(NULL, array('arguments' => array(':format_name' => 'name', ':expected_format' => '. Alphanumeric and dash characters only', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_FORMAT); return c_base_return_error::s_false($error); @@ -152,58 +293,78 @@ class c_base_session { /** * Returns the stored user name. * - * @return c_base_return_string - * The user name string. + * @return c_base_return_string|c_base_return_null + * The user name string or NULL if undefined. + * FALSE with the error bit set is returned on error. */ public function get_name() { + if (is_null($this->name)) { + return new c_base_return_null(); + } + return c_base_return_string::s_new($this->name); } /** * Assigns the user id associated with the session. * - * @param int $id_user + * @param int|null $id_user * The user id. * This must be greater than or equal to 0. + * Set to NULL to remove any existing values. * * @return c_base_return_status * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. */ public function set_id_user($id_user) { - if ((is_int($id_user) && $id_user < 0) || !is_int($id_user) && (!is_string($id_user) || !(is_numeric($id_user) && (int) $id_user >= 0))) { + if (!is_null($id_user) && ((is_int($id_user) && $id_user < 0))) { $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'id_user', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); return c_base_return_error::s_false($error); } - $this->id_user = (int) $id_user; + $this->id_user = $id_user; + return new c_base_return_true(); } /** * Returns the stored user id. * - * @return c_base_return_int - * The user id_user integer. + * @return c_base_return_int|c_base_return_null + * The user id_user integer or NULL if undefined. + * FALSE with the error bit set is returned on error. */ public function get_id_user() { + if (is_null($this->id_user)) { + return new c_base_return_null(); + } + return c_base_return_int::s_new($this->id_user); } /** * Assigns the host ip address associated with the session. * - * @param string $host + * @param string|null $host * The host ip address. + * Set to NULL to remove any existing values. * * @return c_base_return_status * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. */ public function set_host($host) { - if (!is_string($host) || empty($host)) { + if (!is_null($host) && (!is_string($host) || empty($host))) { $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'host', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); return c_base_return_error::s_false($error); } + if (is_null($host)) { + $this->host = nULL; + return new c_base_return_true(); + } + if (mb_strlen($host) == 0 || ip2long($host) === FALSE) { $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'host', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); return c_base_return_error::s_false($error); @@ -216,10 +377,15 @@ class c_base_session { /** * Returns the stored host ip address. * - * @return c_base_return_string - * The host ip address string. + * @return c_base_return_string|c_base_return_null + * The host ip address string or NULL if undefined. + * FALSE with the error bit set is returned on error. */ public function get_host() { + if (is_null($this->host)) { + return new c_base_return_null(); + } + return c_base_return_string::s_new($this->host); } @@ -231,10 +397,11 @@ class c_base_session { * * @param string|null $password * The password. - * Assigning null disable the password. + * Set to NULL to remove any existing values. * * @return c_base_return_status * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. * * @see: c_base_session::load() */ @@ -262,10 +429,15 @@ class c_base_session { /** * Returns the stored password. * - * @return c_base_return_string - * The password string. + * @return c_base_return_string|c_base_return_null + * The password string or NULL if undefined. + * FALSE with the error bit set is returned on error. */ public function get_password() { + if (is_null($this->password)) { + return new c_base_return_null(); + } + return c_base_return_string::s_new($this->password); } @@ -274,14 +446,75 @@ class c_base_session { * * The settings provides optional information that a service may want to store with a particular session. * - * @param array $settings + * @param $setting + * A value to assign at the specified delta. + * Can be any variable type. + * + * @return c_base_return_status + * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. + */ + public function set_setting($delta, $setting) { + if (!is_int($delta) && !is_string($delta)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'delta', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + + if (!is_array($this->settings)) { + $this->settings = array(); + } + + $this->settings[$delta] = $setting; + return new c_base_return_true(); + } + + /** + * Returns a specific index within the stored settings. + * + * @param int|string $delta + * (optional) If an integer or a string, represents a specific index in the given settings array. + * + * @return c_base_return_value|c_base_return_null + * The settings array value at the specified delta or NULL if undefined. + * FALSE with the error bit set is returned on error. + */ + public function get_setting($delta) { + if (!is_int($delta) && !is_string($delta)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'delta', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + + if (is_null($this->settings)) { + return new c_base_return_null(); + } + + if (!array_key_exists($delta, $this->settings)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':index_name' => $delta, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::NOT_FOUND_ARRAY_INDEX); + return c_base_return_error::s_false($error); + } + + if ($this->settings[$delta] instanceof c_base_return) { + return $this->settings[$delta]; + } + + return c_base_return_value::s_new($this->settings[$delta]); + } + + /** + * Assigns the settings associated with the session. + * + * The settings provides optional information that a service may want to store with a particular session. + * + * @param array|null $settings * The settings array to assign. + * Set to NULL to remove any existing values. * * @return c_base_return_status * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. */ public function set_settings($settings) { - if (!is_array($settings)) { + if (!is_null($settings) && !is_array($settings)) { $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'settings', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); return c_base_return_error::s_false($error); } @@ -293,10 +526,15 @@ class c_base_session { /** * Returns the stored settings. * - * @return c_base_return_array - * The settings array. + * @return c_base_return_array|c_base_return_null + * The settings array or NULL if undefined. + * FALSE with the error bit set is returned on error. */ public function get_settings() { + if (is_null($this->settings)) { + return new c_base_return_null(); + } + return c_base_return_array::s_new($this->settings); } @@ -321,20 +559,27 @@ class c_base_session { * Manually assign this for existing sessions only. * This should be auto-populated when a new session is saved. * - * @param string $session_id + * @param string|null $session_id * The session id string. + * Set to NULL to remove any existing values. * * @return c_base_return_status * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. * * @see: c_base_session::save() */ public function set_session_id($session_id) { - if (!is_string($session_id) || empty($session_id)) { + if (!is_null($session_id) && (!is_string($session_id) || empty($session_id))) { $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'session_id', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); return c_base_return_error::s_false($error); } + if (is_null($session_id)) { + $this->session_id = NULL; + return new c_base_return_true(); + } + // deny 0-length session_id. if (mb_strlen($session_id) == 0) { $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'session_id', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); @@ -348,26 +593,33 @@ class c_base_session { /** * Returns the stored session id. * - * @return c_base_return_string - * The session id string. + * @return c_base_return_string|c_base_return_null + * The session id string or NULL if undefined. + * FALSE with the error bit set is returned on error. */ public function get_session_id() { + if (is_null($this->session_id)) { + return new c_base_return_null(); + } + return c_base_return_string::s_new($this->session_id); } /** * Assigns the session expiration timeout. * - * @param int $timeout_expire + * @param int|null $timeout_expire * The unix timestamp for the expiration timeout. + * Set to NULL to remove any existing values. * * @return c_base_return_status * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. * * @see: c_base_session::save() */ public function set_timeout_expire($timeout_expire) { - if (!is_int($timeout_expire)) { + if (!is_null($timeout_expire) && !is_int($timeout_expire)) { $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'timeout_expire', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); return c_base_return_error::s_false($error); } @@ -379,26 +631,33 @@ class c_base_session { /** * Returns the unix timestamp for the session expiration timeout. * - * @return c_base_return_int - * The unix timestamp for the session expiration timeout. + * @return c_base_return_int|c_base_return_null + * The unix timestamp for the session expiration timeout or NULL if undefined. + * FALSE with the error bit set is returned on error. */ public function get_timeout_expire() { + if (is_null($this->timeout_expire)) { + return new c_base_return_null(); + } + return c_base_return_int::s_new($this->timeout_expire); } /** * Assigns the max session timeout. * - * @param int $timeout_max + * @param int|null $timeout_max * The unix timestamp for the max session timeout. + * Set to NULL to remove any existing values. * * @return c_base_return_status * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. * * @see: c_base_session::save() */ public function set_timeout_max($timeout_max) { - if (!is_int($timeout_max)) { + if (!is_null($timeout_max) && !is_int($timeout_max)) { $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'timeout_max', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); return c_base_return_error::s_false($error); } @@ -410,18 +669,73 @@ class c_base_session { /** * Returns the unix timestamp for the max timeout. * - * @return c_base_return_int - * The unix timestamp for the max timeout. + * @return c_base_return_int|c_base_return_null + * The unix timestamp for the max timeout or NULL if undefined. + * FALSE with the error bit set is returned on error. */ public function get_timeout_max() { + if (is_null($this->timeout_max)) { + return new c_base_return_null(); + } + return c_base_return_int::s_new($this->timeout_max); } /** + * Assigns an array of form problems. + * + * @param array|null $problems + * An array of form problems. + * Set to NULL to remove any existing values. + * + * @return c_base_return_status + * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. + */ + public function set_problems($problems) { + if (!is_null($problems) && !is_array($problems)) { + $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'problems', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); + return c_base_return_error::s_false($error); + } + + $this->problems = array(); + + if (is_null($problems)) { + return new c_base_return_true(); + } + + foreach ($problems as $problem) { + if ($problem instanceof c_base_form_problem) { + $this->problems[] = $problem; + } + } + unset($problem); + + $this->problems = $problems; + return new c_base_return_true(); + } + + /** + * Returns the unix timestamp for the max timeout. + * + * @return c_base_return_array + * An array containing any problems associated with forms for this session. + * FALSE with the error bit set is returned on error. + */ + public function get_problems() { + if (is_null($this->problems)) { + $this->problems = array(); + } + + return c_base_return_array::s_new($this->problems); + } + + /** * Assigns the max session timeout. * - * @param int $seconds + * @param int|null $seconds * Number of seconds until timeout is reached. + * Set to NULL to remove any existing values. * @param int $microseconds * (optional) Number of microseconds until timeout is reached. * @param bool $receive @@ -430,11 +744,12 @@ class c_base_session { * * @return c_base_return_status * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. * * @see: socket_set_option() */ public function set_socket_timeout($seconds, $microseconds = 0, $receive = TRUE) { - if (!is_int($seconds) || $seconds < 0) { + if (!is_null($seconds) && (!is_int($seconds) || $seconds < 0)) { $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'seconds', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); return c_base_return_error::s_false($error); } @@ -449,6 +764,11 @@ class c_base_session { return c_base_return_error::s_false($error); } + if (is_null($seconds)) { + $this->socket_timeout = NULL; + return new c_base_return_true(); + } + if (!is_array($this->socket_timeout)) { $this->socket_timeout = array( 'send' => NULL, @@ -475,35 +795,18 @@ class c_base_session { /** * Returns the unix timestamp for the max timeout. * - * @return c_base_return_int - * The unix timestamp for the max timeout. + * @return c_base_return_int|c_base_return_null + * The unix timestamp for the max timeout or NULL if undefined. + * FALSE with the error bit set is returned on error. * * @see: socket_get_option() */ public function get_socket_timeout() { - return c_base_return_array::s_new($this->socket_timeout); - } - - /** - * Returns the stored error array. - * - * This should be called after a load() or a save() command to check to see if the socket returned any error. - * - * This does not return the socket error, for that use self::get_error_socket() - * - * @return c_base_return_array|c_base_return_status - * The error array or boolean returned by the socket when transferring data or NULL if there are no socket errors. - * A value of FALSE means that no error was returned by the socket. - * A value of an array() for both load() and save() would contain the socket error message. - * - * @see: self::get_error_socket() - */ - public function get_error() { - if (is_bool($this->error)) { - c_base_return_bool::s_new($this->error); + if (is_null($this->socket_timeout)) { + return new c_base_return_null(); } - return c_base_return_array::s_new($this->error); + return c_base_return_array::s_new($this->socket_timeout); } /** @@ -512,7 +815,8 @@ class c_base_session { * Use self::get_error() to get the error reported in the packet and not the socket. * * @return c_base_return_int - * Number representing the socket error. + * Number representing the socket error or NULL if undefined. + * FALSE with the error bit set is returned on error. * * @see: self::get_error() * @see: socket_last_error() @@ -531,6 +835,7 @@ class c_base_session { * * @return c_base_return_status * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. * * @see: self::get_error_socket() * @see: socket_clear_error() @@ -605,6 +910,7 @@ class c_base_session { * * @return c_base_return_status * TRUE on success, FALSE otherwise. + * FALSE with the error bit set is returned on error. */ public function do_disconnect() { if (!is_resource($this->socket)) { @@ -626,6 +932,7 @@ class c_base_session { * * @return c_base_return_status * TRUE when connected, FALSE otherwise. + * FALSE with the error bit set is returned on error. */ public function is_connected() { if (is_resource($this->socket)) { @@ -640,6 +947,7 @@ class c_base_session { * * @return c_base_return_status * TRUE on success, FALSE on failure. + * FALSE with the error bit set is returned on error. * * @see: c_base_session::do_connect() * @see: c_base_session::p_transfer() @@ -662,10 +970,10 @@ class c_base_session { $response = $this->p_transfer(array('ip' => $this->host, 'session_id' => $this->session_id)); if (c_base_return::s_has_error($response)) { - return $response->get_error(); + return c_base_return_error::s_false($response->get_error()); } - $response = c_base_return_array::s_value_exact($response); + $response = $response->get_value_exact(); if (empty($response['result']) || !is_array($response['result'])) { unset($response); @@ -724,6 +1032,7 @@ class c_base_session { * * @return c_base_return_status * TRUE on success, FALSE on failure. + * FALSE with the error bit set is returned on error. * * @see: c_base_session::set_name() * @see: c_base_session::set_host() @@ -814,6 +1123,7 @@ class c_base_session { * * @return c_base_return_status * TRUE on success, FALSE on failure. + * FALSE with the error bit set is returned on error. * * @see: self::do_connect() * @see: self::p_transfer() @@ -870,6 +1180,7 @@ class c_base_session { * * @return c_base_return_status * TRUE on success, FALSE on failure. + * FALSE with the error bit set is returned on error. * * @see: self::do_connect() * @see: self::p_transfer() @@ -882,7 +1193,7 @@ class c_base_session { $response = $this->p_transfer(array('flush' => TRUE)); if (c_base_return::s_has_error($response)) { - return $response->get_error(); + return c_base_return_error::s_false($response->get_error()); } $response = c_base_return_array::s_value_exact($response); @@ -906,13 +1217,11 @@ class c_base_session { * @return c_base_return_status|c_base_return_array * An array is returned on success. * FALSE is returned otherwise. + * FALSE with the error bit set is returned on error. * * @see: c_base_session::do_connect() */ private function p_transfer($request) { - unset($this->error); - $this->error = NULL; - $json = json_encode($request); $written = @socket_write($this->socket, $json); @@ -937,10 +1246,6 @@ class c_base_session { $response = json_decode($json, TRUE); unset($json); - if (isset($response['error'])) { - $this->error = $response['error']; - } - if ($response === FALSE) { $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'json_decode', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::OPERATION_FAILURE); return c_base_return_error::s_false($error); @@ -949,78 +1254,3 @@ class c_base_session { return c_base_return_array::s_new($response); } } - -/** - * A return class whose value is represented as a c_base_session. - */ -class c_base_session_return extends c_base_return_value { - use t_base_return_value_exact; - - /** - * @see: t_base_return_value::p_s_new() - */ - public static function s_new($value) { - return self::p_s_new($value, __CLASS__); - } - - /** - * @see: t_base_return_value::p_s_value() - */ - public static function s_value($return) { - return self::p_s_value($return, __CLASS__); - } - - /** - * @see: t_base_return_value_exact::p_s_value_exact() - */ - public static function s_value_exact($return) { - return self::p_s_value_exact($return, __CLASS__, new c_base_session()); - } - - /** - * Assign the value. - * - * @param c_base_session $value - * Any value so long as it is a c_base_session object. - * NULL is not allowed. - * - * @return c_base_return_status - * TRUE on success, FALSE otherwise. - */ - public function set_value($value) { - if (!($value instanceof c_base_session)) { - return FALSE; - } - - $this->value = $value; - return TRUE; - } - - /** - * Return the value. - * - * @return c_base_session $value - * The value array stored within this class. - */ - public function get_value() { - if (!($this->value instanceof c_base_session)) { - $this->value = NULL; - } - - return $this->value; - } - - /** - * Return the value of the expected type. - * - * @return c_base_session $value - * The value c_base_session stored within this class. - */ - public function get_value_exact() { - if (!($this->value instanceof c_base_session)) { - $this->value = new c_base_session(); - } - - return $this->value; - } -} diff --git a/common/theme/classes/theme_dom.php b/common/theme/classes/theme_dom.php index 129713b..39065d1 100644 --- a/common/theme/classes/theme_dom.php +++ b/common/theme/classes/theme_dom.php @@ -27,7 +27,7 @@ class c_theme_dom extends DOMDocument { * Class constructor. */ public function __construct() { - super.__construct('1.0', 'UTF-8'); + parent::__construct('1.0', 'UTF-8'); } /** diff --git a/common/theme/classes/theme_html.php b/common/theme/classes/theme_html.php index 49140f4..f51544d 100644 --- a/common/theme/classes/theme_html.php +++ b/common/theme/classes/theme_html.php @@ -24,7 +24,7 @@ require_once('common/base/classes/base_mime.php'); * There are amazing levels of inconsistency in HTML5, but for now this class implements HTML5 as closely as possible. * Future versions of this may violate the standard in favor of consistency and sanity. */ -class c_theme_html { +class c_theme_html extends c_base_return { const DEFAULT_MAX_RECURSION_DEPTH = 16384; private $html; @@ -36,6 +36,8 @@ class c_theme_html { * Class constructor. */ public function __construct() { + parent::__construct(); + $this->html = NULL; $this->markup = NULL; $this->http = NULL; @@ -50,6 +52,29 @@ class c_theme_html { unset($this->markup); unset($this->http); unset($this->max_recursion_depth); + + parent::__destruct(); + } + + /** + * @see: t_base_return_value::p_s_new() + */ + public static function s_new($value) { + return self::p_s_new($value, __CLASS__); + } + + /** + * @see: t_base_return_value::p_s_value() + */ + public static function s_value($return) { + return self::p_s_value($return, __CLASS__); + } + + /** + * @see: t_base_return_value_exact::p_s_value_exact() + */ + public static function s_value_exact($return) { + return self::p_s_value_exact($return, __CLASS__, ''); } /** @@ -62,7 +87,7 @@ class c_theme_html { * @param array|null $classes * (optional) An array of strings representing additional classes to append. * - * @return c_base_markup_tag_return|c_base_return_status + * @return c_base_markup_tag|c_base_return_status * A newly created tag is returned on success. * FALSE with the error bit set is returned on error. */ @@ -111,7 +136,7 @@ class c_theme_html { $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_CLASS, $class); unset($class); - return c_base_markup_tag_return::s_new($tag); + return $tag; } /** @@ -137,7 +162,7 @@ class c_theme_html { /** * Get the markup html assigned to this object. * - * @return c_base_html_return|c_base_return_status + * @return c_base_html|c_base_return_status * The markup html object. * FALSE is returned if no id is assigned. * FALSE with error bit set is returned on error. @@ -147,7 +172,7 @@ class c_theme_html { $this->html = new c_base_html(); } - return c_base_html_return::s_new($this->html); + return $this->html; } /** @@ -210,7 +235,7 @@ class c_theme_html { /** * Get the HTTP information * - * @return c_base_html_return|c_base_return_status + * @return c_base_http|c_base_return_status * The markup tags object. * FALSE is returned if no id is assigned. * FALSE with error bit set is returned on error. @@ -220,7 +245,7 @@ class c_theme_html { $this->http = new c_base_http(); } - return c_base_http_return::s_new($this->http); + return $this->http; } /** @@ -244,9 +269,9 @@ class c_theme_html { } /** - * Get the markup html assigned to this object. + * Get the maximum recursion depth integer assigned to this object. * - * @return c_base_html_return|c_base_return_status + * @return c_base_return_int|c_base_return_status * The markup html object. * FALSE is returned if no id is assigned. * FALSE with error bit set is returned on error. diff --git a/database/sql/reservation/base-associations.sql b/database/sql/reservation/base-associations.sql index 170fe3e..e71961a 100644 --- a/database/sql/reservation/base-associations.sql +++ b/database/sql/reservation/base-associations.sql @@ -6,7 +6,7 @@ start transaction; /** Custom database specific settings (do this on every connection made) **/ set bytea_output to hex; -set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,editors,drafters,requesters,users,public; set datestyle to us; @@ -14,12 +14,12 @@ set datestyle to us; /*** Associations ***/ create table managers.t_associations ( id bigint not null, - id_owner bigint not null, + id_manager bigint not null, id_group bigint, id_coordinator bigint not null, name_machine varchar(128) not null, - name_machine_owner varchar(128) not null, + name_machine_manager varchar(128) not null, name_machine_coordinator varchar(128) not null, name_human varchar(256) not null, @@ -37,7 +37,7 @@ create table managers.t_associations ( constraint cc_associations_id check (id > 0), - constraint cf_associations_id_owner foreign key (id_owner, name_machine_owner) references administers.t_users (id, name_machine) on delete restrict on update cascade, + constraint cf_associations_id_manager foreign key (id_manager, name_machine_manager) references administers.t_users (id, name_machine) on delete restrict on update cascade, constraint cf_associations_id_coordinator foreign key (id_coordinator, name_machine_coordinator) references administers.t_users (id, name_machine) on delete restrict on update cascade, constraint cf_associations_group foreign key (id_group) references managers.t_groups (id) on delete restrict on update cascade, constraint cf_associations_field_affiliation foreign key (field_affiliation) references managers.t_field_affiliations (id) on delete restrict on update cascade, @@ -58,8 +58,8 @@ grant usage on managers.s_associations_id to reservation_users; /*** provide current user access to their own information ***/ create view users.v_associations_self with (security_barrier=true) as with allowed_groups as (select id from users.v_groups_self) - select id, id_owner, id_group, id_coordinator, name_machine, name_machine_owner, name_machine_cooordinator, name_human, date_created, date_changed, field_affiliation, field_classification from managers.t_associations - where is_deleted is not true and ((group_id is null and (name_machine_owner)::text = (current_user)::text) or group_id in (select * from allowed_groups)); + select id, id_manager, id_group, id_coordinator, name_machine, name_machine_manager, name_machine_coordinator, name_human, date_created, date_changed, field_affiliation, field_classification from managers.t_associations + where is_deleted is not true and ((id_group is null and (name_machine_manager)::text = (current_user)::text) or id_group in (select * from allowed_groups)); grant select on users.v_associations_self to reservation_users; @@ -67,27 +67,25 @@ grant select on users.v_associations_self to reservation_users; /*** provide current user access to associations who they are assigned as the coordinator of ***/ create view users.v_associations_coordinator_self with (security_barrier=true) as with allowed_groups as (select id from users.v_groups_self) - select id, id_owner, id_group, id_coordinator, name_machine, name_machine_owner, name_machine_cooordinator, name_human, date_created, date_changed, field_affiliation, field_classification from managers.t_associations - where is_deleted is not true and (name_machine_coordinator)::text = (current_user)::text); + select id, id_manager, id_group, id_coordinator, name_machine, name_machine_manager, name_machine_coordinator, name_human, date_created, date_changed, field_affiliation, field_classification from managers.t_associations + where is_deleted is not true and (name_machine_coordinator)::text = (current_user)::text; grant select on users.v_associations_coordinator_self to reservation_users; /** provide current user access to insert their own associations **/ create view users.v_associations_self_insert with (security_barrier=true) as - with allowed_groups as (select id from users.v_groups_self) - select id, id_owner, id_group, id_coordinator, name_machine, name_machine_owner, name_machine_cooordinator, name_human, field_affiliation, field_classification from managers.t_associations - where is_deleted is not true and (group_id is null or group_id in (select * from allowed_groups)) and (name_machine_owner)::text = (current_user)::text + select id, id_manager, id_group, id_coordinator, name_machine, name_machine_manager, name_machine_coordinator, name_human, field_affiliation, field_classification from managers.t_associations + where is_deleted is not true and (id_group is null or id_group in (select id from users.v_groups_self)) and (name_machine_manager)::text = (current_user)::text with check option; grant insert on users.v_associations_self_insert to reservation_users; /** provide current user access to update their own associations **/ -create view public.v_associations_self_update with (security_barrier=true) as - with allowed_groups as (select id from users.v_groups_self) - select id, id_group, id_coordinator, name_machine, name_machine_cooordinator, name_human, date_changed, field_affiliation, field_classification from managers.t_associations - where is_deleted is not true and (group_id is null or group_id in (select * from allowed_groups)) and date_changed = localtimestamp and (name_machine_owner)::text = (current_user)::text +create view users.v_associations_self_update with (security_barrier=true) as + select id, id_group, id_coordinator, name_machine, name_machine_coordinator, name_human, date_changed, field_affiliation, field_classification from managers.t_associations + where is_deleted is not true and (id_group is null or id_group in (select id from users.v_groups_self)) and date_changed = localtimestamp and (name_machine_manager)::text = (current_user)::text with check option; grant insert on users.v_associations_self_update to reservation_users; diff --git a/database/sql/reservation/base-fields.sql b/database/sql/reservation/base-fields.sql index acce227..4d309d2 100644 --- a/database/sql/reservation/base-fields.sql +++ b/database/sql/reservation/base-fields.sql @@ -6,7 +6,7 @@ start transaction; /** Custom database specific settings (do this on every connection made) **/ set bytea_output to hex; -set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,editors,drafters,requesters,users,public; set datestyle to us; diff --git a/database/sql/reservation/base-first.sql b/database/sql/reservation/base-first.sql index 2bf5e64..84f29f6 100644 --- a/database/sql/reservation/base-first.sql +++ b/database/sql/reservation/base-first.sql @@ -14,7 +14,9 @@ create role reservation_users_publisher inherit nologin; create role reservation_users_insurer inherit nologin; create role reservation_users_financer inherit nologin; create role reservation_users_reviewer inherit nologin; +create role reservation_users_editor inherit nologin; create role reservation_users_drafter inherit nologin; +create role reservation_users_requester inherit nologin; grant reservation_users to reservation_users_administer with admin option; grant reservation_users to reservation_users_manager with admin option; @@ -23,7 +25,9 @@ grant reservation_users to reservation_users_publisher; grant reservation_users to reservation_users_insurer; grant reservation_users to reservation_users_financer; grant reservation_users to reservation_users_reviewer; +grant reservation_users to reservation_users_editor; grant reservation_users to reservation_users_drafter; +grant reservation_users to reservation_users_requester; grant reservation_users_manager to reservation_users_administer with admin option; @@ -42,9 +46,15 @@ grant reservation_users_financer to reservation_users_manager with admin option; grant reservation_users_reviewer to reservation_users_administer with admin option; grant reservation_users_reviewer to reservation_users_manager with admin option; +grant reservation_users_editor to reservation_users_administer with admin option; +grant reservation_users_editor to reservation_users_manager with admin option; + grant reservation_users_drafter to reservation_users_administer with admin option; grant reservation_users_drafter to reservation_users_manager with admin option; +grant reservation_users_requester to reservation_users_administer with admin option; +grant reservation_users_requester to reservation_users_manager with admin option; + /** This is the role the database should use to connect to to perform system activity **/ create role reservation_user; diff --git a/database/sql/reservation/base-groups.sql b/database/sql/reservation/base-groups.sql index 72f317b..0d0b020 100644 --- a/database/sql/reservation/base-groups.sql +++ b/database/sql/reservation/base-groups.sql @@ -6,17 +6,24 @@ start transaction; /** Custom database specific settings (do this on every connection made) **/ set bytea_output to hex; -set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,editors,drafters,requesters,users,public; set datestyle to us; +/* Note about composite groups (is_composite) + Instead of having an array of multiple groups assigned to one entity or having a table of group and entity associates, use a group that logically represents multiple groups. + For example, if I want to add both group_1 and group_2 to entity_a, then I can create group_3 and put all users from group_1 and group_2 in it. + @todo: I will likely need to create a composite groups table to manage the relations between a composite group and its non-composites for management purposes. + + @todo: with this composite groups design, I can get rid of the user to groups table and need users only to be assigned to a single (composite) group. + the current flaw with this design may be with access control in creating or auto-creating composite groups. +*/ /** Groups **/ create table managers.t_groups ( id bigint not null, id_sort smallint not null default 0, id_external bigint, - id_creator bigint not null, id_manager bigint, name_machine varchar(128) not null, @@ -31,6 +38,9 @@ create table managers.t_groups ( is_deleted boolean default false not null, is_locked boolean default false not null, + is_composite boolean default false not null, + + can_manage_paths boolean default false not null, settings json, @@ -43,7 +53,6 @@ create table managers.t_groups ( constraint cu_groups_name_machine unique (name_machine), constraint cu_groups_user unique (id, name_machine), - constraint cf_t_groups_creator foreign key (id_creator, name_machine_creator) references administers.t_users (id, name_machine) on delete restrict on update cascade, constraint cf_t_groups_manager foreign key (id_manager, name_machine_manager) references administers.t_users (id, name_machine) on delete restrict on update cascade ); @@ -88,7 +97,7 @@ create index ci_groups_id_sort_z on managers.t_groups (id_sort) with (fillfactor /** Groups to Users Association **/ -create table managers.t_groups_users ( +create table managers.t_group_users ( id_user bigint not null, id_group bigint not null, @@ -96,8 +105,8 @@ create table managers.t_groups_users ( constraint cu_groups_id unique (id_user, id_group), - constraint cf_t_groups_users_user foreign key (id_user, name_machine_user) references administers.t_users (id, name_machine) on delete cascade on update cascade, - constraint cf_t_groups_users_group foreign key (id_group) references managers.t_groups (id) on delete cascade on update cascade + constraint cf_t_group_users_user foreign key (id_user, name_machine_user) references administers.t_users (id, name_machine) on delete cascade on update cascade, + constraint cf_t_group_users_group foreign key (id_group) references managers.t_groups (id) on delete cascade on update cascade ); grant select,insert,update on managers.t_groups to reservation_users_administer; @@ -105,32 +114,59 @@ grant select,insert,update on managers.t_groups to reservation_users_manager; grant select on managers.t_groups to reservation_users_auditor; +/*** provide group manages access to manage users assigned to their groups ***/ +create view users.v_group_users_manage with (security_barrier=true) as + select gu.id_user, gu.id_group from managers.t_group_users gu + inner join managers.t_groups g on g.id = gu.id_group + where g.is_deleted is not true and (g.name_machine_manager)::text = (current_user)::text; + +grant select, insert, update, delete on users.v_group_users_manage to reservation_users; + + /*** provide current user access to their own information ***/ create view users.v_groups_self with (security_barrier=true) as - select g.id, g.id_sort, g.id_external, g.id_creator, g.id_manager, g.name_machine, g.name_human, g.is_locked, g.date_created, g.date_changed, g.date_synced, g.settings from managers.t_groups g - inner join managers.t_groups_users gu on g.id = gu.id_group + select g.id, g.id_sort, g.id_external, g.id_manager, g.name_machine, g.name_human, g.is_locked, g.is_composite, g.date_created, g.date_changed, g.date_synced, g.can_manage_paths, g.settings from managers.t_groups g + inner join managers.t_group_users gu on g.id = gu.id_group where g.is_deleted is not true and (gu.name_machine_user)::text = (current_user)::text; grant select on users.v_groups_self to reservation_users; -/*** provide group manages access to manage users assigned to their groups ***/ -create view users.v_groups_users_manage with (security_barrier=true) as - select gu.id_user, gu.id_group from managers.t_groups_users gu - inner join managers.t_groups g on g.id = gu.id_group - where g.is_deleted is not true and (gu.name_machine_manager)::text = (current_user)::text; - -grant select, insert, update, delete on users.v_groups_self to reservation_users; - - /*** provide group manages access to manage users their groups ***/ create view users.v_groups_manage with (security_barrier=true) as - select g.id, g.id_sort, g.id_external, g.name_machine, g.name_human, g.is_locked, g.date_changed, g.date_synced, g.settings from managers.t_groups g - inner join managers.t_groups_users gu on g.id = gu.id_group - where g.is_deleted is not true and date_changed = localtimestamp and (date_synced is null or date_synced = localtimestamp) and (gu.name_machine_user)::text = (current_user)::text; + select g.id, g.id_sort, g.id_external, g.name_machine, g.name_human, g.is_locked, g.is_composite, g.date_changed, g.date_synced, g.can_manage_paths, g.settings from managers.t_groups g + inner join managers.t_group_users gu on g.id = gu.id_group + where g.is_deleted is not true and (date_changed is null or date_changed = localtimestamp) and (date_synced is null or date_synced = localtimestamp) and (gu.name_machine_user)::text = (current_user)::text; grant select, insert, update on users.v_groups_manage to reservation_users; + +/** Groups Composites **/ +create table managers.t_group_composites ( + id_composite bigint not null, + id_group bigint not null, + + constraint cu_group_composites_id unique (id_composite, id_group), + + constraint cf_t_group_composites_composite foreign key (id_composite) references managers.t_groups (id) on delete cascade on update cascade, + constraint cf_t_group_composites_group foreign key (id_group) references managers.t_groups (id) on delete cascade on update cascade +); + +grant select,insert,update on managers.t_groups to reservation_users_administer; +grant select,insert,update on managers.t_groups to reservation_users_manager; +grant select on managers.t_groups to reservation_users_auditor; + + +/*** provide group manages access to composite groups containing groups they belong to. ***/ +create view users.v_group_composites with (security_barrier=true) as + with allowed_groups as (select id from users.v_groups_self) + select gc.id_composite, gc.id_group from managers.t_group_composites gc + inner join managers.t_groups g on g.id = gc.id_group + where g.is_deleted is not true and (g.is_locked is not true or (g.name_machine_manager)::text = (current_user)::text) and ((g.name_machine_manager)::text = (current_user)::text or gc.id_group in (select * from allowed_groups)); + +grant select on users.v_group_composites to reservation_users; + + commit transaction; diff --git a/database/sql/reservation/base-log_groups.sql b/database/sql/reservation/base-log_groups.sql index 5e91e4a..61dfb60 100644 --- a/database/sql/reservation/base-log_groups.sql +++ b/database/sql/reservation/base-log_groups.sql @@ -6,7 +6,7 @@ start transaction; /** Custom database specific settings (do this on every connection made) **/ set bytea_output to hex; -set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,editors,drafters,requesters,users,public; set datestyle to us; @@ -29,7 +29,7 @@ create table managers.t_log_groups ( constraint cf_log_groups_id_user foreign key (id_user, name_machine_user) references administers.t_users (id, name_machine) on delete restrict on update cascade, constraint cf_log_groups_id_group foreign key (id_group) references managers.t_groups (id) on delete restrict on update cascade, - constraint cf_log_groups_log_type foreign key (log_type) references managers.t_log_types (id) on delete restrict on update cascade, + constraint cf_log_groups_log_type foreign key (log_type) references managers.t_log_types (id) on delete restrict on update cascade ); create sequence managers.s_log_groups_id owned by managers.t_log_groups.id; @@ -44,7 +44,7 @@ grant usage on managers.s_log_groups_id to reservation_users; /** only allow select and insert for users when user id is current user **/ create view users.v_log_groups_self with (security_barrier=true) as - gselect id, id_user, id_group, log_type, log_details, log_date from managers.t_log_groups + select id, id_user, id_group, log_type, log_details, log_date from managers.t_log_groups where (name_machine_user)::text = (current_user)::text; grant select on users.v_log_groups_self to reservation_users; @@ -59,7 +59,7 @@ grant insert on users.v_log_groups_self_insert to reservation_users; /*** provide group user activity logging ***/ -create table managers.t_log_groups_users ( +create table managers.t_log_group_users ( id bigint not null, id_user bigint default 1 not null, id_group bigint not null, @@ -69,38 +69,38 @@ create table managers.t_log_groups_users ( log_type bigint not null, log_date timestamp default localtimestamp not null, - constraint cp_log_groups_id primary key (id), + constraint cp_log_group_users_id primary key (id), - constraint cc_log_groups_id check (id > 0), + constraint cc_log_group_users_id check (id > 0), - constraint cf_log_groups_id_user foreign key (id_user, name_machine_user) references administers.t_users (id, name_machine) on delete restrict on update cascade, - constraint cf_log_groups_id_group foreign key (id_group) references managers.t_groups (id) on delete restrict on update cascade, - constraint cf_log_groups_log_type foreign key (log_type) references managers.t_log_types (id) on delete restrict on update cascade, + constraint cf_log_group_users_id_user foreign key (id_user, name_machine_user) references administers.t_users (id, name_machine) on delete restrict on update cascade, + constraint cf_log_group_users_id_group foreign key (id_group) references managers.t_groups (id) on delete restrict on update cascade, + constraint cf_log_group_users_log_type foreign key (log_type) references managers.t_log_types (id) on delete restrict on update cascade ); -create sequence managers.s_log_groups_users_id owned by managers.t_log_groups_users.id; -alter table managers.t_log_groups_users alter column id set default nextval('managers.s_log_groups_users_id'::regclass); +create sequence managers.s_log_group_users_id owned by managers.t_log_group_users.id; +alter table managers.t_log_group_users alter column id set default nextval('managers.s_log_group_users_id'::regclass); -grant select on managers.t_log_groups_users to reservation_users_administer; -grant select on managers.t_log_groups_users to reservation_users_manager; -grant select on managers.t_log_groups_users to reservation_users_auditor; -grant select,usage on managers.s_log_groups_users_id to reservation_users_administer; -grant usage on managers.s_log_groups_users_id to reservation_users; +grant select on managers.t_log_group_users to reservation_users_administer; +grant select on managers.t_log_group_users to reservation_users_manager; +grant select on managers.t_log_group_users to reservation_users_auditor; +grant select,usage on managers.s_log_group_users_id to reservation_users_administer; +grant usage on managers.s_log_group_users_id to reservation_users; /** only allow select and insert for users when user id is current user **/ -create view users.v_log_groups_users_self with (security_barrier=true) as - select id, id_user, id_group, log_type, log_date from managers.t_log_groups_users +create view users.v_log_group_users_self with (security_barrier=true) as + select id, id_user, id_group, log_type, log_date from managers.t_log_group_users where (name_machine_user)::text = (current_user)::text; -grant select on users.v_log_groups_users_self to reservation_users; +grant select on users.v_log_group_users_self to reservation_users; -create view users.v_log_groups_users_self_insert with (security_barrier=true) as - select id_user, id_group, name_machine_user, log_type from managers.t_log_groups_users +create view users.v_log_group_users_self_insert with (security_barrier=true) as + select id_user, id_group, name_machine_user, log_type from managers.t_log_group_users where (name_machine_user)::text = (current_user)::text with check option; -grant insert on users.v_log_groups_users_self_insert to reservation_users; +grant insert on users.v_log_group_users_self_insert to reservation_users; diff --git a/database/sql/reservation/base-log_problems.sql b/database/sql/reservation/base-log_problems.sql index 19ded9b..abb1e25 100644 --- a/database/sql/reservation/base-log_problems.sql +++ b/database/sql/reservation/base-log_problems.sql @@ -6,7 +6,7 @@ start transaction; /** Custom database specific settings (do this on every connection made) **/ set bytea_output to hex; -set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,editors,drafters,requesters,users,public; set datestyle to us; @@ -29,9 +29,9 @@ create table managers.t_log_problems ( constraint cu_log_problems_name_machine unique (name_machine) ); -grant select on managers.t_log_activity to reservation_users_administer; -grant select on managers.t_log_activity to reservation_users_manager; -grant select on managers.t_log_activity to reservation_users_auditor; +grant select on managers.t_log_problems to reservation_users_administer; +grant select on managers.t_log_problems to reservation_users_manager; +grant select on managers.t_log_problems to reservation_users_auditor; @@ -66,7 +66,7 @@ create view users.v_log_problems_users_self with (security_barrier=true) as select id_problem, id_user, date_created, log_details from managers.t_log_problems_users where (name_machine_user)::text = (current_user)::text; -grant select on users.v_log_activity_self to reservation_users; +grant select on users.v_log_problems_users_self to reservation_users; create view users.v_log_problems_users_self_insert with (security_barrier=true) as select id_problem, id_user, name_machine_user, log_details from managers.t_log_problems_users diff --git a/database/sql/reservation/base-log_types.sql b/database/sql/reservation/base-log_types.sql index dd43b4b..5ea2a47 100644 --- a/database/sql/reservation/base-log_types.sql +++ b/database/sql/reservation/base-log_types.sql @@ -6,7 +6,7 @@ start transaction; /** Custom database specific settings (do this on every connection made) **/ set bytea_output to hex; -set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,editors,drafters,requesters,users,public; set datestyle to us; @@ -18,6 +18,7 @@ create table managers.t_log_types ( name_machine varchar(128) not null, name_human varchar(256) not null, + is_locked boolean default false not null, is_deleted boolean default false not null, date_created timestamp default localtimestamp not null, @@ -39,8 +40,15 @@ grant select on managers.t_log_types to reservation_users_manager; grant select on managers.t_log_types to reservation_users_auditor; grant select,usage on managers.s_log_types_id to reservation_users_administer; +create index ci_log_types_deleted_not on managers.t_log_types (id) + where is_deleted is not true; + +create index ci_log_types_public on managers.t_log_types (id) + where is_deleted is not true and is_locked is not true; + create view public.v_log_types with (security_barrier=true) as - select id, name_machine, name_human from managers.t_log_types; + select id, name_machine, name_human from managers.t_log_types + where is_deleted is not true and is_locked is not true; grant select on public.v_log_types to reservation_users; grant select on public.v_log_types to public_users; diff --git a/database/sql/reservation/base-log_users.sql b/database/sql/reservation/base-log_users.sql index d938c73..d3996ab 100644 --- a/database/sql/reservation/base-log_users.sql +++ b/database/sql/reservation/base-log_users.sql @@ -4,6 +4,13 @@ start transaction; +/** Custom database specific settings (do this on every connection made) **/ +set bytea_output to hex; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,editors,drafters,requesters,users,public; +set datestyle to us; + + + /*** provide user activity logging ***/ create table managers.t_log_users ( id bigint not null, @@ -110,19 +117,16 @@ create index ci_log_users_response_code_redirects on managers.t_log_users (id) create index ci_log_users_response_code_notable on managers.t_log_users (id) where response_code in (400, 403, 404, 410, 500, 503); -/** when using current_user reserved function/word the index gets ignored. To prevent this, create a manual/custom index and alter the behavior of the views to be more explicit. **/ -create unique index ci_log_users_current_user on managers.t_log_users (name_machine_user) with (fillfactor = 100); - /** only allow select and insert for users when user id is current user **/ create view users.v_log_users_self with (security_barrier=true) as - select id, id_user, log_title, log_type, log_severity, log_details, log_date, request_client from managers.t_log_users + select id, id_user, log_title, log_type, log_severity, log_details, log_date, request_client, response_code from managers.t_log_users where (name_machine_user)::text = (current_user)::text; grant select on users.v_log_users_self to reservation_users; create view users.v_log_users_self_insert with (security_barrier=true) as - select id_user, name_machine_user, log_title, log_type, log_severity, log_details, request_client from managers.t_log_users + select id_user, name_machine_user, log_title, log_type, log_severity, log_details, request_client, response_code from managers.t_log_users where (name_machine_user)::text = (current_user)::text with check option; @@ -131,7 +135,7 @@ grant insert on users.v_log_users_self_insert to reservation_users; /** only allow insert for the public user **/ create view public.v_log_users_self_insert with (security_barrier=true) as - select id_user, name_machine_user, log_title, log_type, log_severity, log_details, request_client from managers.t_log_users + select id_user, name_machine_user, log_title, log_type, log_severity, log_details, request_client, response_code from managers.t_log_users where id_user = 1 and name_machine_user = 'unknown' with check option; @@ -140,7 +144,7 @@ grant insert on public.v_log_users_self_insert to public_users; /** only allow insert for the system user **/ create view system.v_log_users_self_insert with (security_barrier=true) as - select id_user, name_machine_user, log_title, log_type, log_severity, log_details, request_client from managers.t_log_users + select id_user, name_machine_user, log_title, log_type, log_severity, log_details, request_client, response_code from managers.t_log_users where id_user = 2 and name_machine_user = 'system' with check option; @@ -206,8 +210,6 @@ create index ci_log_activity_response_code_503 on managers.t_log_activity (id) create index ci_log_activity_response_code_notable on managers.t_log_activity (id) where response_code in (403, 404, 410, 500, 503); -/** when using current_user reserved function/word the index gets ignored. To prevent this, create a manual/custom index and alter the behavior of the views to be more explicit. **/ -create unique index ci_log_activity_current_user on managers.t_log_activity (name_machine_user) with (fillfactor = 100); /** only allow select and insert for users when user id is current user **/ diff --git a/database/sql/reservation/base-main.sql b/database/sql/reservation/base-main.sql index 33b2ee2..266af79 100644 --- a/database/sql/reservation/base-main.sql +++ b/database/sql/reservation/base-main.sql @@ -15,7 +15,7 @@ start transaction; /** Custom database specific settings (do this on every connection made) **/ set bytea_output to hex; -set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,editors,drafters,requesters,users,public; set datestyle to us; @@ -29,7 +29,9 @@ create schema publishers authorization reservation_users_publisher; create schema insurer authorization reservation_users_insurer; create schema financer authorization reservation_users_financer; create schema reviewers authorization reservation_users_reviewer; +create schema editors authorization reservation_users_editor; create schema drafters authorization reservation_users_drafter; +create schema requesters authorization reservation_users_requester; create schema users authorization reservation_users; revoke create on schema system from reservation_user; @@ -40,7 +42,9 @@ revoke create on schema publishers from reservation_users_publisher; revoke create on schema insurer from reservation_users_insurer; revoke create on schema financer from reservation_users_financer; revoke create on schema reviewers from reservation_users_reviewer; +revoke create on schema editors from reservation_users_editor; revoke create on schema drafters from reservation_users_drafter; +revoke create on schema requesters from reservation_users_requester; revoke create on schema users from reservation_users; grant usage on schema system to reservation_user; @@ -51,7 +55,9 @@ grant usage on schema publishers to reservation_users_publisher; grant usage on schema insurer to reservation_users_insurer; grant usage on schema financer to reservation_users_financer; grant usage on schema reviewers to reservation_users_reviewer; +grant usage on schema editors to reservation_users_editor; grant usage on schema drafters to reservation_users_drafter; +grant usage on schema requesters to reservation_users_requester; grant usage on schema users to reservation_users; grant create,usage on schema system to postgres; @@ -62,7 +68,9 @@ grant create,usage on schema publishers to postgres; grant create,usage on schema insurer to postgres; grant create,usage on schema financer to postgres; grant create,usage on schema reviewers to postgres; +grant create,usage on schema editors to postgres; grant create,usage on schema drafters to postgres; +grant create,usage on schema requesters to postgres; grant create,usage on schema users to postgres; diff --git a/database/sql/reservation/base-paths.sql b/database/sql/reservation/base-paths.sql index f45d3db..d263a92 100644 --- a/database/sql/reservation/base-paths.sql +++ b/database/sql/reservation/base-paths.sql @@ -1,5 +1,5 @@ /** Standardized SQL Structure - Content **/ -/** This depends on: base-structure.sql **/ +/** This depends on: base-groups.sql **/ start transaction; @@ -11,4 +11,113 @@ set datestyle to us; +/*** provide path type id and names ***/ +create table managers.t_path_types ( + id bigint not null, + + name_machine varchar(128) not null, + name_human varchar(256) not null, + + is_locked boolean default false not null, + is_deleted boolean default false not null, + + date_created timestamp default localtimestamp not null, + date_changed timestamp default localtimestamp not null, + date_deleted timestamp, + + constraint cp_path_types_id primary key (id), + + constraint cu_path_types_user unique (name_machine), + + constraint cc_path_types_id check (id > 0) +); + +create sequence managers.s_path_types_id owned by managers.t_path_types.id; +alter table managers.t_path_types alter column id set default nextval('managers.s_path_types_id'::regclass); + +grant select,insert,update on managers.t_path_types to reservation_users_administer; +grant select on managers.t_path_types to reservation_users_manager; +grant select on managers.t_path_types to reservation_users_auditor; +grant select,usage on managers.s_path_types_id to reservation_users_administer; + +create index ci_path_types_deleted_not on managers.t_path_types (id) + where is_deleted is not true; + +create index ci_path_types_public on managers.t_path_types (id) + where is_deleted is not true and is_locked is not true; + +create view public.v_path_types with (security_barrier=true) as + select id, name_machine, name_human from managers.t_path_types + where is_deleted is not true and is_locked is not true; + +grant select on public.v_path_types to reservation_users; +grant select on public.v_path_types to public_users; + + +/* @todo: pre-populate the path types. */ + + +/* @todo: with its current design, the id_access field needs a trigger to maintain its up to date status if/when group ids change. */ +/* @todo: come up with a design for dynamic path management via users/managers (as opposed to hardcoded paths in source). */ +/*** provide paths table (@todo: this is added as a stub and needs to be finished) ***/ +create table managers.t_paths ( + id bigint not null, + id_type bigint not null, + id_group bigint, + + name_machine varchar(128) not null, + name_human varchar(256) not null, + + is_private boolean default true not null, + is_locked boolean default false not null, + is_deleted boolean default false not null, + + date_created timestamp default localtimestamp not null, + date_changed timestamp default localtimestamp not null, + date_deleted timestamp, + + constraint cp_paths_id primary key (id), + + constraint cu_paths_name_machine unique (name_machine), + + constraint cc_paths_id check (id > 0), + + constraint cf_paths_id_type foreign key (id_type) references managers.t_path_types (id) on delete restrict on update cascade, + constraint cf_paths_id_group foreign key (id_group) references managers.t_groups (id) on delete restrict on update cascade +); + +create sequence managers.s_paths_id owned by managers.t_paths.id; +alter table managers.t_paths alter column id set default nextval('managers.s_paths_id'::regclass); + +grant select on managers.t_paths to reservation_users_administer; +grant select on managers.t_paths to reservation_users_manager; +grant select on managers.t_paths to reservation_users_auditor; +grant select,usage on managers.s_paths_id to reservation_users_administer; +grant usage on managers.s_paths_id to reservation_users; + +create index ci_paths_deleted_not on managers.t_paths (id) + where is_deleted is not true; + +create index ci_paths_private_not on managers.t_paths (id) + where is_deleted is not true and is_private is not true; + +create index ci_paths_locked_not on managers.t_paths (id) + where is_deleted is not true and is_locked is not true; + +create index ci_paths_public on managers.t_paths (id) + where is_deleted is not true and is_locked is not true and is_private is not true; + +create view users.v_paths with (security_barrier=true) as + with allowed_groups as (select id from users.v_groups_self) + select id, id_type, id_group, name_machine, name_human, is_private from managers.t_paths + where is_deleted is not true and (is_locked is not true or id_group in (select * from allowed_groups)) and (is_private is not true or (is_private is true and id_group in (select * from allowed_groups))); + +grant select on users.v_paths to reservation_users; + +create view public.v_paths with (security_barrier=true) as + select id, id_type, name_machine, name_human from managers.t_paths + where is_deleted is not true and is_locked is not true and is_private is not true; + +grant select on public.v_path_types to public_users; + commit transaction; diff --git a/database/sql/reservation/base-requests.sql b/database/sql/reservation/base-requests.sql index 24f3129..49279fd 100644 --- a/database/sql/reservation/base-requests.sql +++ b/database/sql/reservation/base-requests.sql @@ -6,7 +6,7 @@ start transaction; /** Custom database specific settings (do this on every connection made) **/ set bytea_output to hex; -set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,editors,drafters,requesters,users,public; set datestyle to us; @@ -19,6 +19,7 @@ create table managers.t_request_types ( name_machine varchar(128) not null, name_human varchar(256) not null, + is_locked boolean default false not null, is_deleted boolean default false not null, date_created timestamp default localtimestamp not null, @@ -40,11 +41,17 @@ grant select on managers.t_request_types to reservation_users_auditor; grant select,usage on managers.s_request_types_id to reservation_users_administer; grant select,usage on managers.s_request_types_id to reservation_users_manager; -create view users.v_request_types with (security_barrier=true) as +create index ci_request_types_deleted_not on managers.t_request_types (id) + where is_deleted is not true; + +create index ci_request_types_public on managers.t_request_types (id) + where is_deleted is not true and is_locked is not true; + +create view requesters.v_request_types with (security_barrier=true) as select id, id_external, name_machine, name_human from managers.t_request_types - where is_deleted is false; + where is_deleted is not true and is_locked is not true; -grant select on users.v_request_types to reservation_users; +grant select on requesters.v_request_types to reservation_users_requester; /** @todo: consider creating default request types **/ @@ -53,12 +60,13 @@ grant select on users.v_request_types to reservation_users; /*** Requests ***/ create table managers.t_requests ( id bigint not null, - id_owner bigint not null, id_revision bigint not null, id_type bigint not null, + id_association bigint not null, + id_creator bigint not null, name_machine varchar(128) not null, - name_machine_owner varchar(128) not null, + name_machine_creator varchar(128) not null, name_human varchar(256) not null, is_approved boolean default false not null, @@ -116,7 +124,7 @@ create table managers.t_requests ( field_setup_round_tables_8ft public.ct_field_needed_with_total not null, field_setup_security public.ct_field_needed_with_details not null, field_setup_special_requests public.ct_field_needed_with_details not null, - field_setup_standard_blue_chairs public.ct_field_needed_with_total not null; + field_setup_standard_blue_chairs public.ct_field_needed_with_total not null, field_services_alcohol_served public.ct_field_served_with_caterer not null, field_services_food public.ct_field_served_with_caterer not null, field_services_open_flames public.ct_field_used_with_details not null, @@ -129,9 +137,11 @@ create table managers.t_requests ( constraint cu_requests_name_machine unique (name_machine), constraint cc_requests_id check (id > 0), + constraint cc_requests_approved check ((is_approved is true and is_denied is not true) or (is_approved is not true and is_denied is true)), - constraint cf_requests_id_owner foreign key (id_owner, name_machine_owner) references administers.t_users (id, name_machine) on delete restrict on update cascade, - constraint cf_requests_request_type foreign key (id_type) references managers.t_request_types (id) on delete restrict on update cascade + constraint cf_requests_id_creator foreign key (id_creator, name_machine_creator) references administers.t_users (id, name_machine) on delete restrict on update cascade, + constraint cf_requests_request_type foreign key (id_type) references managers.t_request_types (id) on delete restrict on update cascade, + constraint cf_requests_association foreign key (id_association) references managers.t_associations (id) on delete restrict on update cascade ); create sequence managers.s_requests_id owned by managers.t_requests.id; @@ -145,9 +155,43 @@ grant select,usage on managers.s_requests_id to reservation_users_manager; grant usage on managers.s_requests_id to reservation_users; -/** @todo: create all appropriate views, including individual views for is_cancelled, is_deleted, is_published, is_unpublished, is_denied, and is_troubled **/ +/** @todo: create all appropriate views (and indexes), including individual views for is_cancelled, is_deleted, is_published, is_unpublished, is_denied, and is_troubled **/ +create index ci_requests_deleted_not on managers.t_requests (id) + where is_deleted is not true; + +create index ci_requests_approved on managers.t_requests (id) + where is_deleted is not true and is_cancelled is not true and is_approved is true; + +create index ci_requests_approved_cancelled on managers.t_requests (id) + where is_deleted is not true and is_cancelled is true and is_approved is true; + + +/*** approved requests (but not cancelled) ***/ +create view users.v_requests_approved with (security_barrier=true) as + select id, id_revision, id_type, id_association, name_machine, name_human, is_troubled, date_created, date_changed, field_additional, field_dates, field_fees_custodial, field_fees_equipment, field_fees_facilities, field_fees_grounds, field_fees_maintenance, field_fees_other, field_fees_security, field_fees_university, field_location, field_information_attendance, field_information_organization, field_information_adviser_approval, field_insurance_affiliated, field_insurance_contractor, field_insurance_unaffiliated, field_plans_activities, field_plans_audience, field_plans_description, field_presentation_designing_material, field_presentation_external_audio_person, field_presentation_production, field_presentation_printed_material, field_presentation_publicity, field_presentation_technical_equipment, field_presentation_university_logo, field_registration_revenue, field_registration_phone, field_registration_required, field_registration_ticket_dates, field_registration_ticket_phone, field_registration_ticket_price, field_registration_ticket_website, field_registration_website, field_setup_other_tables, field_setup_parking_assistance, field_setup_podium, field_setup_portable_stage, field_setup_rectangular_tables_8ft, field_setup_road_closures, field_setup_round_tables_8ft, field_setup_security, field_setup_special_requests, field_setup_standard_blue_chairs, field_services_alcohol_served, field_services_food, field_services_open_flames, field_title, in_state, in_step from managers.t_requests + where is_deleted is not true and is_cancelled is not true and is_approved is true; + +grant select on users.v_requests_approved to reservation_users; + + +/*** approved requests (only cancelled) ***/ +create view users.v_requests_approved_cancelled with (security_barrier=true) as + select id, id_revision, id_type, id_association, name_machine, name_human, is_troubled, date_created, date_changed, field_additional, field_dates, field_fees_custodial, field_fees_equipment, field_fees_facilities, field_fees_grounds, field_fees_maintenance, field_fees_other, field_fees_security, field_fees_university, field_location, field_information_attendance, field_information_organization, field_information_adviser_approval, field_insurance_affiliated, field_insurance_contractor, field_insurance_unaffiliated, field_plans_activities, field_plans_audience, field_plans_description, field_presentation_designing_material, field_presentation_external_audio_person, field_presentation_production, field_presentation_printed_material, field_presentation_publicity, field_presentation_technical_equipment, field_presentation_university_logo, field_registration_revenue, field_registration_phone, field_registration_required, field_registration_ticket_dates, field_registration_ticket_phone, field_registration_ticket_price, field_registration_ticket_website, field_registration_website, field_setup_other_tables, field_setup_parking_assistance, field_setup_podium, field_setup_portable_stage, field_setup_rectangular_tables_8ft, field_setup_road_closures, field_setup_round_tables_8ft, field_setup_security, field_setup_special_requests, field_setup_standard_blue_chairs, field_services_alcohol_served, field_services_food, field_services_open_flames, field_title, in_state, in_step from managers.t_requests + where is_deleted is not true and is_cancelled is true and is_approved is true; + +grant select on users.v_requests_approved to reservation_users; + + +/*** requests the current user can manage (do determine this, the associations table is join and because it is already joined, add the additional fields provided by assocation). ***/ +/* @todo: review this to see if I can come up with a better way than doing an inner join on associations. */ +create view users.v_requests_self with (security_barrier=true) as + select r.id, r.id_revision, r.id_type, r.id_association, a.id_group, a.id_coordinator, r.name_machine, a.name_machine_coordinator, r.name_human, a.name_human as name_human_association, r.is_troubled, r.date_created, r.date_changed, r.field_additional, r.field_dates, r.field_fees_custodial, r.field_fees_equipment, r.field_fees_facilities, r.field_fees_grounds, r.field_fees_maintenance, r.field_fees_other, r.field_fees_security, r.field_fees_university, r.field_location, r.field_information_attendance, r.field_information_organization, r.field_information_adviser_approval, r.field_insurance_affiliated, r.field_insurance_contractor, r.field_insurance_unaffiliated, r.field_plans_activities, r.field_plans_audience, r.field_plans_description, r.field_presentation_designing_material, r.field_presentation_external_audio_person, r.field_presentation_production, r.field_presentation_printed_material, r.field_presentation_publicity, r.field_presentation_technical_equipment, r.field_presentation_university_logo, r.field_registration_revenue, r.field_registration_phone, r.field_registration_required, r.field_registration_ticket_dates, r.field_registration_ticket_phone, r.field_registration_ticket_price, r.field_registration_ticket_website, r.field_registration_website, r.field_setup_other_tables, r.field_setup_parking_assistance, r.field_setup_podium, r.field_setup_portable_stage, r.field_setup_rectangular_tables_8ft, r.field_setup_road_closures, r.field_setup_round_tables_8ft, r.field_setup_security, r.field_setup_special_requests, r.field_setup_standard_blue_chairs, r.field_services_alcohol_served, r.field_services_food, r.field_services_open_flames, r.field_title, a.field_affiliation, a.field_classification, r.in_state, r.in_step from managers.t_requests r + inner join managers.t_associations a on r.id_association = a.id + where r.is_deleted is not true and a.is_deleted is not true and ((id_group is null and (a.name_machine_manager)::text = (current_user)::text) or a.id in (select id from users.v_associations_self)); + +grant select on users.v_requests_self to reservation_users; -/** @todo: create "managers.t_requests_revision" that is identical to "managers.t_requests" with all the columns allowed to be null. +/** @todo: create "managers.t_requests_revision" that is identical to "managers.t_requests" with all the columns allowed to be null. **/ commit transaction; diff --git a/database/sql/reservation/base-statistics.sql b/database/sql/reservation/base-statistics.sql index 6b06ffb..99a8779 100644 --- a/database/sql/reservation/base-statistics.sql +++ b/database/sql/reservation/base-statistics.sql @@ -6,7 +6,7 @@ start transaction; /** Custom database specific settings (do this on every connection made) **/ set bytea_output to hex; -set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,editors,drafters,requesters,users,public; set datestyle to us; diff --git a/database/sql/reservation/base-users.sql b/database/sql/reservation/base-users.sql index b68bb46..4f7e1e6 100644 --- a/database/sql/reservation/base-users.sql +++ b/database/sql/reservation/base-users.sql @@ -6,7 +6,7 @@ start transaction; /** Custom database specific settings (do this on every connection made) **/ set bytea_output to hex; -set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,editors,drafters,requesters,users,public; set datestyle to us; @@ -62,9 +62,6 @@ create index ci_users_private_not on administers.t_users (id) create index ci_users_private_email_not on administers.t_users (id) where is_deleted is not true and is_private is not true and (address_email).private is not true; -/** when using current_user reserved function/word the index gets ignored. To prevent this, create a manual/custom index and alter the behavior of the views to be more explicit. **/ -create unique index ci_users_current_user on administers.t_users (name_machine) with (fillfactor = 100); - create index ci_users_id_sort_a on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 97; create index ci_users_id_sort_b on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 98; create index ci_users_id_sort_c on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 99; @@ -227,6 +224,7 @@ grant select on administers.vm_users_date_synced_previous_year to reservation_us grant select on administers.vm_users_date_synced_previous_year to reservation_users_manager; + /*** provide sequence id preservation table ***/ create table administers.t_users_sequences ( id bigint not null, @@ -246,9 +244,6 @@ create table administers.t_users_sequences ( grant select,insert,update,delete on administers.t_users_sequences to reservation_users_administer; grant select on administers.t_users_sequences to reservation_users_auditor; -/** when using current_user reserved function/word the index gets ignored. To prevent this, create a manual/custom index and alter the behavior of the views to be more explicit. **/ -create unique index ci_users_sequences_current_user on administers.t_users_sequences (name_machine) with (fillfactor = 40); - create view public.v_users_sequences_locked with (security_barrier=true) as select id, id_user, name_machine, is_locked, date_expire from administers.t_users_sequences where is_locked is true and date_expire >= current_timestamp and (name_machine)::text = (current_user)::text diff --git a/documentation/access_roles.txt b/documentation/access_roles.txt index 4f487a8..e69f746 100644 --- a/documentation/access_roles.txt +++ b/documentation/access_roles.txt @@ -34,10 +34,19 @@ The roles: - This role is intended for users who need to approve, deny, or otherwise be involved in some sort of workflow process. - It should be very common for projects to have a sub-set of reviewer access roles via tables. +- editor: + - This role is intended for users who need to make changes (edit content). + - This role does not grant the access to create any content or make any requests. + - With the reservation system example. thos would be a request for a reservation. + - drafter: - This role is intended for users who create content but are not allowed to publish that content. - This is primarily used for workflow. +- requester: + - This role is intended for users who need to make a request. + - With the reservation system example. thos would be a request for a reservation. + - (system)_users: - Replace (system) with the appropriate name for the system, generally the database name (for example, the reservation system, this would be reservation_users). - Provides basic access to the database, such as ldap integration. diff --git a/examples/test.php b/examples/test.php new file mode 100755 index 0000000..b381058 --- /dev/null +++ b/examples/test.php @@ -0,0 +1,1122 @@ +do_push(); + } + + if (isset($stuff['cookie_login']['cookie'])) { + $stuff['cookie_login']['cookie']->do_push(); + } + } + + function theme($stuff) { + print("

Testing

\n"); + print("The following is a test of the database design and base database and cookied functionality.
"); + print("
"); + + if (isset($_SERVER["HTTPS"])) { + print("1) You are using HTTPS.
"); + print("
"); + } + else { + print("1) You are not using HTTPS.
"); + print("
"); + } + + print("2) _SERVER:
"); + #foreach ($_SERVER as $key => $value) { + # print(" - $key = " . print_r($value, TRUE) . "
"); + #} + print(" - output disabled.
"); + unset($key); + unset($value); + print("
"); + + // Useful _SERVER Variables: + // REQUEST_TIME, REQUEST_TIME_FLOAT + // HTTPS, HTTP_HOST + // HTTP_USER_AGENT + // HTTP_ACCEPT, HTTP_ACCEPT_LANGUAGE, HTTP_ACCEPT_ENCODING + // HTTP_DNT + // HTTP_CONNECTION, HTTP_CACHE_CONTRO + // HTTP_AUTHORIZATION + // protossl (which = 's' for https, and = '' for http) + // SERVER_NAME, SERVER_ADDR, SERVER_PORT + // REMOTE_ADDR, REMOTE_PORT + // DOCUMENT_ROOT + // REQUEST_SCHEME + // CONTEXT_PREFIX, CONTEXT_DOCUMENT_ROOT + // SERVER_PROTOCOL + // REQUEST_METHOD, REQUEST_URI, SCRIPT_NAME + // QUERY_STRING + // QUERY_STRING + + // running php from command line exposes user space environmental variables, such as: + // TERM, SHELL, USER, HOME, _ + + print("

Cookie Test

\n"); + if (isset($stuff['cookie_existence']['new'])) { + print("3) A new existence cookie has been created.
"); + print($stuff['cookie_existence']['new']); + } + elseif (isset($stuff['cookie_existence']['exists'])) { + print("3) The existence cookie has been loaded.
"); + print($stuff['cookie_existence']['exists']); + } + else { + print("3) Disabled
"); + } + + + print("

Login, Session, and Database Connection Test

\n"); + if (isset($stuff['login']) && isset($_SERVER["HTTPS"])) { + print("4) Login
"); + print($stuff['login']); + } + else { + print("4) Disabled
"); + } + + + print("

LDAP Test

\n"); + if (isset($stuff['ldap']) && isset($_SERVER["HTTPS"])) { + print("5) LDAP
"); + if (isset($stuff['ldap']['markup'])) { + print($stuff['ldap']['markup']); + } + } + else { + print("5) Disabled
"); + } + + + if (isset($stuff['resources'])) { + $difference_seconds = microtime(TRUE) - $stuff['resources']['time']; + $difference_milli = $difference_seconds * 1000; + $mu_1 = memory_get_usage(TRUE); + $mu_2 = memory_get_usage(); + $mp_1 = memory_get_peak_usage(TRUE); + $mp_2 = memory_get_peak_usage(); + + print("

Resources

\n"); + print("6) Time Taken: " . sprintf('%.10g', $difference_milli) . " milliseconds (" . sprintf('%.06g', $difference_seconds) . " seconds).
"); + print("7) Memory Usage (Real): " . $mu_1 . " bytes (" . sprintf('%.06g', $mu_1 / 1024 / 1024) . " megabytes).
"); + print("8) Memory Usage (emalloc): " . $mu_2 . " bytes (" . sprintf('%.06g', $mu_2 / 1024 / 1024) . " megabytes)
"); + print("9) Peak Memory Usage (Real): " . $mp_1 . " bytes (" . sprintf('%.06g', $mp_1 / 1024 / 1024) . " megabytes).
"); + print("10) Peak Memory Usage (emalloc): " . $mp_2 . " bytes (" . sprintf('%.06g', $mp_2 / 1024 / 1024) . " megabytes).
"); + } + } + + function session(&$stuff) { + $database = new c_base_database(); + + $remote_address = '127.0.0.1'; + if (!empty($_SERVER['REMOTE_ADDR'])) { + $remote_address = $_SERVER['REMOTE_ADDR']; + } + + // cookie is used to determine whether or not the user is logged in. + $cookie = new c_base_cookie(); + $cookie->set_name("test-logged_in-localhost"); + $cookie->set_path('/'); + $cookie->set_domain('.localhost'); + $cookie->set_secure(TRUE); + $cookie->set_http_only(TRUE); + $cookie->set_first_only(TRUE); + $cookie->set_same_site(c_base_cookie::SAME_SITE_STRICT); + + $logged_in = FALSE; + $failure = FALSE; + + if ($cookie->do_pull() instanceof c_base_return_true) { + $data = $cookie->get_value_exact(); + + if ($cookie->validate() instanceof c_base_return_true && !empty($data['session_id'])) { + if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['form_id'])) { + if ($_POST['form_id'] == 'logout_form') { + // delete the session. + $session = new c_base_session(); + $session->set_socket_directory('/programs/sockets/sessionize_accounts/'); + $session->set_system_name('reservation'); + $session->set_host($remote_address); + $session->set_session_id($data['session_id']); + + $result = $session->do_connect(); + if ($result instanceof c_base_return_true) { + unset($connected); + $session->do_pull(); + + $name = $session->get_name()->get_value(); + $password = $session->get_password()->get_value(); + assign_database_string($database, $name, $password, $session); + unset($name); + unset($password); + + $connected = connect_database($database); + if ($connected) { + set_log_user($database, 'logout'); + $database->do_disconnect(); + } + unset($connected); + + $result = $session->do_terminate(); + $session->do_disconnect(); + } + unset($session); + unset($result); + + // delete the cookie. + $cookie->set_expires(-1); + $cookie->set_max_age(-1); + $stuff['cookie_login']['cookie'] = $cookie; + } + } + else { + $session = new c_base_session(); + $session->set_socket_directory('/programs/sockets/sessionize_accounts/'); + $session->set_system_name('reservation'); + $session->set_host($remote_address); + $session->set_session_id($data['session_id']); + + $result = $session->do_connect(); + $failure = c_base_return::s_has_error($result); + if (!$failure) { + $result = $session->do_pull(); + $session->do_disconnect(); + + $connected = FALSE; + if ($result instanceof c_base_return_true) { + $name = $session->get_name()->get_value(); + $password = $session->get_password()->get_value(); + assign_database_string($database, $name, $password, $session); + unset($name); + unset($password); + + $connected = connect_database($database); + + if (!isset($stuff['login'])) { + $stuff['login'] = ''; + } + + if ($connected) { + $stuff['login'] .= 'Connected: success
' . "\n"; + } + else { + $stuff['login'] .= 'Connected: failure
' . "\n"; + } + } + unset($result); + + if ($connected) { + // check to see if the session timeout has been extended and if so, then update the cookie. + $session_expire = $session->get_timeout_expire()->get_value_exact(); + $session_seconds = $session_expire - time(); + if ($session_seconds == 0) { + $session_seconds = -1; + } + if ($session_expire > $data['expire']) { + $data['expire'] = gmdate("D, d-M-Y H:i:s T", $session_expire); + $cookie->set_value($data); + $cookie->set_expires($session_expire); + $stuff['cookie_login']['cookie'] = $cookie; + } + + if (!isset($stuff['login'])) { + $stuff['login'] = ''; + } + + $user_data = get_user_data($database, $session->get_name()->get_value_exact(), $ldap_data); + + $stuff['login'] .= ' - You are logged in as: ' . $session->get_name()->get_value_exact() . '
' . "\n"; + $stuff['login'] .= ' - Your user id is: ' . $session->get_id_user()->get_value_exact() . '
' . "\n"; + #$stuff['login'] .= ' - Your password is: ' . $session->get_password()->get_value_exact() . '
' . "\n"; + $stuff['login'] .= ' - You will be auto-logged out at: ' . $data['expire'] . '
' . "\n"; + $stuff['login'] .= '
' . "\n"; + $stuff['login'] .= 'Your user data is:
' . "\n"; + $stuff['login'] .= print_r($user_data, TRUE) . "
"; + $stuff['login'] .= '
' . "\n"; + $logged_in = TRUE; + + ldap($stuff, $session->get_name()->get_value_exact()); + set_log_activity($database, $session->get_id_user()->get_value_exact()); + get_database_data($database, $stuff, $session->get_id_user()->get_value_exact()); + + if ($session->get_id_user()->get_value_exact() > 0) { + $log = get_log_activity($database); + $table = build_log_activity_table($log); + $stuff['login'] .= "
" . $table . "
"; + + unset($log); + unset($table); + } + + if ($session->get_id_user()->get_value_exact() > 0) { + $log = get_log_users($database); + $table = build_log_users_table($log); + $stuff['login'] .= "
" . $table . "
"; + + unset($log); + unset($table); + } + } + else { + if (!isset($stuff['login'])) { + $stuff['login'] = ''; + } + + $error = $session->get_error(); + $stuff['login'] .= ' - Failed to load requested session, error: ' . print_r($error, TRUE) . "

"; + unset($error); + } + } + + unset($session); + } + } + unset($data); + } + else { + if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['form_id'])) { + if ($_POST['form_id'] == 'login_form' && !empty($_POST['login_name']) && isset($_POST['login_password'])) { + $connected = FALSE; + $session = new c_base_session(); + $session->set_socket_directory('/programs/sockets/sessionize_accounts/'); + $session->set_system_name('reservation'); + $session->set_name($_POST['login_name']); + $session->set_host($remote_address); + $session->set_password($_POST['login_password']); + + $user_data = array(); + $account_exists = check_login_access($database, $_POST['login_name'], $_POST['login_password'], $session); + if (!$account_exists) { + $user_id = 1; + $session->set_name('public_user'); + $session->set_password(NULL); + if (!isset($stuff['login'])) { + $stuff['login'] = ''; + } + $stuff['login'] .= "DEBUG: does not exist and does not exist in ldap (falling back to the public account to access the database).
"; + + $database->set_session($session); + #$database->set_persistent(TRUE); + assign_database_string($database, 'public_user', NULL, $session); + $connected = connect_database($database); + + if ($connected) { + set_log_user($database, 'login_failure', $_POST['login_name'], 403); + + $stuff['login'] .= ' - Accessing database as: public_user' . '
' . "\n"; + $stuff['login'] .= ' - Your user id is: 1 ' . '
' . "\n"; + $stuff['login'] .= '
' . "\n"; + $logged_in = TRUE; + + set_log_activity($database, $user_id); + } + } + else { + if (!isset($stuff['login'])) { + $stuff['login'] = ''; + } + + $ldap_data = NULL; + ldap($stuff, $session->get_name()->get_value_exact()); + if (!empty($stuff['ldap']['data'])) { + $ldap_data = $stuff['ldap']['data']; + } + + $connected = TRUE; + $stuff['login'] .= "DEBUG: account already exists or exists in ldap.
"; + $user_data = get_user_data($database, $_POST['login_name'], $ldap_data); + $user_id = $user_data['id_user']; + unset($user_data['id_user']); + unset($ldap_data); + } + $session->set_id_user($user_id); + $session->set_settings($user_data); + + if (!$connected) { + $failure = TRUE; + } + else { + set_log_user($database, 'login'); + + $result = $session->do_connect(); + $failure = c_base_return::s_has_error($result); + } + + if (!$failure) { + $result = $session->do_push(600, 1800); // (10 minutes, 30 minutes) + $session->do_disconnect(); + + $session_expire = $session->get_timeout_expire()->get_value_exact(); + $session_max = $session->get_timeout_max()->get_value_exact(); + $expire_string = date("D, d M Y H:i:s T", $session_expire); + $cookie->set_expires($session_expire); + $cookie->set_max_age(NULL); + + if ($result instanceof c_base_return_true) { + $data = array( + 'session_id' => $session->get_session_id()->get_value_exact(), + 'expire' => gmdate("D, d-M-Y H:i:s T", $session_expire), // unecessary, but provided for debug purposes. + ); + $cookie->set_value($data); + $stuff['cookie_login']['cookie'] = $cookie; + + if (!isset($stuff['login'])) { + $stuff['login'] = ''; + } + + $stuff['login'] .= ' - You are logged in as: ' . $session->get_name()->get_value_exact() . '
' . "\n"; + $stuff['login'] .= ' - Your user id is: ' . $session->get_id_user()->get_value_exact() . '
' . "\n"; + #$stuff['login'] .= ' - Your password is: ' . $session->get_password()->get_value_exact() . '
' . "\n"; + $stuff['login'] .= ' - You will be auto-logged out at: ' . $expire_string . ' (' . $session_expire . ')' . '
' . "\n"; + $stuff['login'] .= '
' . "\n"; + $stuff['login'] .= 'Your user data is:
' . "\n"; + $stuff['login'] .= print_r($user_data, TRUE) . "
"; + $stuff['login'] .= '
' . "\n"; + $logged_in = TRUE; + + if (!isset($stuff['ldap']['markup'])) { + ldap($stuff, $session->get_name()->get_value_exact()); + } + + set_log_activity($database, $user_id); + get_database_data($database, $stuff, $user_id); + + if ($session->get_id_user()->get_value_exact() > 0) { + $log = get_log_activity($database); + $table = build_log_activity_table($log); + $stuff['login'] .= "
" . $table . "
"; + + unset($log); + unset($table); + } + + if ($session->get_id_user()->get_value_exact() > 0) { + $log = get_log_users($database); + $table = build_log_users_table($log); + $stuff['login'] .= "
" . $table . "
"; + + unset($log); + unset($table); + } + + unset($user_id); + unset($user_data); + } + else { + if (!isset($stuff['login'])) { + $stuff['login'] = ''; + } + + $error = $session->get_error(); + $stuff['login'] .= ' - failed to save requested session, error: ' . print_r($error, TRUE) . "
"; + unset($error); + } + } + + unset($session); + } + } + } + unset($cookie); + + login_form($stuff, $logged_in); + + $database->do_disconnect(); + unset($database); + } + + function login_form(&$stuff, $logged_in = FALSE) { + if (!isset($stuff['login'])) { + $stuff['login'] = ''; + } + + $stuff['login'] .= '
' . "\n"; + + if ($logged_in) { + $stuff['login'] .= ' ' . "\n"; + $stuff['login'] .= ' ' . "\n"; + } + else { + $stuff['login'] .= ' ' . "\n"; + $stuff['login'] .= ' ' . "\n"; + $stuff['login'] .= ' ' . "\n"; + $stuff['login'] .= ' ' . "\n"; + } + $stuff['login'] .= '
' . "\n"; + $stuff['login'] .= '
' . "\n"; + + #$stuff['login'] .= '_SERVER[REQUEST_METHOD]= ' . print_r($_SERVER["REQUEST_METHOD"], TRUE) . "
"; + #$stuff['login'] .= '_GET = ' . print_r($_GET, TRUE) . "
"; + #$stuff['login'] .= '_POST = ' . print_r($_POST, TRUE) . "
"; + #$stuff['login'] .= '
' . "\n"; + } + + function get_database_data(&$database, &$stuff, $user_id) { + $stuff['login'] .= 'query: "select * from v_users;"
' . "\n"; + $query_result = $database->do_query('select * from v_users'); + if ($query_result instanceof c_base_database_result) { + $all = $query_result->fetch_all(); + $stuff['login'] .= "
    "; + foreach ($all->get_value_exact() as $row) { + $stuff['login'] .= "
  1. "; + foreach ($row as $column => $value) { + $stuff['login'] .= " '$column' = '$value'"; + } + $stuff['login'] .= "
  2. \n"; + unset($column); + unset($value); + } + unset($row); + unset($row_number); + } + $stuff['login'] .= '

' . "\n"; + + $stuff['login'] .= '
' . "\n"; + } + + function check_login_access(&$database, $username, $password, $session) { + if ($username == 'public_user') return FALSE; + + $database->set_session($session); + assign_database_string($database, $username, $password, $session); + + $connected = connect_database($database); + if ($connected) { + return TRUE; + } + + // it is possible the user name might not exist, so try to create it. + $ensure_result = ensure_user_account($_POST['login_name']); + + // try again now that the system has attempted to ensure the user account exists. + $connected = connect_database($database); + if ($connected) { + set_log_user($database, 'create_user'); + return TRUE; + } + + return FALSE; + } + + function assign_database_string(&$database, $username, $password, $session) { + $database->set_session($session); + + $connection_string = new c_base_connection_string(); + $connection_string->set_host('127.0.0.1'); + $connection_string->set_port(5095); + $connection_string->set_database('reservation'); + $connection_string->set_user($username); + $connection_string->set_password($password); + $connection_string->set_ssl_mode('require'); + $connection_string->set_connect_timeout(4); + $database->set_connection_string($connection_string); + unset($connection_string); + } + + function connect_database(&$database) { + if (!($database->do_connect() instanceof c_base_return_true)) { + return FALSE; + } + + $database->do_query('set bytea_output to hex;'); + $database->do_query('set search_path to system,administers,managers,publishers,reviewers,drafters,users,public;'); + $database->do_query('set datestyle to us;'); + + return TRUE; + } + + function set_log_user(&$database, $type, $user_name = NULL, $response_code = 200) { + $query_string = ''; + #$query_string .= 'insert into v_log_users_self_insert (id_user, name_machine_user, log_title, log_type, log_severity, log_details, request_client, response_code)'; + #$query_string .= ' values (coalesce((select id from v_users_self), 1), coalesce((select name_machine_user from v_users_self), \'unknown\'), $1, $2, $3, $4, ($5, $6, $7), $8); '; + $query_string .= 'insert into v_log_users_self_insert (id_user, log_title, log_type, log_severity, log_details, request_client, response_code)'; + $query_string .= ' values (coalesce((select id from v_users_self), 1), $1, $2, $3, $4, ($5, $6, $7), $8); '; + + $query_parameters = array(); + $query_parameters[4] = json_encode(NULL); + $query_parameters[5] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0'; + $query_parameters[6] = isset($_SERVER['REMOTE_PORT']) ? $_SERVER['REMOTE_PORT'] : 0; + $query_parameters[7] = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '' ; // @todo: test providing NULL. + $query_parameters[8] = $response_code; + + if ($type == 'login' ) { + $query_parameters[1] = "Logging in to system."; + $query_parameters[2] = 17; + $query_parameters[3] = 1; + } + elseif ($type == 'logout' ) { + $query_parameters[1] = "Logging out of system."; + $query_parameters[2] = 18; + $query_parameters[3] = 1; + } + elseif ($type == 'create' ) { + $query_parameters[1] = "Created user account."; + $query_parameters[2] = 27; + $query_parameters[3] = 1; + } + elseif ($type == 'login_failure' ) { + $query_parameters[1] = "Failed to login as the user '" . $user_name . "'."; + $query_parameters[2] = 17; + $query_parameters[3] = 2; + $query_parameters[4] = json_encode(array('user_name' => $user_name)); + } + else { + return FALSE; + } + + ksort($query_parameters); + + $query_result = $database->do_query($query_string, $query_parameters); + unset($query_string); + unset($query_parameters); + + return TRUE; + } + + function set_log_activity(&$database, $user_id, $response_code = 200) { + $connected = connect_database($database); + + if (!isset($stuff['login'])) { + $stuff['login'] = ''; + } + + if ($connected) { + $stuff['login'] .= 'Connected: success
' . "\n"; + } + else { + $stuff['login'] .= 'Connected: failure
' . "\n"; + } + + if ($connected) { + $name_machine_user = 'current_user'; + if (!is_int($user_id) || $user_id == 1) { + $user_id = 1; + $name_machine_user = '\'unknown\''; + } + + $query_string = ''; + $query_string .= 'insert into v_log_activity_self_insert (id_user, name_machine_user, request_path, request_arguments, request_client, request_headers, response_headers, response_code) values ($1, ' . $name_machine_user . ', $2, $3, ($4, $5, $6), $7, $8, $9); '; + + // @todo: populate headers. + $request_headers = json_encode(NULL); + $response_headers = json_encode(NULL); + + $query_parameters = array(); + $query_parameters[] = $user_id; + $query_parameters[] = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '/'; + $query_parameters[] = is_array($_GET) && !empty($_GET) ? print_r(array_keys($_GET), TRUE) : ''; + $query_parameters[] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0'; + $query_parameters[] = isset($_SERVER['REMOTE_PORT']) ? $_SERVER['REMOTE_PORT'] : 0; + $query_parameters[] = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : NULL; + $query_parameters[] = $request_headers; + $query_parameters[] = $response_headers; + $query_parameters[] = $response_code; + unset($response_headers); + unset($request_headers); + unset($response_code); + + // for debugging. + #print($query_string . '
'); + #print_r($query_parameters); + #print('
'); + + $query_result = $database->do_query($query_string, $query_parameters); + unset($query_string); + unset($query_parameters); + } + else { + return FALSE; + } + + return TRUE; + } + + function get_user_data(&$database, $user_name, $ldap_data = NULL) { + $id_sort = (int) ord($user_name[0]); + $sort_string = ' where id_sort = ' . $id_sort; + + $user_data = array( + 'id_user' => NULL, + 'id_sort' => $id_sort, + ); + $query_result = $database->do_query('select id, id_external, name_human, address_email, is_private, is_locked, date_created, date_changed, settings from v_users_self' . $sort_string); + if ($query_result instanceof c_base_database_result) { + if ($query_result->number_of_rows()->get_value_exact() > 0) { + $result = $query_result->fetch_row(); + if (!($result instanceof c_base_return_false)) { + $result_array = $result->get_value(); + if (!empty($result_array)) { + $user_data['id_user'] = $result_array[0]; + $user_data['id_external'] = $result_array[1]; + $user_data['name_human'] = $result_array[2]; + $user_data['address_email'] = $result_array[3]; + $user_data['is_private'] = $result_array[4]; + $user_data['is_locked'] = $result_array[5]; + $user_data['date_created'] = $result_array[6]; + $user_data['date_changed'] = $result_array[7]; + $user_data['settings'] = json_decode($result_array[8], TRUE); + } + } + } + } + + if (is_null($user_data['id_user'])) { + if (is_null($ldap_data)) { + $query_result = $database->do_query('insert into v_users_self_insert (id_sort, name_machine) values (' . $id_sort . ', user)'); + } + else { + $email = explode('@', $ldap_data['mail']); + $parameters = array( + $ldap_data['givenname'], + $ldap_data['sn'], + $ldap_data['cn'], + $email[0], + $email[1], + $ldap_data['employeenumber'], + ); + #$query_result = $database->do_query('insert into v_users_self_insert (id_sort, name_machine, name_human.first, name_human.last, name_human.complete, address_email.name, address_email.domain, address_email.private, id_external) values (' . $id_sort . ', user, $1, $2, $3, $4, $5, t, $6)', $parameters); + $query_result = $database->do_query('insert into v_users_self_insert (id_sort, name_machine, name_human.first, name_human.last, name_human.complete, address_email, id_external) values (' . $id_sort . ', user, $1, $2, $3, ($4, $5, TRUE), $6)', $parameters); + } + + $user_data['id_user'] = 1; + $query_result = $database->do_query('select id, id_external, name_human, address_email, is_private, is_locked, date_created, date_changed, settings from v_users_self' . $sort_string); + if ($query_result instanceof c_base_database_result) { + if ($query_result->number_of_rows()->get_value_exact() > 0) { + $result = $query_result->fetch_row(); + if (!($result instanceof c_base_return_false)) { + $result_array = $result->get_value(); + $user_data['id_user'] = $result_array[0]; + $user_data['id_external'] = $result_array[1]; + $user_data['name_human'] = $result_array[2]; + $user_data['address_email'] = $result_array[3]; + $user_data['is_private'] = $result_array[4]; + $user_data['is_locked'] = $result_array[5]; + $user_data['date_created'] = $result_array[6]; + $user_data['date_changed'] = $result_array[7]; + $user_data['settings'] = json_decode($result_array[8], TRUE); + } + } + } + } + + return $user_data; + } + + function get_log_activity(&$database) { + $values = array(); + + $user_id = NULL; + $query_result = $database->do_query('select id, request_path, request_date, request_client, response_code from v_log_activity_self order by request_date desc limit 20;'); + if ($query_result instanceof c_base_database_result) { + $total_rows = $query_result->number_of_rows()->get_value_exact(); + + if ($total_rows > 0) { + for ($i = 0; $i < $total_rows; $i++) { + $result = $query_result->fetch_row(); + if (!($result instanceof c_base_return_false)) { + $values[$i] = $result->get_value(); + } + } + } + } + + return $values; + } + + function get_log_users(&$database) { + $values = array(); + + $user_id = NULL; + $query_result = $database->do_query('select id, log_title, log_type, log_date, request_client, response_code from v_log_users_self order by log_date desc limit 10;'); + if ($query_result instanceof c_base_database_result) { + $total_rows = $query_result->number_of_rows()->get_value_exact(); + + if ($total_rows > 0) { + for ($i = 0; $i < $total_rows; $i++) { + $result = $query_result->fetch_row(); + if (!($result instanceof c_base_return_false)) { + $values[$i] = $result->get_value(); + } + } + } + } + + return $values; + } + + function build_log_activity_table($activity) { + $table = ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + + $total = count($activity); + if ($total > 0) { + for ($i = 0; $i < $total; $i++) { + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + } + unset($i); + } + else { + $table .= ''; + } + unset($total); + + $table .= ''; + $table .= '
Activity History (Latest 20 Entries)
IDPathDateClientHTTP Code
' . $activity[$i][0] . '' . $activity[$i][1] . '' . $activity[$i][2] . '' . $activity[$i][3] . '' . $activity[$i][4] . '
No Entries Found
'; + + return $table; + } + + function build_log_users_table($activity) { + $table = ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + + $total = count($activity); + if ($total > 0) { + for ($i = 0; $i < $total; $i++) { + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + $table .= ''; + } + unset($i); + } + else { + $table .= ''; + } + unset($total); + + $table .= ''; + $table .= '
User History (Latest 10 Entries)
IDTitleTypeDateClientHTTP Code
' . $activity[$i][0] . '' . $activity[$i][1] . '' . $activity[$i][2] . '' . $activity[$i][3] . '' . $activity[$i][4] . '' . $activity[$i][5] . '
No Entries Found
'; + + return $table; + } + + function ensure_user_account($user_name) { + $socket_path = "127.0.0.1"; + $socket_family = AF_INET; + $socket_port = 5433; + $socket_protocol = SOL_TCP; + + $socket_type = SOCK_STREAM; + + $packet_size_target = 63; + $packet_size_client = 1; + + $socket = socket_create($socket_family, $socket_type, $socket_protocol); + if ($socket === FALSE) { + socket_close($socket); + return FALSE; + } + unset($socket); + + $connected = socket_connect($socket, $socket_path, $socket_port); + if ($connected === FALSE) { + socket_close($socket); + return FALSE; + } + unset($connected); + + $name_length = strlen(trim($user_name)); + $difference = $packet_size_target - $name_length; + + if ($difference > 0) { + // the packet expects a packet to be NULL terminated or at most $packet_size_target. + $packet = pack('a' . $name_length . 'x' . $difference, trim($user_name)); + } + else { + $packet = pack('a' . $name_length, $user_name); + } + + $written = socket_write($socket, $packet, $packet_size_target); + if ($written === FALSE) { + socket_close($socket); + return FALSE; + } + unset($written); + + $response = socket_read($socket, $packet_size_client); + socket_close($socket); + if (!is_string($response) || strlen($response) == 0) { + return FALSE; + } + unset($response); + + // an integer is expected to be returned by the socket. + $response_packet = unpack('C', $response); + $response_value = (int) $response_packet[1]; + + // response codes as defined in the c source file: + // 0 = no problems detected. + // 1 = invalid user name, bad characters, or name too long. + // 2 = failed to connect to the ldap server and could not query the ldap name. + // 3 = user name not found in ldap database. + // 4 = failed to connect to the database. + // 5 = error returned while executing the SQL command. + // 6 = error occured while reading input from the user (such as via recv()). + // 7 = error occured while writing input from the user (such as via send()). + // 8 = the received packet is invalid, such as wrong length. + // 10 = connection timed out when reading or writing. + // 11 = the connection is being forced closed. + // 12 = the connection is closing because the service is quitting. + return $response_value; + } + + function ldap(&$stuff, $username) { + $stuff['ldap']['markup'] = ''; + $stuff['ldap']['data'] = array(); + + $ldap = new c_base_ldap(); + $ldap->set_name('ldaps://127.0.0.1:1636/'); + #$ldap->set_bind_name(''); + #$ldap->set_bind_password(''); + $connected = $ldap->do_connect(); + if (c_base_return::s_has_error($connected)) { + $message = $ldap->get_error_message(); + if ($message instanceof c_base_return_string) { + $message = $message->get_value(); + } + else { + $message = NULL; + } + + $stuff['ldap']['markup'] .= 'Connection Failed' . "
"; + $stuff['ldap']['markup'] .= 'ERROR: ' . $message . "
"; + unset($message); + return; + } + + $base_dn = 'ou=users,ou=People'; + $filter = '(uid=' . $username . ')'; + + $read = $ldap->do_search($base_dn, $filter, array('mail', 'gecos', 'givenname', 'cn', 'sn', 'employeenumber')); + if (c_base_return::s_has_error($read)) { + $message = $ldap->get_error_message(); + if ($message instanceof c_base_return_string) { + $message = $message->get_value(); + } + else { + $message = NULL; + } + + $stuff['ldap']['markup'] .= 'ERROR: ' . $message . "
"; + unset($message); + + $ldap->do_disconnect(); + return; + } + + $entries = $read->get_entry_all(); + if ($entries instanceof c_base_return_array) { + $entries = $entries->get_value(); + } + else { + $entries = array(); + } + + if ($entries['count'] > 0) { + $entry = array( + 'uid' => $username, + 'mail' => $entries[0]['mail'][0], + 'gecos' => $entries[0]['gecos'][0], + 'givenname' => $entries[0]['givenname'][0], + 'cn' => $entries[0]['cn'][0], + 'sn' => $entries[0]['sn'][0], + 'employeenumber' => $entries[0]['employeenumber'][0], + ); + $stuff['ldap']['data'] = $entry; + + $stuff['ldap']['markup'] .= "\n"; + } + else { + $stuff['ldap']['data'] = NULL; + + $stuff['ldap']['markup'] .= "No LDAP entry found.\n"; + } + } + + function existence_cookie(&$stuff) { + $agent_string = 'unknown'; + if (isset($_SERVER['HTTP_USER_AGENT'])) { + $agent_string = $_SERVER['HTTP_USER_AGENT']; + } + + + // create an existence cookie + $cookie = new c_base_cookie(); + $cookie->set_name("test-cookie_existence-" . (isset($_SERVER["HTTPS"]) ? '-ssl' : '-no_ssl')); + $cookie->set_path('/'); + $cookie->set_domain('.localhost'); + $cookie->set_secure(isset($_SERVER["HTTPS"])); + $cookie->set_max_age(600); + $cookie->set_http_only(TRUE); + $cookie->set_first_only(TRUE); + $cookie->set_same_site(c_base_cookie::SAME_SITE_STRICT); + + $result = $cookie->do_pull(); + if ($result instanceof c_base_return_true) { + $data = $cookie->get_value_exact(); + + $same_site = ''; + switch ($cookie->get_same_site()->get_value_exact()) { + case c_base_cookie::SAME_SITE_NONE: + $same_site = 'no restriction'; + break; + case c_base_cookie::SAME_SITE_RELAXED: + $same_site = 'relaxed'; + break; + case c_base_cookie::SAME_SITE_STRICT: + $same_site = 'strict'; + break; + } + + #$expire_string = date("D, d M Y H:i:s T", $cookie->get_expires()->get_value_exact()); + #$max_age_string = date("D, d M Y H:i:s T", $cookie->get_max_age()->get_value_exact()); + $max_age_string = $cookie->get_max_age()->get_value_exact(); + + $validated = "Invalid"; + if ($cookie->validate() instanceof c_base_return_true) { + $validated = "Valid"; + } + + $stuff['cookie_existence'] = array('exists' => array()); + $stuff['cookie_existence']['exists'] = " - The cookie settings:
"; + $stuff['cookie_existence']['exists'] .= " -- Name: '" . $cookie->get_name()->get_value_exact() . "'
"; + $stuff['cookie_existence']['exists'] .= " -- Domain: '" . $cookie->get_domain()->get_value_exact() . "'
"; + $stuff['cookie_existence']['exists'] .= " -- Path: '" . $cookie->get_path()->get_value_exact() . "'
"; + $stuff['cookie_existence']['exists'] .= " -- Value:
"; + $stuff['cookie_existence']['exists'] .= " ---- Message: " . $data['message'] . "
"; + $stuff['cookie_existence']['exists'] .= " ---- Expire: " . $data['expire'] . "
"; + $stuff['cookie_existence']['exists'] .= " ---- Checksum: " . $data['checksum'] . "
"; + $stuff['cookie_existence']['exists'] .= " ---- Checksum Validity: " . $validated . "
"; + $stuff['cookie_existence']['exists'] .= " -- Max-Age: '" . $max_age_string . "'
"; + #$stuff['cookie_existence']['exists'] .= " -- Expires: '" . $expire_string . "'
"; + $stuff['cookie_existence']['exists'] .= " -- HTTP Only: '" . ($cookie->get_http_only()->get_value_exact() ? 'True' : 'False') . "'
"; + $stuff['cookie_existence']['exists'] .= " -- First Only: '" . ($cookie->get_first_only()->get_value_exact() ? 'True' : 'False') . "'
"; + $stuff['cookie_existence']['exists'] .= " -- Same Site: '" . $same_site . "'
"; + $stuff['cookie_existence']['exists'] .= "
"; + + unset($data); + unset($validated); + unset($expire_string); + unset($max_age_string); + unset($same_site); + } + else { + $expire = '+10 minutes'; + $expire_stamp = strtotime($expire); + $expire_string = date("D, d M Y H:i:s T", $expire_stamp); + $same_site = ''; + switch ($cookie->get_same_site()->get_value_exact()) { + case c_base_cookie::SAME_SITE_NONE: + $same_site = 'no restriction'; + break; + case c_base_cookie::SAME_SITE_RELAXED: + $same_site = 'relaxed'; + break; + case c_base_cookie::SAME_SITE_STRICT: + $same_site = 'strict'; + break; + } + + #$max_age_string = date("D, d M Y H:i:s T", $cookie->get_max_age()->get_value_exact()); + $max_age_string = $cookie->get_max_age()->get_value_exact(); + + $data = array( + 'message' => "Your agent string is: " . $agent_string, + 'expire' => gmdate("D, d-M-Y H:i:s T", $expire_stamp), + ); + $cookie->set_value($data); + $cookie->set_expires($expire_stamp); + $checksum = $cookie->build_checksum()->get_value_exact(); + + $stuff['cookie_existence'] = array('new' => array()); + $stuff['cookie_existence']['new'] = " - The following cookie should be generated:
"; + $stuff['cookie_existence']['new'] .= " -- Name: '" . $cookie->get_name()->get_value_exact() . "'
"; + $stuff['cookie_existence']['new'] .= " -- Domain: '" . $cookie->get_domain()->get_value_exact() . "'
"; + $stuff['cookie_existence']['new'] .= " -- Path: '" . $cookie->get_path()->get_value_exact() . "'
"; + $stuff['cookie_existence']['new'] .= " -- Value:
"; + $stuff['cookie_existence']['new'] .= " ---- Message: " . $data['message'] . "
"; + $stuff['cookie_existence']['new'] .= " ---- Expire: " . $data['expire'] . "
"; + $stuff['cookie_existence']['new'] .= " ---- Checksum (expected): " . $checksum . "
"; + $stuff['cookie_existence']['new'] .= " -- Max-Age: '" . $max_age_string . "'
"; + $stuff['cookie_existence']['new'] .= " -- Expires: '" . $expire . "', or: '" . $expire_string . "'
"; + $stuff['cookie_existence']['new'] .= " -- HTTP Only: '" . ($cookie->get_http_only()->get_value_exact() ? 'True' : 'False') . "'
"; + $stuff['cookie_existence']['new'] .= " -- First Only: '" . ($cookie->get_first_only()->get_value_exact() ? 'True' : 'False') . "'
"; + $stuff['cookie_existence']['new'] .= " -- Same Site: '" . $same_site . "'
"; + $stuff['cookie_existence']['new'] .= "
"; + $stuff['cookie_existence']['cookie'] = $cookie; + + unset($data); + unset($checksum); + unset($expire); + unset($expire_string); + unset($expire_stamp); + unset($max_age_string); + unset($same_site); + } + unset($result); + unset($agent_string); + } + + $stuff = array( + 'resources' => array( + 'time' => microtime(TRUE), + ), + ); + + existence_cookie($stuff); + session($stuff); + headers($stuff); + theme($stuff); diff --git a/program/reservation/index.php b/program/reservation/index.php index d258890..0228b9e 100644 --- a/program/reservation/index.php +++ b/program/reservation/index.php @@ -51,6 +51,10 @@ $settings['cookie_name'] = 'reservation-session'; $settings['cookie_path'] = '/'; $settings['cookie_domain'] = '.localhost'; + $settings['cookie_http_only'] = FALSE; // setting this to false will allow javascript to access this cookie, such as for ajax. + $settings['cookie_host_only'] = TRUE; + $settings['cookie_same_site'] = c_base_cookie::SAME_SITE_STRICT; + $settings['session_socket'] = '/program/sockets/sessionize_accounts/'; $settings['session_system'] = 'reservation'; $settings['session_expire'] = 600; // 10 minutes $settings['session_max'] = 1800; // 30 minutes @@ -113,10 +117,8 @@ * System settings * @param c_base_session &$session * Session information. - * @param c_base_cookie &$cookie_login - * Session login cookie. */ - function reservation_process_request(&$http, &$database, &$settings, &$session, &$cookie_login) { + function reservation_process_request(&$http, &$database, &$settings, &$session) { $html = new c_base_html(); @@ -152,14 +154,14 @@ // assign base header tag - #$tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_BASE)->get_value_exact(); + #$tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_BASE); #$tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_HREF, 'http://localhost/'); #$html->set_header($tag); #unset($tag); // assign http-equiv header tag - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META)->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_HTTP_EQUIV, 'Content-Type'); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_CONTENT, 'text/html; charset=utf-8'); $html->set_header($tag); @@ -167,14 +169,14 @@ // assign charset header tag - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META)->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_CHARACTER_SET, c_base_charset::UTF_8); $html->set_header($tag); unset($tag); // assign canonical header tag - #$tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META)->get_value_exact(); + #$tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META); #$tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_REL, 'canonical'); #$tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_HREF, 'http://localhost/'); #$html->set_header($tag); @@ -182,7 +184,7 @@ // assign shortlink header tag - #$tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META)->get_value_exact(); + #$tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META); #$tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_REL, 'shortlink'); #$tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_HREF, '/'); #$html->set_header($tag); @@ -190,7 +192,7 @@ // assign description header tag - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META)->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_NAME, 'description'); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_CONTENT, 'A reservation/scheduling system.'); $html->set_header($tag); @@ -198,7 +200,7 @@ // assign distribution header tag - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META)->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_NAME, 'distribution'); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_CONTENT, 'web'); $html->set_header($tag); @@ -206,7 +208,7 @@ // assign robots header tag - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META)->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_NAME, 'robots'); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_CONTENT, 'INDEX,FOLLOW'); $html->set_header($tag); @@ -214,7 +216,7 @@ // assign expires header tag - #$tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META)->get_value_exact(); + #$tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META); #$tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_HTTP_EQUIV, 'expires'); #$tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_CONTENT, date('r', strtotime('+30 minutes'))); #$html->set_header($tag); @@ -222,47 +224,68 @@ // assign viewport header tag - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META)->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_META); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_NAME, 'viewport'); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_CONTENT, 'width=device-width, initial-scale=1'); $html->set_header($tag); unset($tag); - - // define any global css/javascript here as appropriate link/script c_base_markup_tag tag types. - - // finish building pages. if (!isset($_SERVER["HTTPS"])) { - reservation_build_page_require_https($html); + reservation_build_page_require_https($html, $settings, $session); } - elseif ($session === FALSE) { - // check to see if user has filled out the login form. - if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['form_id']) && $_POST['form_id'] == 'login_form') { - $problems = reservation_attempt_login($database, $settings, $session, $cookie_login); - - if ($problems instanceof c_base_return_false) { - // @todo: render default page. - reservation_build_page_dashboard($html); - // @todo: process and handle different paths here and load page as requested. + elseif ($settings['database_user'] == 'public_user') { + // if the session cookie exists, but the user is still public_user, then the cookie is no longer valid. + if (empty($session->get_session_id()->get_value_exact())) { + // check to see if user has filled out the login form. + if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['form_id']) && $_POST['form_id'] == 'login_form') { + $problems = reservation_attempt_login($database, $settings, $session); + + if ($problems instanceof c_base_return_false) { + reservation_build_page_dashboard($html, $settings, $session); + // @todo: process and handle different paths here and load page as requested. + } + else { + // store the problems in the session object (because session as a subclass of c_base_return). + $session->set_problems($problems); + + // @todo: render login failure. + reservation_process_path_public($html, $settings, $session); + } + unset($problems); } else { - - // @todo: render login failure. - // $logged_in should be an array of error messages. - reservation_build_login_page($html, $problems->get_value()); + reservation_process_path_public($html, $settings, $session); } } else { - reservation_build_login_page($html); + $cookie_login = $session->get_cookie(); + + // delete the cookie. + $cookie_login->set_expires(-1); + $cookie_login->set_max_age(-1); + $session->set_cookie($cookie_login); + unset($cookie_login); + + reservation_process_path_public($html, $settings, $session); } } else { - reservation_build_page_dashboard($html); - // @todo: process and handle different paths here and load page as requested. + // load current database settings. + reservation_database_string($database, $settings); + + // load current user roles + reservation_get_current_roles($database, $settings, $session); // @todo: handle returnr result errors. + + if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['form_id'])) { + reservation_process_forms($html, $settings, $session); + } + else { + reservation_process_path($html, $settings, $session); + } } - return c_base_html_return::s_new($html); + return $html; } /** @@ -283,6 +306,35 @@ } /** + * Build the HTTP response. + * + * @param c_base_http &$http + * Http object. + * @param c_base_session &$session + * Session information. + * @param string $markup + * The HTML markup. + */ + function reservation_build_response(&$http, &$session, $markup) { + $http->set_response_content($markup); + + + // send the session cookie if a session id is specified. + $session_id = $session->get_session_id()->get_value_exact(); + if (!empty($session_id)) { + $cookie_login = $session->get_cookie(); + + if ($cookie_login instanceof c_base_cookie) { + $http->set_response_set_cookie($cookie_login); + } + unset($cookie_login); + } + unset($session_id); + + return new c_base_return_true(); + } + + /** * Main Program Function */ function reservation_main() { @@ -297,14 +349,13 @@ // 3: process session information - $cookie_login = new c_base_cookie(); - $session = reservation_process_sessions($settings, $cookie_login)->get_value_exact(); + $session = reservation_process_sessions($http, $settings); gc_collect_cycles(); // 4: perform actions, process work. $database = new c_base_database(); - $html = reservation_process_request($http, $database, $settings, $session, $cookie_login)->get_value(); + $html = reservation_process_request($http, $database, $settings, $session); if (!($html instanceof c_base_html)) { $html = new c_base_html(); } @@ -323,10 +374,8 @@ // 6: build response information. - $http->set_response_content($markup); - $http->set_response_set_cookie($cookie_login); + reservation_build_response($http, $session, $markup); unset($markup); - unset($cookie_login); gc_collect_cycles(); diff --git a/program/reservation/reservation_database.php b/program/reservation/reservation_database.php index 185fc5b..4132a80 100644 --- a/program/reservation/reservation_database.php +++ b/program/reservation/reservation_database.php @@ -3,10 +3,11 @@ * @file * Provides reservation database functions. */ - #require_once('../../common/base/classes/base_error.php'); - #require_once('../../common/base/classes/base_return.php'); - #require_once('../../common/base/classes/base_session.php'); - #require_once('../../common/base/classes/base_database.php'); + require_once('common/base/classes/base_error.php'); + require_once('common/base/classes/base_return.php'); + require_once('common/base/classes/base_session.php'); + require_once('common/base/classes/base_database.php'); + require_once('common/base/classes/base_access.php'); /** * Build the database connection string. @@ -34,7 +35,7 @@ $connection_string = new c_base_connection_string(); $connection_string->set_host($settings['database_host']); $connection_string->set_port($settings['database_port']); - $connection_string->set_database_name($settings['database_name']); + $connection_string->set_database($settings['database_name']); $connection_string->set_user($settings['database_user']); if (!is_null($settings['database_password'])) { @@ -74,7 +75,7 @@ // configure default settings. $database->do_query('set bytea_output to hex;'); - $database->do_query('set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public;'); + $database->do_query('set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,editors,drafters,requesters,users,public;'); $database->do_query('set datestyle to us;'); return new c_base_return_true(); @@ -113,13 +114,13 @@ return c_base_return_error::s_false($error); } + $id_sort = (int) ord($user_name[0]); + $user_data = array( 'id_user' => NULL, 'id_sort' => $id_sort, ); - $id_sort = (int) ord($user_name[0]); - $parameters = array( $id_sort, $user_name, @@ -302,3 +303,113 @@ return c_base_return_array::s_new($return_data); } + + /** + * Get all roles assigned to the current user. + * + * @param c_base_database &$database + * The database object. + * @param array &$settings + * The system settings array. + * @param c_base_session &$session + * The current session. + * + * @return c_base_return_status + * TRUE on success, FALSE otherwise. + * FALSE with error bit set is returned on error. + */ + function reservation_get_current_roles($database, $settings, &$session) { + $connected = $database->is_connected(); + if ($connected instanceof c_base_return_false) { + $connected = reservation_database_connect($database); + } + + $roles = new c_base_roles(); + + + // if there is no session, then assume that this is a public account. + if (empty($session->get_session_id()->get_value_exact())) { + $roles->set_role(c_base_roles::PUBLIC, TRUE); + $session->set_setting('roles', $roles); + unset($roles); + + return new c_base_return_true(); + } + + + // if unable to connect to database to retrieve other roles, just return the ppublic role. + if ($connected instanceof c_base_return_false) { + $roles->set_role(c_base_roles::PUBLIC, TRUE); + $session->set_setting('roles', $roles); + unset($roles); + + $connection_string = $database->get_connection_string(); + $database_name = ($connection_string instanceof c_base_connection_string) ? $connection_string->get_database()->get_value_exact() : ''; + unset($connection_string); + + $error = c_base_error::s_log(NULL, array('arguments' => array(':database_name' => $database_name, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::POSTGRESQL_NO_CONNECTION); + unset($database_name); + + return c_base_return_error::s_false($error); + } + unset($connected); + + + // assign default roles. + $roles->set_role(c_base_roles::PUBLIC, FALSE); + $roles->set_role(c_base_roles::USER, TRUE); + + + // load all postgresql roles. + $result = $database->do_query('SELECT role_name FROM information_schema.enabled_roles'); + if ($result instanceof c_base_database_result) { + $rows = $result->fetch_all()->get_value_exact(); + + foreach ($rows as $row) { + if (!array_key_exists('role_name', $row)) { + continue; + } + + switch ($row['role_name']) { + case $settings['database_name'] . '_requester': + $roles->set_role(c_base_roles::REQUESTER, TRUE); + break; + case $settings['database_name'] . '_drafter': + $roles->set_role(c_base_roles::DRAFTER, TRUE); + break; + case $settings['database_name'] . '_editor': + $roles->set_role(c_base_roles::EDITOR, TRUE); + break; + case $settings['database_name'] . '_reviewer': + $roles->set_role(c_base_roles::REVIEWER, TRUE); + break; + case $settings['database_name'] . '_financer': + $roles->set_role(c_base_roles::FINANCER, TRUE); + break; + case $settings['database_name'] . '_insurer': + $roles->set_role(c_base_roles::INSURER, TRUE); + break; + case $settings['database_name'] . '_publisher': + $roles->set_role(c_base_roles::PUBLISHER, TRUE); + break; + case $settings['database_name'] . '_auditor': + $roles->set_role(c_base_roles::AUDITOR, TRUE); + break; + case $settings['database_name'] . '_manager': + $roles->set_role(c_base_roles::MANAGER, TRUE); + break; + case $settings['database_name'] . '_administer': + $roles->set_role(c_base_roles::ADMINISTER, TRUE); + break; + } + } + unset($row); + unset($rows); + } + unset($result); + + $session->set_setting('roles', $roles); + unset($roles); + + return new c_base_return_true(); + } diff --git a/program/reservation/reservation_paths.php b/program/reservation/reservation_paths.php index db09e62..aa7ba2c 100644 --- a/program/reservation/reservation_paths.php +++ b/program/reservation/reservation_paths.php @@ -8,6 +8,7 @@ require_once('common/base/classes/base_markup.php'); require_once('common/base/classes/base_html.php'); require_once('common/base/classes/base_charset.php'); + require_once('common/base/classes/base_form.php'); require_once('program/reservation/reservation_database.php'); require_once('program/reservation/reservation_session.php'); @@ -17,17 +18,17 @@ * * @param c_base_html &$html * The html page object. - * @param null|array $problems - * (optional) An array of problems to report when building the form. - * This is specified only after a form is submitted. - * - * @return c_base_html_return - * The markup tags object. + * @param array $settings + * The system settings array. + * @param c_base_session &$session + * The current session. */ -function reservation_build_login_page(&$html, $problems = NULL) { +function reservation_build_login_page(&$html, $settings, $session) { $problem_fields = array(); $problem_messages = array(); + // @fixme: create a form problems array in session and use that. + $problems = $session->get_problems(); if (is_array($problems)) { foreach ($problems as $problem) { if (!empty($problem['fields']) && is_array($problem['fields'])) { @@ -43,16 +44,17 @@ function reservation_build_login_page(&$html, $problems = NULL) { } unset($problem); } + unset($problems); if (!empty($problem_messages)) { - $messages = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_DIVIDER, 'form_problems', array('form_problems'))->get_value_exact(); + $messages = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_DIVIDER, 'form_problems', array('form_problems')); foreach ($problem_messages as $problem_delta => $problem_message) { $class = array( 'form_problems-problem', 'form_problems-problem-' . $problem_delta, ); - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_DIVIDER, 'form_problems-problem-' . $problem_delta, $class)->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_DIVIDER, 'form_problems-problem-' . $problem_delta, $class); $tag->set_text($problem_message); unset($class); @@ -68,28 +70,28 @@ function reservation_build_login_page(&$html, $problems = NULL) { unset($problem_messages); // login form - $form = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_FORM, 'login_form', array('login_form'))->get_value_exact(); + $form = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_FORM, 'login_form', array('login_form')); $form->set_attribute(c_base_markup_attributes::ATTRIBUTE_METHOD, 'post'); $form->set_attribute(c_base_markup_attributes::ATTRIBUTE_ROLE, 'form'); $form->set_attribute(c_base_markup_attributes::ATTRIBUTE_ACCEPT_CHARACTER_SET, c_base_charset::UTF_8); // H1 - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_H1)->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_H1); $tag->set_text('Login to System'); $form->set_tag($tag); unset($tag); // hidden form data - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_HIDDEN, 'form_id', array('login_form-id'))->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_HIDDEN, 'form_id', array('login_form-id')); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_VALUE, 'login_form'); $form->set_tag($tag); unset($tag); // label: username - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_LABEL, NULL, array('login_form-label-username'))->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_LABEL, NULL, array('login_form-label-username')); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_FOR, 'login_form-username'); $tag->set_text('Username'); $form->set_tag($tag); @@ -104,7 +106,7 @@ function reservation_build_login_page(&$html, $problems = NULL) { $class[] = 'field_has_problem'; } - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_TEXT, 'login_form-username', $class)->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_TEXT, 'login_form-username', $class); unset($class); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_REQUIRED, TRUE); @@ -113,7 +115,7 @@ function reservation_build_login_page(&$html, $problems = NULL) { // label: password - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_LABEL, NULL, array('login_form-label-password'))->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_LABEL, NULL, array('login_form-label-password')); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_FOR, 'login_form-password'); $tag->set_text('Password'); $form->set_tag($tag); @@ -128,7 +130,7 @@ function reservation_build_login_page(&$html, $problems = NULL) { $class[] = 'field_has_problem'; } - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_PASSWORD, 'login_form-password', $class)->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_PASSWORD, 'login_form-password', $class); unset($class); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_REQUIRED, TRUE); @@ -137,14 +139,14 @@ function reservation_build_login_page(&$html, $problems = NULL) { // button: reset - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_RESET, 'login_form-reset', array('login_form-button-reset'))->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_RESET, 'login_form-reset', array('login_form-button-reset')); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_VALUE, 'Reset'); $form->set_tag($tag); unset($tag); // button: submit - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_SUBMIT, 'login_form-login', array('login_form-button-login'))->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_SUBMIT, 'login_form-login', array('login_form-button-login')); $tag->set_attribute(c_base_markup_attributes::ATTRIBUTE_VALUE, 'Login'); $form->set_tag($tag); unset($tag); @@ -163,36 +165,40 @@ function reservation_build_login_page(&$html, $problems = NULL) { * The system settings array. * @param c_base_session &$session * The current session. - * @param c_base_cookie &$cookie_login - * Session login cookie. * * @return c_base_return_array|c_base_return_status * FALSE on success. * An array of problems on failure. * FALSE with error bit set is returned on error. */ -function reservation_attempt_login(&$database, &$settings, &$session, &$cookie_login) { +function reservation_attempt_login(&$database, &$settings, &$session) { $problems = array(); if (empty($_POST['login_form-username'])) { - $problems[] = array( - 'fields' => array('login_form-username'), - 'messages' => 'No valid username has been supplied.', - ); + $problem = new c_base_form_problem(); + $problem->set_field('login_form-username'); + $problem->set_value('No valid username has been supplied.'); + + $problems[] = $problem; + unset($problem); } if (empty($_POST['login_form-password'])) { - $problems[] = array( - 'fields' => array('login_form-password'), - 'messages' => 'No valid password has been supplied.', - ); + $problem = new c_base_form_problem(); + $problem->set_field('login_form-password'); + $problem->set_value('No valid password has been supplied.'); + + $problems[] = $problem; + unset($problem); } // explicitly deny access to internal user accounts if ($_POST['login_form-username'] == 'public_user') { - $problems[] = array( - 'fields' => array('login_form-username'), - 'messages' => 'Unable to login, an incorrect user name or password has been specified.', - ); + $problem = new c_base_form_problem(); + $problem->set_field('login_form-username'); + $problem->set_value('Unable to login, an incorrect user name or password has been specified.'); + + $problems[] = $problem; + unset($problem); } // return current list of problems before continuing to login attempt with credentials. @@ -200,20 +206,6 @@ function reservation_attempt_login(&$database, &$settings, &$session, &$cookie_l return c_base_return_array::s_new($problems); } - - // assign username and password to both session and database. - if (!($session instanceof c_base_session)) { - $session = new c_base_session(); - } - - if (empty($_SERVER['REMOTE_ADDR'])) { - $session->set_host('0.0.0.0'); - } - else { - $session->set_host($_SERVER['REMOTE_ADDR']); - } - - $session->set_system_name($settings['session_system']); $session->set_name($_POST['login_form-username']); $session->set_password($_POST['login_form-password']); $settings['database_user'] = $_POST['login_form-username']; @@ -248,10 +240,12 @@ function reservation_attempt_login(&$database, &$settings, &$session, &$cookie_l } if ($connected instanceof c_base_return_false) { - $problems[] = array( - 'fields' => array('login_form-username'), - 'messages' => 'Unable to login, an incorrect user or password has been specified.', - ); + $problem = new c_base_form_problem(); + $problem->set_field('login_form-username'); + $problem->set_value('Unable to login, an incorrect user or password has been specified.'); + + $problems[] = $problem; + unset($problem); } else { // @todo: add log entry. @@ -263,7 +257,15 @@ function reservation_attempt_login(&$database, &$settings, &$session, &$cookie_l // the session needs to be opened and the data needs to be saved on successful login. $result = $session->do_connect(); - if (!c_base_return::s_has_error($result)) { + if (c_base_return::s_has_error($result)) { + // @todo: process each error message. + $problem = new c_base_form_problem(); + $problem->set_value('Failed to load session.'); + + $problems[] = $problem; + unset($problem); + } + else { $ldap = reservation_database_load_ldap_data($settings, $_POST['login_form-username'])->get_value(); if ($ldap instanceof c_base_return_false || !is_array($ldap)) { $ldap = array( @@ -273,6 +275,12 @@ function reservation_attempt_login(&$database, &$settings, &$session, &$cookie_l if (isset($ldap['status']) && $ldap['status'] instanceof c_base_return_false) { // @todo: handle error situation. + $problem = new c_base_form_problem(); + $problem->set_field('login_form-username'); + $problem->set_value('Failed to retrieve ldap information for specified user.'); + + $problems[] = $problem; + unset($problem); } $user_data = reservation_database_get_user_data($database, $_POST['login_form-username'], $ldap['data'])->get_value(); @@ -283,22 +291,29 @@ function reservation_attempt_login(&$database, &$settings, &$session, &$cookie_l // @todo: get and use user id from $user_data. - $result = $session->do_push($settings['session_expire'], $settings['session_max']); + $pushed = $session->do_push($settings['session_expire'], $settings['session_max']); $session->do_disconnect(); $session_expire = $session->get_timeout_expire()->get_value_exact(); - $cookie_login->set_expires($session_expire); - $cookie_login->set_max_age(NULL); + $cookie_login = $session->get_cookie(); - if ($result instanceof c_base_return_true) { - $data = array( - 'session_id' => $session->get_session_id()->get_value_exact(), - 'expire' => gmdate("D, d-M-Y H:i:s T", $session_expire), // unecessary, but provided for debug purposes. - ); - $cookie_login->set_data($data); + if ($cookie_login instanceof c_base_cookie) { + $cookie_login->set_expires($session_expire); + $cookie_login->set_max_age(NULL); + + if ($pushed instanceof c_base_return_true) { + $data = array( + 'session_id' => $session->get_session_id()->get_value_exact(), + 'expire' => gmdate("D, d-M-Y H:i:s T", $session_expire), // unecessary, but provided for debug purposes. + ); + + $cookie_login->set_value($data); + $session->set_cookie($cookie_login); + } } - unset($result); + unset($cookie_login); unset($session_expire); + unset($pushed); } unset($result); @@ -315,36 +330,162 @@ function reservation_attempt_login(&$database, &$settings, &$session, &$cookie_l /** * Build the HTTPS requirement page. + * * @param c_base_html &$html * The html page object. - * - * @return c_base_html_return - * The markup tags object. + * @param array $settings + * The system settings array. + * @param c_base_session &$session + * The current session. */ -function reservation_build_page_require_https(&$html) { - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_H1)->get_value_exact(); +function reservation_build_page_require_https(&$html, $settings, &$session) { + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_H1); $tag->set_text('HTTPS Connection is Required'); $html->set_tag($tag); + unset($tag); - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_DIVIDER)->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_DIVIDER); $tag->set_text('Please use a secure connection to access this website.'); $html->set_tag($tag); + unset($tag); } /** * Build the dashboard page. + * * @param c_base_html &$html * The html page object. - * - * @return c_base_html_return - * The markup tags object. + * @param array $settings + * The system settings array. + * @param c_base_session &$session + * The current session. */ -function reservation_build_page_dashboard(&$html) { - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_H1)->get_value_exact(); +function reservation_build_page_dashboard(&$html, $settings, &$session) { + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_H1); $tag->set_text('Dashboard'); $html->set_tag($tag); + unset($tag); - $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_DIVIDER)->get_value_exact(); + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_DIVIDER); $tag->set_text('All links will go here.'); $html->set_tag($tag); + unset($tag); + + $roles = array(); + $roles_object = $session->get_setting('roles'); + if ($roles_object instanceof c_base_roles) { + $roles = $roles_object->get_roles()->get_value_exact(); + } + unset($roles_object); + + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_DIVIDER); + $tag->set_text('You are currently logged in as: ' . $settings['database_user']); + $html->set_tag($tag); + unset($tag); + + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_DIVIDER); + $tag->set_text('You are currently assigned the following roles:'); + $html->set_tag($tag); + unset($tag); + + $tag_ul = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_UNORDERED_LIST); + + foreach ($roles as $role) { + $tag_li = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_LIST_ITEM); + + switch ($role) { + case c_base_roles::PUBLIC: + $tag_li->set_text('Public'); + break; + case c_base_roles::USER: + $tag_li->set_text('User'); + break; + case c_base_roles::REQUESTER: + $tag_li->set_text('Requester'); + break; + case c_base_roles::DRAFTER: + $tag_li->set_text('Drafter'); + break; + case c_base_roles::EDITOR: + $tag_li->set_text('Editor'); + break; + case c_base_roles::REVIEWER: + $tag_li->set_text('Reviewer'); + break; + case c_base_roles::FINANCER: + $tag_li->set_text('Financer'); + break; + case c_base_roles::INSURER: + $tag_li->set_text('Insurer'); + break; + case c_base_roles::PUBLISHER: + $tag_li->set_text('Publisher'); + break; + case c_base_roles::AUDITOR: + $tag_li->set_text('Auditor'); + break; + case c_base_roles::MANAGER: + $tag_li->set_text('Manager'); + break; + case c_base_roles::ADMINISTER: + $tag_li->set_text('Administer'); + break; + } + + $tag_ul->set_tag($tag_li); + unset($tag_li); + } + unset($role); + + $html->set_tag($tag_ul); +} + +/** + * Process and build requested forms. + * + * @param c_base_html &$html + * The html page object. + * @param array $settings + * The system settings array. + * @param c_base_session &$session + * The current session. + */ +function reservation_process_forms(&$html, $settings, &$session) { + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_H1); + $tag->set_text('Form Processing'); + $html->set_tag($tag); + unset($tag); + + $tag = c_theme_html::s_create_tag(c_base_markup_tag::TYPE_DIVIDER); + $tag->set_text('This function is called to process specific forms.'); + $html->set_tag($tag); + unset($tag); +} + +/** + * Process request path and determine what to do. + * + * @param c_base_html &$html + * The html page object. + * @param array $settings + * The system settings array. + * @param c_base_session &$session + * The current session. + */ +function reservation_process_path(&$html, $settings, &$session) { + reservation_build_page_dashboard($html, $settings, $session); +} + +/** + * Process request path for public users and determine what to do. + * + * @param c_base_html &$html + * The html page object. + * @param array $settings + * The system settings array. + * @param c_base_session &$session + * The current session. + */ +function reservation_process_path_public(&$html, $settings, &$session) { + reservation_build_login_page($html, $settings, $session); } diff --git a/program/reservation/reservation_session.php b/program/reservation/reservation_session.php index afc9bb6..083d112 100644 --- a/program/reservation/reservation_session.php +++ b/program/reservation/reservation_session.php @@ -15,76 +15,119 @@ /** * Process session information. * + * @param c_base_http &$http + * Http object. * @param array &$settings * System settings. - * @param c_base_cookie &$cookie_login - * A login cookie object. * - * @param c_base_return_status|c_base_session + * @param c_base_session * Session information is returned on success. - * FALSE is returned when no session is defined. - * FALSE with error bit set is returned on error. + * Session information with error bit set is returned on error. */ - function reservation_process_sessions(&$settings, &$cookie_login) { + function reservation_process_sessions(&$http, &$settings) { + $cookie_login = $http->get_request(c_base_http::REQUEST_COOKIE, $settings['cookie_name']); + + $no_session = FALSE; + if (!($cookie_login instanceof c_base_cookie)) { + $cookie_login = new c_base_cookie(); + + $no_session = TRUE; + } + + // create a session object regardless of login session cookie. + $session = new c_base_session(); + $session->set_socket_directory($settings['session_socket']); + $session->set_system_name($settings['session_system']); + + // the requester should not have any control over specifying/changing these settings, so overwrite whatever is defined by the request cookie. $cookie_login->set_name($settings['cookie_name']); $cookie_login->set_path($settings['cookie_path']); $cookie_login->set_domain($settings['cookie_domain']); + $cookie_login->set_http_only($settings['cookie_http_only']); + $cookie_login->set_host_only($settings['cookie_host_only']); + $cookie_login->set_same_site($settings['cookie_same_site']); $cookie_login->set_secure(TRUE); - $pulled = $cookie_login->do_pull(); - if ($pulled instanceof c_base_return_true) { - $cookie_data = $cookie_login->get_data()->get_value_exact(); + if (empty($_SERVER['REMOTE_ADDR'])) { + $session->set_host('0.0.0.0'); + } + else { + $session->set_host($_SERVER['REMOTE_ADDR']); + } - if (!($cookie_login->validate() instanceof c_base_return_true) || empty($cookie_data['session_id'])) { - // cookie_login failed validation or the cookie contains no session id. - return new c_base_return_false(); - } + // no session cookie has been defined, so there is no existing session to load. + if ($no_session) { + $session->set_cookie($cookie_login); + unset($cookie_login); + unset($no_session); - $session = new c_base_session(); - $session->set_system_name($settings['session_system']); - $session->set_session_id($cookie_data['session_id']); + $error = c_base_error::s_log(NULL, array('arguments' => array(':session_name' => $settings['cookie_name'], ':function_name' => __FUNCTION__)), i_base_error_messages::NO_SESSION); + $session->set_error($error); + unset($error); - if (empty($_SERVER['REMOTE_ADDR'])) { - $session->set_host('0.0.0.0'); - } - else { - $session->set_host($_SERVER['REMOTE_ADDR']); - } + return $session; + } + unset($no_session); - $session_connection = $session->do_connect(); - if (c_base_return::s_has_error($session_connection)) { - return $session_connection; - } + $cookie_data = $cookie_login->get_value_exact(); + if (!($cookie_login->validate() instanceof c_base_return_true) || empty($cookie_data['session_id'])) { + $session->set_cookie($cookie_login); + unset($cookie_login); - $result = $session->do_pull(); - $session->do_disconnect(); + // cookie_login failed validation or the cookie contains no session id. + $error = c_base_error::s_log(NULL, array('arguments' => array(':session_name' => $settings['cookie_name'], ':function_name' => __FUNCTION__)), i_base_error_messages::SESSION_INVALID); + $session->set_error($error); + unset($error); - if ($result instanceof c_base_return_true) { - $user_name = $session->get_name()->get_value(); - $password = $session->get_password()->get_value(); + return $session; + } - if (is_string($user_name) && is_string($password)) { - $settings['database_user'] = $user_name; - $settings['database_password'] = $password; - } - } + $session->set_session_id($cookie_data['session_id']); - // check to see if the session timeout has been extended and if so, then update the cookie. - $session_expire = $session->get_timeout_expire()->get_value_exact(); - $session_seconds = $session_expire - time(); - if ($session_seconds == 0) { - $session_seconds = -1; - } - if ($session_expire > $cookie_data['expire']) { - $cookie_data['expire'] = gmdate("D, d-M-Y H:i:s T", $session_expire); - $cookie_login->set_data($value); - $cookie_login->set_expires($session_expire); + + // connect to the session using the given session id. + $session_connection = $session->do_connect(); + if (c_base_return::s_has_error($session_connection)) { + $session->set_cookie($cookie_login); + unset($cookie_login); + + $session->set_error($session_connection->get_error()); + unset($error); + + return $session; + } + + $result = $session->do_pull(); + $session->do_disconnect(); + + if ($result instanceof c_base_return_true) { + $user_name = $session->get_name()->get_value(); + $password = $session->get_password()->get_value(); + + if (is_string($user_name) && is_string($password)) { + $settings['database_user'] = $user_name; + $settings['database_password'] = $password; } + } + - return c_base_session_return::s_new($session); + // check to see if the session timeout has been extended and if so, then update the cookie. + $session_expire = $session->get_timeout_expire()->get_value_exact(); + $session_seconds = $session_expire - time(); + if ($session_seconds == 0) { + $session_seconds = -1; } - return new c_base_return_false(); + if ($session_expire > $cookie_data['expire']) { + $cookie_data['expire'] = gmdate("D, d-M-Y H:i:s T", $session_expire); + $cookie_login->set_value($cookie_data); + $cookie_login->set_expires($session_expire); + } + + $session->set_cookie($cookie_login); + unset($cookie_login); + + return $session; } /** @@ -161,7 +204,7 @@ } unset($written); - $response = socket_read($socket, $packet_size_client); + $response = @socket_read($socket, $packet_size_client); socket_close($socket); unset($socket); unset($packet_size_client); -- 1.8.3.1