From 4ffb21087e8f89074573fe27b9c18112dd62fa88 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Fri, 3 Mar 2017 01:23:53 -0600 Subject: [PATCH] Progress: continuing development, updated test example, added language testing, miscellaneous fixes Did some testing and made sure the test example was working. Added some languages for testing. - I specifically added japanese as a language to test for error messages because it is so different from english. - It is not practical to implement the error messages class for many languages right now because I expect major refactoring as I continue coding. - Another simple language test is added, testing the languages: russian, spanish, japanese, and english. More work done on in developing the database. Other fixes and changes. --- common/base/classes/base_error.php | 7 +- .../base/classes/base_error_messages_english.php | 100 ++++- .../base/classes/base_error_messages_japanese.php | 250 ++++++++++++ common/base/classes/base_http.php | 3 +- common/base/classes/base_languages.php | 16 +- common/base/classes/base_session.php | 98 +++-- common/theme/classes/theme_markup.php | 4 +- database/sql/reservation/base-dates.sql | 59 +++ database/sql/reservation/base-fields.sql | 4 +- database/sql/reservation/base-legal.sql | 123 ++++++ database/sql/reservation/base-log_problems.sql | 32 +- database/sql/reservation/base-log_types.sql | 6 +- database/sql/reservation/base-paths.sql | 2 +- database/sql/reservation/base-requests.sql | 4 +- database/sql/reservation/base-statistics.sql | 11 +- database/sql/reservation/base-users.sql | 51 +-- examples/test.php | 421 ++++++++++++++++----- program/reservation/reservation_paths.php | 28 +- program/reservation/reservation_session.php | 56 ++- 19 files changed, 1052 insertions(+), 223 deletions(-) create mode 100644 common/base/classes/base_error_messages_japanese.php create mode 100644 database/sql/reservation/base-dates.sql create mode 100644 database/sql/reservation/base-legal.sql diff --git a/common/base/classes/base_error.php b/common/base/classes/base_error.php index 6d4b749..cdd1bfa 100644 --- a/common/base/classes/base_error.php +++ b/common/base/classes/base_error.php @@ -138,7 +138,7 @@ class c_base_error { if (is_int($code)) { $entry->set_code($code); } - elseif (is_null($message)) { + elseif (is_null($code)) { $entry->set_code(0); } @@ -344,7 +344,7 @@ class c_base_error { * TRUE on success, FALSE otherwise. */ public function set_code($code) { - if (!is_string($code)) { + if (!is_int($code)) { return FALSE; } @@ -432,7 +432,7 @@ class c_base_error { * The backtrace will be stored as an object. * * @param int $count - * (optional) Assign a custom count that is used to prevent unecessary function calls from being included in the backtrace. + * (optional) Assign a custom count that is used to prevent unnecessary function calls from being included in the backtrace. * This is essentially to remove the functions called to generate this backtrace, which do not matter. * Instead, only the function where the error happens should the backtrace limit count apply. * This does nothing when the limit is set to 0 (which means unlimited). @@ -512,6 +512,7 @@ interface i_base_error_messages { const POSTGRESQL_CONNECTION_FAILURE = 14; const POSTGRESQL_NO_CONNECTION = 15; const POSTGRESQL_NO_RESOURCE = 16; + const SOCKET_FAILURE = 17; /** diff --git a/common/base/classes/base_error_messages_english.php b/common/base/classes/base_error_messages_english.php index 9ec232e..6e5cf08 100644 --- a/common/base/classes/base_error_messages_english.php +++ b/common/base/classes/base_error_messages_english.php @@ -10,7 +10,91 @@ require_once('common/base/classes/base_languages.php'); /** * English language version of common error messages. */ -final class c_base_error_messages_english extends i_base_error_messages { +final class c_base_error_messages_english implements i_base_error_messages { + + /** + * Converts a given error message into a processed string. + * + * @param c_base_error $code + * The error message code. + * @param bool $arguments + * (optional) When TRUE, argument placeholders are added. + * When FALSE, no placeholders are provided. + * All placeholders should begin with a single colon ':'. + * @param bool $function_name + * (optional) When TRUE, the function name is included with the message. + * When FALSE, no funciton name is provided. + * @param bool $use_html + * (optional) When TRUE, the message is escaped and then wrapped in HTML. + * When FALSE, no HTML wrapping or escaping is peformed. + * + * @return c_base_return_string + * A processed string is returned on success. + * FALSE with error bit set is returned on error. + * + * @see: s_get_message() + */ + static function s_render_error_message($error, $arguments = TRUE, $function_name = FALSE, $html = TRUE) { + if (!($error instanceof c_base_error)) { + return c_base_return_string::s_new(''); + } + + $code = $error->get_code(); + if (is_null($code)) { + unset($code); + return c_base_return_string::s_new(''); + } + + $message = self::s_get_message($code, $arguments, $function_name)->get_value_exact(); + if (empty($message)) { + unset($message); + unset($code); + return c_base_return_string::s_new(''); + } + unset($code); + + if ($arguments === FALSE) { + unset($arguments); + + if ($html) { + return c_base_return_string::s_new('
' . $message . '
'); + } + + return c_base_return_string::s_new($message); + } + + $details = $error->get_details(); + if (isset($details['arguments']) && is_array($details['arguments'])) { + if ($html) { + foreach ($details['arguments'] as $detail_name => $detail_value) { + $detail_name_css = 'error_message-argument-' . preg_replace('/[^[:word:]-]/i', '', $detail_name); + $message = preg_replace('/' . preg_quote($detail_name, '/') . '\b/i', '
' . htmlspecialchars($detail_value, ENT_HTML5 | ENT_COMPAT | ENT_DISALLOWED | ENT_SUBSTITUTE, 'UTF-8') . '
', $message); + } + unset($detail_name_css); + } + else { + foreach ($details as $detail_name => $detail_value) { + $message = preg_replace('/' . preg_quote($detail_name, '/') . '\b/i', $detail_value, $message); + } + } + unset($detail_name); + unset($detail_value); + unset($details); + + if ($html) { + return c_base_return_string::s_new('
' . $message . '
'); + } + + return c_base_return_string::s_new($message); + } + unset($details); + + if ($html) { + return c_base_return_string::s_new('
' . $message . '
'); + } + + return c_base_return_string::s_new($message); + } /** * Returns a standard error message associated with the given code. @@ -69,10 +153,10 @@ final class c_base_error_messages_english extends i_base_error_messages { } elseif ($code === self::OPERATION_UNECESSARY) { if ($arguments === TRUE) { - return c_base_return_string::s_new('Did not perform unecessary operation, :operation_name' . (is_null($function_name_string) ? '' : ',') . $function_name_string . '.'); + return c_base_return_string::s_new('Did not perform unnecessary operation, :operation_name' . (is_null($function_name_string) ? '' : ',') . $function_name_string . '.'); } else { - return c_base_return_string::s_new('Did not perform unecessary operation.'); + return c_base_return_string::s_new('Did not perform unnecessary operation.'); } } elseif ($code === self::FUNCTION_FAILURE) { @@ -101,7 +185,7 @@ final class c_base_error_messages_english extends i_base_error_messages { } elseif ($code === self::NOT_FOUND_DIRECTORY) { if ($arguments === TRUE) { - return c_base_return_string::s_new('The directory, :direction_name, was not found or cannot be accessed' . $function_name_string . '.'); + return c_base_return_string::s_new('The directory, :directory_name, was not found or cannot be accessed' . $function_name_string . '.'); } else { return c_base_return_string::s_new('File not found or cannot be accessed.'); @@ -147,6 +231,14 @@ final class c_base_error_messages_english extends i_base_error_messages { return c_base_return_string::s_new('No database resource is available.'); } } + elseif ($code === self::SOCKET_FAILURE) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('Failed to perform socket operation, :operation_name, socket error (:socket_error) \':socket_error_message\'' . (is_null($function_name_string) ? '' : ',') . $function_name_string . '.'); + } + else { + return c_base_return_string::s_new('Failed to perform socket operation.'); + } + } return c_base_return_string::s_new(''); } diff --git a/common/base/classes/base_error_messages_japanese.php b/common/base/classes/base_error_messages_japanese.php new file mode 100644 index 0000000..07a4d49 --- /dev/null +++ b/common/base/classes/base_error_messages_japanese.php @@ -0,0 +1,250 @@ +get_code(); + if (is_null($code)) { + unset($code); + return c_base_return_string::s_new(''); + } + + $message = self::s_get_message($code, $arguments, $function_name)->get_value_exact(); + if (empty($message)) { + unset($message); + unset($code); + return c_base_return_string::s_new(''); + } + unset($code); + + if ($arguments === FALSE) { + unset($arguments); + + if ($html) { + return c_base_return_string::s_new('
' . $message . '
'); + } + + return c_base_return_string::s_new($message); + } + + $details = $error->get_details(); + if (isset($details['arguments']) && is_array($details['arguments'])) { + if ($html) { + foreach ($details['arguments'] as $detail_name => $detail_value) { + $detail_name_css = 'error_message-argument-' . preg_replace('/[^[:word:]-]/i', '', $detail_name); + $message = preg_replace('/' . preg_quote($detail_name, '/') . '\b/i', '
' . htmlspecialchars($detail_value, ENT_HTML5 | ENT_COMPAT | ENT_DISALLOWED | ENT_SUBSTITUTE, 'UTF-8') . '
', $message); + } + unset($detail_name_css); + } + else { + foreach ($details as $detail_name => $detail_value) { + $message = preg_replace('/' . preg_quote($detail_name, '/') . '\b/i', $detail_value, $message); + } + } + unset($detail_name); + unset($detail_value); + unset($details); + + if ($html) { + return c_base_return_string::s_new('
' . $message . '
'); + } + + return c_base_return_string::s_new($message); + } + unset($details); + + if ($html) { + return c_base_return_string::s_new('
' . $message . '
'); + } + + return c_base_return_string::s_new($message); + } + + /** + * Returns a standard error message associated with the given code. + * + * @param int $code + * The error message code. + * @param bool $arguments + * (optional) When TRUE, argument placeholders are added. + * When FALSE, no placeholders are provided. + * All placeholders should begin with a single colon ':'. + * @param bool $function_name + * (optional) When TRUE, the function name is included with the message. + * When FALSE, no funciton name is provided. + * + * @return c_base_return_string + * A processed string is returned on success. + * FALSE with error bit set is returned on error. + */ + static function s_get_message($code, $arguments = TRUE, $function_name = FALSE) { + $function_name_string = NULL; + if ($function_name) { + $function_name_string = ' :function_name を呼び出している間'; + } + + if ($code === self::INVALID_ARGUMENT) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('無効な引数 :argument_name が指定されています' . $function_name_string . '。'); + } + else { + return c_base_return_string::s_new('無効な引数が指定されています' . $function_name_string . '。'); + } + } + elseif ($code === self::INVALID_FORMAT) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('引数 :format_name の形式が無効です' . $function_name_string . '。:expected_format'); + } + else { + return c_base_return_string::s_new('無効な形式が指定されています。'); + } + } + elseif ($code === self::INVALID_VARIABLE) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('変数 :variable_name は無効です' . $function_name_string . '。'); + } + else { + return c_base_return_string::s_new('無効な変数が指定されています。'); + } + } + elseif ($code === self::OPERATION_FAILURE) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('操作の実行に失敗しました :operation_name' . (is_null($function_name_string) ? '' : '、') . $function_name_string . '。'); + } + else { + return c_base_return_string::s_new('操作を実行できませんでした。'); + } + } + elseif ($code === self::OPERATION_UNECESSARY) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('不要な操作を実行しませんでした :operation_name' . (is_null($function_name_string) ? '' : '、') . $function_name_string . '。'); + } + else { + return c_base_return_string::s_new('不要な操作を実行しませんでした。'); + } + } + elseif ($code === self::FUNCTION_FAILURE) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('関数 :function_name は実行に失敗しました。'); + } + else { + return c_base_return_string::s_new('関数の実行に失敗しました。'); + } + } + elseif ($code === self::NOT_FOUND_ARRAY_INDEX) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('配列 :index_name に索引 :array_name が見つかりませんでした。' . $function_name_string . '。'); + } + else { + return c_base_return_string::s_new('指定された配列内のインデックスの検索に失敗しました。'); + } + } + elseif ($code === self::NOT_FOUND_FILE) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('ファイル :file_name が見つかりませんでした、またはアクセスできません' . $function_name_string . '。'); + } + else { + return c_base_return_string::s_new('ファイルが見つからないか、アクセスできません。'); + } + } + elseif ($code === self::NOT_FOUND_DIRECTORY) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('ディレクトリ :directory_name が見つかりませんでした、またはアクセスできません' . $function_name_string . '。'); + } + else { + return c_base_return_string::s_new('ファイルが見つからないか、アクセスできません。'); + } + } + elseif ($code === self::NO_CONNECTION) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('リソース :resource_name は接続されていません' . $function_name_string . '。'); + } + else { + return c_base_return_string::s_new('リソースが接続されていません。'); + } + } + elseif ($code === self::NO_SUPPORT) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('機能 :functionality_name は現在サポートされていません。' . $function_name_string . '。'); + } + else { + return c_base_return_string::s_new('要求された機能はサポートされていません。'); + } + } + elseif ($code === self::POSTGRESQL_CONNECTION_FAILURE) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('データベースへの接続に失敗しました。 :database_name' . (is_null($function_name_string) ? '' : '、') . $function_name_string . '。'); + } + else { + return c_base_return_string::s_new('データベースに接続できませんでした。'); + } + } + elseif ($code === self::POSTGRESQL_NO_CONNECTION) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('データベース :database_name は接続されていません' . $function_name_string . '。'); + } + else { + return c_base_return_string::s_new('データベースが接続されていません。'); + } + } + elseif ($code === self::POSTGRESQL_NO_RESOURCE) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('データベースリソースがありません' . $function_name_string . '。'); + } + else { + return c_base_return_string::s_new('データベースリソースは使用できません。.'); + } + } + elseif ($code === self::SOCKET_FAILURE) { + if ($arguments === TRUE) { + return c_base_return_string::s_new('ソケット操作の実行に失敗しました。 :operation_name 、ソケットエラー(:socket_error) \':socket_error_message\'' . (is_null($function_name_string) ? '' : '、') . $function_name_string . '。'); + } + else { + return c_base_return_string::s_new('ソケット操作を実行できませんでした。'); + } + } + + return c_base_return_string::s_new(''); + } +} diff --git a/common/base/classes/base_http.php b/common/base/classes/base_http.php index 7da3494..e447810 100644 --- a/common/base/classes/base_http.php +++ b/common/base/classes/base_http.php @@ -132,7 +132,7 @@ class c_base_http extends c_base_rfc_string { const DELIMITER_ACCEPT_SUB_0 = 'q'; const DELIMITER_ACCEPT_SUB_1 = '='; - const ACCEPT_LANGUAGE_CLASS_DEFAULT = 'c_base_language_us_limited'; + const ACCEPT_LANGUAGE_CLASS_DEFAULT = 'c_base_language_limited'; // cache control options const CACHE_CONTROL_NO_CACHE = 1; @@ -4269,7 +4269,6 @@ class c_base_http extends c_base_rfc_string { foreach ($this->request[self::REQUEST_ACCEPT_LANGUAGE]['data']['choices'] as $weight => &$choice) { foreach ($choice as $key => &$c) { $id = $languages->s_get_id_by_name($c['choice']); - if ($id instanceof c_base_return_false) { $c['language'] = NULL; } diff --git a/common/base/classes/base_languages.php b/common/base/classes/base_languages.php index 40495d4..b893f98 100644 --- a/common/base/classes/base_languages.php +++ b/common/base/classes/base_languages.php @@ -789,14 +789,17 @@ final class c_base_language_us_only implements i_base_language { * * @see: http://www.loc.gov/standards/iso639-2/php/code_list.php */ -final class c_base_language_us_limited implements i_base_language { +final class c_base_language_limited implements i_base_language { private static $s_aliases = array( self::ENGLISH_US => array('en-us'), self::ENGLISH => array('eng', 'en'), self::FRENCH => array('fre', 'fra', 'fr'), + self::GAELIC => array('gla', 'gd'), + self::IRISH => array('gle', 'ga'), self::SPANISH => array('spa', 'es'), self::INDONESIAN => array('ind', 'id'), + self::JAPANESE => array('jpn', 'ja'), self::RUSSIAN => array('rus', 'ru'), self::CHINESE => array('chi', 'zho', 'zh'), self::UNDETERMINED => array('und'), @@ -807,8 +810,11 @@ final class c_base_language_us_limited implements i_base_language { self::ENGLISH_US => array('US English'), self::ENGLISH => array('English'), self::FRENCH => array('French'), + self::GAELIC => array('Gaelic', 'Scottish Gaelic'), + self::IRISH => array('Irish'), self::SPANISH => array('Spanish', 'Castilian'), self::INDONESIAN => array('Indonesian'), + self::JAPANESE => array('Japanese'), self::RUSSIAN => array('Russian'), self::CHINESE => array('Chinese'), self::UNDETERMINED => array('Undetermined'), @@ -822,10 +828,16 @@ final class c_base_language_us_limited implements i_base_language { 'fre' => self::FRENCH, 'fra' => self::FRENCH, 'fr' => self::FRENCH, + 'gla' => self::GAELIC, + 'ga' => self::GAELIC, + 'gle' => self::IRISH, + 'ga' => self::IRISH, 'spa' => self::SPANISH, 'es' => self::SPANISH, 'ind' => self::INDONESIAN, 'id' => self::INDONESIAN, + 'jpn' => self::JAPANESE, + 'ja' => self::JAPANESE, 'rus' => self::RUSSIAN, 'ru' => self::RUSSIAN, 'chi' => self::CHINESE, @@ -1002,7 +1014,7 @@ final class c_base_language_us_limited implements i_base_language { * * @see: http://www.loc.gov/standards/iso639-2/php/code_list.php */ -final class c_base_language_us_all implements i_base_language { +final class c_base_language_all implements i_base_language { private static $s_aliases = array( self::ENGLISH_US => array('en-us'), diff --git a/common/base/classes/base_session.php b/common/base/classes/base_session.php index 28b57c3..a3e0186 100644 --- a/common/base/classes/base_session.php +++ b/common/base/classes/base_session.php @@ -27,6 +27,7 @@ class c_base_session extends c_base_return { private $socket_directory; private $socket_path; private $socket_timeout; + private $socket_error; private $system_name; @@ -55,6 +56,7 @@ class c_base_session extends c_base_return { $this->socket_directory = NULL; $this->socket_path = NULL; $this->socket_timeout = NULL; + $this->socket_error = NULL; $this->cookie = NULL; @@ -87,6 +89,7 @@ class c_base_session extends c_base_return { unset($this->socket_directory); unset($this->socket_path); unset($this->socket_timeout); + unset($this->socket_error); unset($this->cookie); @@ -154,7 +157,7 @@ class c_base_session extends c_base_return { } 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); + $error = c_base_error::s_log(NULL, array('arguments' => array(':directory_name' => $socket_directory, ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::NOT_FOUND_DIRECTORY); return c_base_return_error::s_false($error); } @@ -779,13 +782,29 @@ class c_base_session extends c_base_return { if ($receive) { $this->socket_timeout['receive'] = array('seconds' => $seconds, 'microseconds' => $microseconds); if (is_resource($this->socket)) { - socket_set_option($this->socket, SOL_SOCKET, SO_RCVTIMEO, $seconds, $microseconds); + $result = @socket_set_option($this->socket, SOL_SOCKET, SO_RCVTIMEO, $seconds, $microseconds); + if ($result === FALSE) { + unset($result); + + $this->socket_error = @socket_last_error($this->socket); + $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_set_option', ':socket_error' => $this->socket_error, ':socket_error_message' => @socket_strerror($this->socket_error), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::SOCKET_FAILURE); + return c_base_return_error::s_false($error); + } + unset($result); } } else { $this->socket_timeout['send'] = array('seconds' => $seconds, 'microseconds' => $microseconds); if (is_resource($this->socket)) { - socket_set_option($this->socket, SOL_SOCKET, SO_SNDTIMEO, $seconds, $microseconds); + $result = @socket_set_option($this->socket, SOL_SOCKET, SO_SNDTIMEO, $seconds, $microseconds); + if ($result === FALSE) { + unset($result); + + $this->socket_error = @socket_last_error($this->socket); + $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_set_option', ':socket_error' => $this->socket_error, ':socket_error_message' => @socket_strerror($this->socket_error), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::SOCKET_FAILURE); + return c_base_return_error::s_false($error); + } + unset($result); } } @@ -814,7 +833,7 @@ class c_base_session extends c_base_return { * * Use self::get_error() to get the error reported in the packet and not the socket. * - * @return c_base_return_int + * @return c_base_return_int|c_base_return_null * Number representing the socket error or NULL if undefined. * FALSE with the error bit set is returned on error. * @@ -822,33 +841,11 @@ class c_base_session extends c_base_return { * @see: socket_last_error() */ public function get_error_socket() { - if (!is_resource($this->socket)) { - $error = c_base_error::s_log(NULL, array('arguments' => array(':variable_name' => 'this->socket', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_VARIABLE); - return c_base_return_error::s_false($error); - } - - return c_base_return_int::s_new(@socket_last_error($this->socket)); - } - - /** - * This clears the error on the socket if any exist. - * - * @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() - */ - public function clear_error_socket() { - if (!is_resource($this->socket)) { - $error = c_base_error::s_log(NULL, array('arguments' => array(':variable_name' => 'this->socket', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_VARIABLE); - return c_base_return_error::s_false($error); + if (is_null($this->socket_error)) { + return new c_base_return_null(); } - @socket_clear_error($this->socket); - - return new c_base_return_true(); + return c_base_return_int::s_new($this->socket_error); } /** @@ -874,20 +871,27 @@ class c_base_session extends c_base_return { return c_base_return_error::s_false($error); } - $this->socket = socket_create(AF_UNIX, SOCK_STREAM, 0); - if ($this->socket === FALSE) { - $this->do_disconnect(); + $this->socket = @socket_create(AF_UNIX, SOCK_STREAM, 0); + if (!is_resource($this->socket)) { + $this->socket = NULL; + $this->socket_error = @socket_last_error(); - $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_create', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::OPERATION_FAILURE); + @socket_clear_error(); + + $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_create', ':socket_error' => $this->socket_error, ':socket_error_message' => @socket_strerror($this->socket_error), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::SOCKET_FAILURE); return c_base_return_error::s_false($error); } $connected = @socket_connect($this->socket, $this->socket_path, 0); if ($connected === FALSE) { unset($connected); + + $this->socket_error = @socket_last_error($this->socket); + @socket_clear_error($this->socket); + $this->do_disconnect(); - $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_connect', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::OPERATION_FAILURE); + $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_connect', ':socket_error' => $this->socket_error, ':socket_error_message' => @socket_strerror($this->socket_error), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::SOCKET_FAILURE); return c_base_return_error::s_false($error); } unset($connected); @@ -963,7 +967,7 @@ class c_base_session extends c_base_return { return c_base_return_error::s_false($error); } - if (!is_resource($this->socket) || @socket_last_error($this->socket) != 0) { + if (!is_resource($this->socket)) { $error = c_base_error::s_log(NULL, array('arguments' => array(':variable_name' => 'this->socket', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_VARIABLE); return c_base_return_error::s_false($error); } @@ -1061,7 +1065,7 @@ class c_base_session extends c_base_return { return c_base_return_error::s_false($error); } - if (!is_resource($this->socket) || @socket_last_error($this->socket) != 0) { + if (!is_resource($this->socket)) { $error = c_base_error::s_log(NULL, array('arguments' => array(':variable_name' => 'this->socket', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_VARIABLE); return c_base_return_error::s_false($error); } @@ -1139,7 +1143,7 @@ class c_base_session extends c_base_return { return c_base_return_error::s_false($error); } - if (!is_resource($this->socket) || @socket_last_error($this->socket) != 0) { + if (!is_resource($this->socket)) { $error = c_base_error::s_log(NULL, array('arguments' => array(':variable_name' => 'this->socket', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_VARIABLE); return c_base_return_error::s_false($error); } @@ -1186,7 +1190,7 @@ class c_base_session extends c_base_return { * @see: self::p_transfer() */ public function do_flush() { - if (!is_resource($this->socket) || @socket_last_error($this->socket) != 0) { + if (!is_resource($this->socket)) { $error = c_base_error::s_log(NULL, array('arguments' => array(':variable_name' => 'this->socket', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_VARIABLE); return c_base_return_error::s_false($error); } @@ -1227,10 +1231,19 @@ class c_base_session extends c_base_return { $written = @socket_write($this->socket, $json); unset($json); - if ($written === FALSE || $written == 0) { + if ($written === FALSE) { unset($written); - $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_write', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::OPERATION_FAILURE); + $this->socket_error = @socket_last_error($this->socket); + @socket_clear_error($this->socket); + + $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_write', ':socket_error' => $this->socket_error, ':socket_error_message' => @socket_strerror($this->socket_error), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::SOCKET_FAILURE); + return c_base_return_error::s_false($error); + } + elseif ($written == 0) { + unset($written); + + $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_write', ':socket_error' => NULL, ':socket_error_message' => 'No bytes written.', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::SOCKET_FAILURE); return c_base_return_error::s_false($error); } unset($written); @@ -1239,7 +1252,10 @@ class c_base_session extends c_base_return { if (!is_string($json) || mb_strlen($json) == 0) { unset($json); - $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_read', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::OPERATION_FAILURE); + $this->socket_error = @socket_last_error($this->socket); + @socket_clear_error($this->socket); + + $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_read', ':socket_error' => $this->socket_error, ':socket_error_message' => @socket_strerror($this->socket_error), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::SOCKET_FAILURE); return c_base_return_error::s_false($error); } diff --git a/common/theme/classes/theme_markup.php b/common/theme/classes/theme_markup.php index fe0302b..5c391a0 100644 --- a/common/theme/classes/theme_markup.php +++ b/common/theme/classes/theme_markup.php @@ -164,7 +164,7 @@ class c_theme_tag { } // prevent the assigned text from including markup by translating everything to html entities. - $this->text = htmlspecialchars($text, ENT_HTML5 | ENT_NOQUOTES | ENT_IGNORE, 'UTF-8'); + $this->text = htmlspecialchars($text, ENT_HTML5 | ENT_NOQUOTES | ENT_DISALLOWED | ENT_SUBSTITUTE, 'UTF-8'); return new c_base_return_true(); } @@ -1080,7 +1080,7 @@ class c_theme_tag { } // require the non-null string to not be empty. - // multi-byte is unecessary here because this is a test not for characters but instead for a non-empty string. + // multi-byte is unnecessary here because this is a test not for characters but instead for a non-empty string. if (!is_string($attribute_value) || strlen($attribute_value) < 1) { return c_base_return_error::s_false(); } diff --git a/database/sql/reservation/base-dates.sql b/database/sql/reservation/base-dates.sql new file mode 100644 index 0000000..5708bae --- /dev/null +++ b/database/sql/reservation/base-dates.sql @@ -0,0 +1,59 @@ +/** Standardized SQL Structure - Dates **/ +/** This depends on: base-main.sql **/ +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; + + + +/*** Dates: Contexts ***/ +create table managers.t_date_contexts ( + 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 cu_date_contexts_id unique (id), + constraint cu_date_contexts_name_machine unique (name_machine), + + constraint cc_date_contexts_id check (id >= 0) +); + +create sequence managers.s_date_contexts_id owned by managers.t_date_contexts.id; +alter table managers.t_date_contexts alter column id set default nextval('managers.s_date_contexts_id'::regclass); + +grant select,insert,update on managers.t_date_contexts to reservation_users_administer; +grant select,insert,update on managers.t_date_contexts to reservation_users_manager; +grant select on managers.t_date_contexts to reservation_users_auditor; +grant select,usage on managers.s_date_contexts_id to reservation_users_administer; +grant select,usage on managers.s_date_contexts_id to reservation_users_manager; + +create index ci_date_contexts_deleted_not on managers.t_date_contexts (id) + where is_deleted is not true; + +create index ci_date_contexts_public on managers.t_date_contexts (id) + where is_deleted is not true and is_locked is not true; + + +create view requesters.v_date_contexts with (security_barrier=true) as + select id, name_machine, name_human from managers.t_date_contexts + where is_deleted is not true and is_locked is not true; + +grant select on requesters.v_date_contexts to reservation_users_requester; + +insert into managers.t_date_contexts (id, name_machine, name_human) values (0, 'none', 'None'); +insert into managers.t_date_contexts (name_machine, name_human) values ('rehearsal', 'Rehearsal / Setup'); +insert into managers.t_date_contexts (name_machine, name_human) values ('event', 'Event / Meeting'); +insert into managers.t_date_contexts (name_machine, name_human) values ('cleanup', 'Cleanup / Breakdown'); diff --git a/database/sql/reservation/base-fields.sql b/database/sql/reservation/base-fields.sql index 4d309d2..6f85710 100644 --- a/database/sql/reservation/base-fields.sql +++ b/database/sql/reservation/base-fields.sql @@ -41,7 +41,7 @@ grant select,usage on managers.s_field_affiliations_id to reservation_users_admi grant select,usage on managers.s_field_affiliations_id to reservation_users_manager; create view users.v_field_affiliations with (security_barrier=true) as - select id, id_external, name_machine, name_human from managers.t_field_affiliations + select id, id_external, name_machine, name_human, date_created, date_changed from managers.t_field_affiliations where is_deleted is false; grant select on users.v_field_affiliations to reservation_users; @@ -78,7 +78,7 @@ grant select,usage on managers.s_field_classifications_id to reservation_users_a grant select,usage on managers.s_field_classifications_id to reservation_users_manager; create view users.v_field_classifications with (security_barrier=true) as - select id, id_external, name_machine, name_human from managers.t_field_classifications + select id, id_external, name_machine, name_human, date_created, date_changed from managers.t_field_classifications where is_deleted is false; grant select on users.v_field_classifications to reservation_users; diff --git a/database/sql/reservation/base-legal.sql b/database/sql/reservation/base-legal.sql new file mode 100644 index 0000000..ac01c05 --- /dev/null +++ b/database/sql/reservation/base-legal.sql @@ -0,0 +1,123 @@ +/** Standardized SQL Structure - Legal */ +/** This depends on: base-users.sql **/ +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; + + + +/*** Legal Types ***/ +create table managers.t_legal_types ( + id bigint not null, + id_external bigint, + + 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 cu_legal_types_id unique (id), + constraint cu_legal_types_name_machine unique (name_machine), + + constraint cc_legal_types_id check (id >= 0) +); + +create sequence managers.s_legal_types_id owned by managers.t_legal_types.id; +alter table managers.t_legal_types alter column id set default nextval('managers.s_legal_types_id'::regclass); + +grant select,insert,update on managers.t_legal_types to reservation_users_administer; +grant select,insert,update on managers.t_legal_types to reservation_users_manager; +grant select on managers.t_legal_types to reservation_users_auditor; +grant select,usage on managers.s_legal_types_id to reservation_users_administer; +grant select,usage on managers.s_legal_types_id to reservation_users_manager; + +create index ci_legal_types_deleted_not on managers.t_legal_types (id) + where is_deleted is not true; + +create index ci_legal_types_public on managers.t_legal_types (id) + where is_deleted is not true and is_locked is not true; + + +create view users.v_legal_types with (security_barrier=true) as + select id, id_external, name_machine, name_human from managers.t_legal_types + where is_deleted is not true and is_locked is not true; + +grant select on users.v_legal_types to reservation_users_requester; + + +insert into managers.t_legal_types (id, name_machine, name_human) values (0, 'none', 'None'); + + + +/*** Legal / Digital Signatures ***/ +create table managers.t_signatures ( + id bigint not null, + id_type bigint not null, + id_signer bigint not null, + id_request bigint, + + name_machine_signer varchar(128) not null, + + is_deleted boolean default false not null, + + date_created timestamp default localtimestamp not null, + date_deleted timestamp, + + /* @todo: PGP/GPG based signatures are planned but not currently implemented, the columns (fingerprint and signature) are created but are subject to major change. */ + fingerprint varchar(64), + signature text, + + constraint cu_signatures_id unique (id), + + constraint cc_signatures_id check (id > 0), + + constraint cf_signatures_id_creator foreign key (id_signer, name_machine_signer) references administers.t_users (id, name_machine) on delete restrict on update cascade, + constraint cf_signatures_id_type foreign key (id_type) references managers.t_legal_types (id) on delete restrict on update cascade, + constraint cf_signatures_id_request foreign key (id_request) references managers.t_requests (id) on delete restrict on update cascade +); + +create sequence managers.s_signatures_id owned by managers.t_signatures.id; +alter table managers.t_signatures alter column id set default nextval('managers.s_signatures_id'::regclass); + +grant select,insert,update on managers.t_signatures to reservation_users_administer; +grant select,insert,update on managers.t_signatures to reservation_users_manager; +grant select on managers.t_signatures to reservation_users_auditor; +grant select,usage on managers.s_signatures_id to reservation_users_administer; +grant select,usage on managers.s_signatures_id to reservation_users_manager; +grant usage on managers.s_signatures_id to reservation_users; + +create index ci_signatures_deleted_not on managers.t_signatures (id) + where is_deleted is not true; + +create index ci_signatures_approved on managers.t_signatures (id) + where is_deleted is not true and is_cancelled is not true and is_approved is true; + +create index ci_signatures_approved_cancelled on managers.t_signatures (id) + where is_deleted is not true and is_cancelled is true and is_approved is true; + + +/*** provide current user access to their own information ***/ +create view users.v_signatures_self with (security_barrier=true) as + select id, id_type, id_request, date_created, fingerprint, signature from managers.t_signatures + where is_deleted is not true and (name_machine_signer)::text = (current_user)::text; + +grant select on users.v_signatures_self to reservation_users; + + +/** provide current user access to insert their own associations **/ +create view users.v_signatures_self_insert with (security_barrier=true) as + select id, id_type, id_signer, name_machine_signer, id_request, fingerprint, signature from managers.t_signatures + where is_deleted is not true and (name_machine_signer)::text = (current_user)::text + with check option; + +grant insert on users.v_signatures_self_insert to reservation_users; diff --git a/database/sql/reservation/base-log_problems.sql b/database/sql/reservation/base-log_problems.sql index abb1e25..16439b3 100644 --- a/database/sql/reservation/base-log_problems.sql +++ b/database/sql/reservation/base-log_problems.sql @@ -1,5 +1,6 @@ /** Standardized SQL Structure - Logs - Problems */ /** This depends on: base-users.sql **/ +/* The problem logs are intended for temporary reporting of problems and are meant to allow permanent deletion. */ start transaction; @@ -12,6 +13,7 @@ set datestyle to us; /** Provide a log of problems, which are defined by the software. **/ +/* @todo: shouldnt there be a problem type code? */ create table managers.t_log_problems ( id bigint not null, @@ -20,7 +22,6 @@ create table managers.t_log_problems ( date_created timestamp default localtimestamp not null, date_changed timestamp default localtimestamp not null, - date_deleted timestamp, constraint cp_log_problems_id primary key (id), @@ -29,10 +30,12 @@ create table managers.t_log_problems ( constraint cu_log_problems_name_machine unique (name_machine) ); -grant select on managers.t_log_problems to reservation_users_administer; -grant select on managers.t_log_problems to reservation_users_manager; +grant select,insert,update,delete on managers.t_log_problems to reservation_users_administer; +grant select,insert,update,delete on managers.t_log_problems to reservation_users_manager; grant select on managers.t_log_problems to reservation_users_auditor; +/* @todo: it seems the views for allowing users to insert/delete problems needs to be created. */ + /** Provide a log of problems, associated with a given user. **/ @@ -44,7 +47,6 @@ create table managers.t_log_problems_users ( date_created timestamp default localtimestamp not null, date_changed timestamp default localtimestamp not null, - date_deleted timestamp, log_details json, @@ -63,18 +65,20 @@ grant select on managers.t_log_problems_users to reservation_users_auditor; /** only allow select, insert, and delete for users when user id is current user **/ 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 + select id_problem, id_user, date_created, date_changed, log_details from managers.t_log_problems_users where (name_machine_user)::text = (current_user)::text; 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 + select id_problem, id_user, name_machine_user, date_changed, log_details from managers.t_log_problems_users where (name_machine_user)::text = (current_user)::text with check option; grant insert on users.v_log_problems_users_self_insert to reservation_users; + create view users.v_log_problems_users_self_delete with (security_barrier=true) as select id_problem, id_user from managers.t_log_problems_users where (name_machine_user)::text = (current_user)::text @@ -83,5 +87,21 @@ create view users.v_log_problems_users_self_delete with (security_barrier=true) grant delete on users.v_log_problems_users_self_delete to reservation_users; +/** automatically delete problems deleted from the table managers.t_log_problems_users **/ +create function managers.f_log_problems_users_delete() returns trigger security definer as $$ + begin + if (tg_op = 'DELETE') then + delete from managers.t_log_problems where id = old.id_problem; + return old; + end if; + + return null; + end; +$$ language plpgsql; + +create trigger tr_log_problems_users_delete + after delete on managers.t_log_problems_users + for each row execute procedure managers.f_log_problems_users_delete(); + commit transaction; diff --git a/database/sql/reservation/base-log_types.sql b/database/sql/reservation/base-log_types.sql index 5ea2a47..ab4d906 100644 --- a/database/sql/reservation/base-log_types.sql +++ b/database/sql/reservation/base-log_types.sql @@ -29,7 +29,7 @@ create table managers.t_log_types ( constraint cu_log_types_user unique (name_machine), - constraint cc_log_types_id check (id > 0) + constraint cc_log_types_id check (id >= 0) ); create sequence managers.s_log_types_id owned by managers.t_log_types.id; @@ -60,6 +60,7 @@ alter sequence managers.s_log_types_id restart; /** create well known types that can then be user for indexes (all new types added should be considered for custom indexing). **/ +insert into managers.t_log_types (id, name_machine, name_human) values (0, 'none', 'None'); insert into managers.t_log_types (id, name_machine, name_human) values (1, 'php', 'PHP'); insert into managers.t_log_types (id, name_machine, name_human) values (2, 'theme', 'Theme'); insert into managers.t_log_types (id, name_machine, name_human) values (3, 'cache', 'Cache'); @@ -228,7 +229,7 @@ create table managers.t_log_severity_levels ( constraint cu_log_severity_levels_user unique (name_machine), - constraint cc_log_severity_levels_id check (id > 0) + constraint cc_log_severity_levels_id check (id >= 0) ); create sequence managers.s_log_severity_levels_id owned by managers.t_log_severity_levels.id; @@ -253,6 +254,7 @@ alter sequence managers.s_log_severity_levels_id restart; /** create well known types that can then be user for indexes (all new types added should be considered for custom indexing). **/ +insert into managers.t_log_severity_levels (id, name_machine, name_human) values (0, 'none', 'None'); insert into managers.t_log_severity_levels (id, name_machine, name_human) values (1, 'information', 'Information'); insert into managers.t_log_severity_levels (id, name_machine, name_human) values (2, 'notice', 'Notice'); insert into managers.t_log_severity_levels (id, name_machine, name_human) values (3, 'debug', 'Debug'); diff --git a/database/sql/reservation/base-paths.sql b/database/sql/reservation/base-paths.sql index d263a92..0dde698 100644 --- a/database/sql/reservation/base-paths.sql +++ b/database/sql/reservation/base-paths.sql @@ -109,7 +109,7 @@ create index ci_paths_public on managers.t_paths (id) 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 + select id, id_type, id_group, name_machine, name_human, is_private, date_created, date_changed 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; diff --git a/database/sql/reservation/base-requests.sql b/database/sql/reservation/base-requests.sql index 49279fd..0c07325 100644 --- a/database/sql/reservation/base-requests.sql +++ b/database/sql/reservation/base-requests.sql @@ -29,7 +29,7 @@ create table managers.t_request_types ( constraint cu_request_types_id unique (id), constraint cu_request_types_name_machine unique (name_machine), - constraint cc_request_types_id check (id > 0) + constraint cc_request_types_id check (id >= 0) ); create sequence managers.s_request_types_id owned by managers.t_request_types.id; @@ -47,6 +47,7 @@ create index ci_request_types_deleted_not on managers.t_request_types (id) 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 not true and is_locked is not true; @@ -54,6 +55,7 @@ create view requesters.v_request_types with (security_barrier=true) as grant select on requesters.v_request_types to reservation_users_requester; /** @todo: consider creating default request types **/ +insert into managers.t_request_types (id, name_machine, name_human) values (0, 'none', 'None'); diff --git a/database/sql/reservation/base-statistics.sql b/database/sql/reservation/base-statistics.sql index 99a8779..2b2751c 100644 --- a/database/sql/reservation/base-statistics.sql +++ b/database/sql/reservation/base-statistics.sql @@ -51,13 +51,15 @@ create function managers.f_statistics_http_status_codes_insert() returns trigger return null; end; $$ language plpgsql; -reset role; -revoke create on schema managers from reservation_users_manager; -create trigger tr_statistics_http_status_codes_insert +create trigger tr_log_activity_insert_statistics_http_status_codes after insert on managers.t_log_activity for each row execute procedure managers.f_statistics_http_status_codes_insert(); +create trigger tr_log_users_insert_statistics_http_status_codes + after insert on managers.t_log_users + for each row execute procedure managers.f_statistics_http_status_codes_insert(); + /** create all of the known codes, initializing them to 0. **/ insert into managers.t_statistics_http_status_codes (code) values (0); @@ -148,6 +150,7 @@ grant select on managers.t_statistics_request_path to reservation_users_administ grant select on managers.t_statistics_request_path to reservation_users_manager; grant select on managers.t_statistics_request_path to reservation_users_auditor; + /** permissions prevent this from working as desired, so for now open up these stats to the following users (via a view) **/ create view users.v_statistics_request_path with (security_barrier=true) as select path, count from managers.t_statistics_request_path @@ -155,12 +158,14 @@ create view users.v_statistics_request_path with (security_barrier=true) as grant select,insert,update on users.v_statistics_request_path to reservation_users; + create view public.v_statistics_request_path with (security_barrier=true) as select path, count from managers.t_statistics_request_path with check option; grant select,insert,update on public.v_statistics_request_path to public_users; + /** create an auto-update trigger **/ create function managers.f_statistics_request_path_insert() returns trigger as $$ begin diff --git a/database/sql/reservation/base-users.sql b/database/sql/reservation/base-users.sql index 4f7e1e6..80d4c1a 100644 --- a/database/sql/reservation/base-users.sql +++ b/database/sql/reservation/base-users.sql @@ -105,7 +105,7 @@ insert into administers.t_users (id, name_machine, name_human, is_private) value /*** provide current user access to their own information ***/ create view users.v_users_self with (security_barrier=true) as select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, is_coordinator, date_created, date_changed, date_synced, settings from administers.t_users - where is_deleted is not true and (name_machine)::text = (current_user)::text; + where (name_machine)::text = (current_user)::text; grant select on users.v_users_self to reservation_users; @@ -118,7 +118,7 @@ grant insert on users.v_users_self_insert to reservation_users; create view users.v_users_self_update with (security_barrier=true) as select address_email, is_private, date_changed, date_synced, settings from administers.t_users - where is_deleted is not true and date_changed = localtimestamp and (date_synced is null or date_synced = localtimestamp) and (name_machine)::text = (current_user)::text + where date_changed = localtimestamp and (date_synced is null or date_synced = localtimestamp) and (name_machine)::text = (current_user)::text with check option; grant update on users.v_users_self_update to reservation_users; @@ -127,7 +127,7 @@ grant update on users.v_users_self_update to reservation_users; /**** anonymous user has uid = 1 ****/ create view public.v_users_self with (security_barrier=true) as select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, is_coordinator, date_created, date_changed, date_synced, settings from administers.t_users - where id = 1 and is_deleted is not true and id_sort = 0; + where id = 1 and id_sort = 0; grant select on public.v_users_self to public_users; @@ -135,7 +135,7 @@ grant select on public.v_users_self to public_users; /**** system user has uid = 2 ****/ create view system.v_users_self with (security_barrier=true) as select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, is_coordinator, date_created, date_changed, date_synced, settings from administers.t_users - where id = 2 and is_deleted is not true and id_sort = 0; + where id = 2 and id_sort = 0; grant select on system.v_users_self to reservation_user; @@ -160,20 +160,19 @@ grant select on public.v_users_email to public_users; /*** provide managers with the ability to modify accounts ***/ create view managers.v_users with (security_barrier=true) as - select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, is_coordinator, date_created, date_changed, date_synced from administers.t_users + select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, is_coordinator, date_created, date_changed, date_synced, settings from administers.t_users where is_deleted is not true; grant select on managers.v_users to reservation_users_manager; create view managers.v_users_insert with (security_barrier=true) as - select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, is_coordinator from administers.t_users - where is_deleted is not true + select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, is_coordinator, settings from administers.t_users with check option; grant insert on managers.v_users_insert to reservation_users_manager; create view managers.v_users_update with (security_barrier=true) as - select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, is_coordinator, date_changed, date_synced from administers.t_users + select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, is_coordinator, date_changed, date_synced, settings from administers.t_users where is_deleted is not true and date_changed = localtimestamp and (date_synced is null or date_synced = localtimestamp) with check option; @@ -224,40 +223,4 @@ 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, - id_user bigint not null, - name_machine varchar(128) not null, - is_locked boolean default true not null, - date_expire timestamp not null, - - constraint cu_users_sequences_id unique (id), - constraint cu_users_sequences_name_machine unique (name_machine), - - constraint cc_users_sequences_id check (id > 0), - - constraint cf_users_sequences_user foreign key (id_user, name_machine) references administers.t_users (id, name_machine) on delete cascade on update cascade -); - -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; - -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 - with check option; - -grant select,insert,update,delete on v_users_sequences_locked to reservation_users; - -create view public.v_users_sequences_unlocked with (security_barrier=true) as - select id, id_user, name_machine, is_locked, date_expire from administers.t_users_sequences - where (is_locked is not true or date_expire < current_timestamp) and (name_machine)::text = (current_user)::text - with check option; - -grant select,update,delete on v_users_sequences_unlocked to reservation_users; - - - commit transaction; diff --git a/examples/test.php b/examples/test.php index b381058..606dc7e 100755 --- a/examples/test.php +++ b/examples/test.php @@ -8,9 +8,59 @@ require_once('common/base/classes/base_cookie.php'); require_once('common/base/classes/base_database.php'); require_once('common/base/classes/base_ldap.php'); + require_once('common/base/classes/base_http.php'); - function headers($stuff) { + // create an alias for the default language for error messages. + #class_alias('c_base_error_messages_english', 'c_base_error_messages'); + + + function process_received_headers(&$stuff) { + $stuff['http'] = new c_base_http(); + $stuff['http']->do_load_request(); + + // test error message handling using english or japanese. + $supported_languages = array( + i_base_language::ENGLISH => 'c_base_error_messages_english', + i_base_language::JAPANESE => 'c_base_error_messages_japanese', + ); + + $language_chosen = i_base_language::ENGLISH; + $languages_accepted = $stuff['http']->get_request(c_base_http::REQUEST_ACCEPT_LANGUAGE)->get_value(); + if (isset($languages_accepted['data']['weight']) && is_array($languages_accepted['data']['weight'])) { + foreach ($languages_accepted['data']['weight'] as $weight => $language) { + $language_code = array_pop(array_keys($language)); + if (array_key_exists($language_code, $supported_languages)) { + $language_chosen = $language_code; + break; + } + } + unset($weight); + unset($language); + unset($language_code); + } + unset($languages_accepted); + + if ($language_chosen === i_base_language::ENGLISH) { + require_once('common/base/classes/base_error_messages_english.php'); + } + elseif ($language_chosen === i_base_language::JAPANESE) { + require_once('common/base/classes/base_error_messages_japanese.php'); + } + + $stuff['error_messages'] = new $supported_languages[$language_chosen]; + + unset($supported_languages); + unset($language_chosen); + } + + $stuff = array( + 'resources' => array( + 'time' => microtime(TRUE), + ), + ); + + function send_prepared_headers($stuff) { if (isset($stuff['cookie_existence']['cookie'])) { $stuff['cookie_existence']['cookie']->do_push(); } @@ -21,10 +71,32 @@ } function theme($stuff) { + // @todo: call the appropriate http send function from $stuff['http']. this requires rewriting this entire theme function. + // note: not changing language here because most of the page is in english, regardless of the http accept-language setting. + print(''); + print(''); + print('Testing Koopa'); + print(''); + print(''); + print(''); + print(''); + print(''); + print(''); + print(''); + print(''); + + print(''); print("

Testing

\n"); print("The following is a test of the database design and base database and cookied functionality.
"); print("
"); + if (isset($stuff['errors'])) { + print("0) The following errors have been detected:
"); + print('
    ' . $stuff['errors'] . '
'); + } + if (isset($_SERVER["HTTPS"])) { print("1) You are using HTTPS.
"); print("
"); @@ -43,6 +115,38 @@ unset($value); print("
"); + print("3) Language Test:
"); + + // disclaimer: I used translate.google.com to generate the languages and provided only the default translation (expect translation errors). + $test_strings = array( + i_base_language::ENGLISH => 'This is a test using your browser default language. Currently english (default), spanish, japanese, and russian are tested.', + i_base_language::JAPANESE => 'これは、ブラウザのデフォルト言語を使用したテストです。 現在、英語(デフォルト)、スペイン語、日本語、ロシア語がテストされています。', + i_base_language::RUSSIAN => 'Это тест с помощью браузера по умолчанию язык. В настоящее время английский (по умолчанию), испанский, японский и русский тестируются.', + i_base_language::SPANISH => 'Se trata de una prueba que utiliza el idioma predeterminado de su navegador. Actualmente se ponen a prueba el inglés (predeterminado), el español, el japonés y el ruso.', + ); + + $language_chosen = i_base_language::ENGLISH; + $languages_accepted = $stuff['http']->get_request(c_base_http::REQUEST_ACCEPT_LANGUAGE)->get_value(); + if (isset($languages_accepted['data']['weight']) && is_array($languages_accepted['data']['weight'])) { + foreach ($languages_accepted['data']['weight'] as $weight => $language) { + $language_code = array_pop(array_keys($language)); + if (array_key_exists($language_code, $test_strings)) { + $language_chosen = $language_code; + break; + } + } + unset($weight); + unset($language); + unset($language_code); + } + + print(' - ' . $test_strings[$language_chosen] . "
"); + print("
"); + + unset($language_chosen); + unset($languages_accepted); + unset($test_strings); + // Useful _SERVER Variables: // REQUEST_TIME, REQUEST_TIME_FLOAT // HTTPS, HTTP_HOST @@ -67,37 +171,37 @@ print("

Cookie Test

\n"); if (isset($stuff['cookie_existence']['new'])) { - print("3) A new existence cookie has been created.
"); + print("4) 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("4) The existence cookie has been loaded.
"); print($stuff['cookie_existence']['exists']); } else { - print("3) Disabled
"); + print("4) Disabled
"); } print("

Login, Session, and Database Connection Test

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

LDAP Test

\n"); if (isset($stuff['ldap']) && isset($_SERVER["HTTPS"])) { - print("5) LDAP
"); + print("6) LDAP
"); if (isset($stuff['ldap']['markup'])) { print($stuff['ldap']['markup']); } } else { - print("5) Disabled
"); + print("6) Disabled
"); } @@ -110,12 +214,15 @@ $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).
"); + print("7) Time Taken: " . sprintf('%.10g', $difference_milli) . " milliseconds (" . sprintf('%.06g', $difference_seconds) . " seconds).
"); + print("8) Memory Usage (Real): " . $mu_1 . " bytes (" . sprintf('%.06g', $mu_1 / 1024 / 1024) . " megabytes).
"); + print("9) Memory Usage (emalloc): " . $mu_2 . " bytes (" . sprintf('%.06g', $mu_2 / 1024 / 1024) . " megabytes)
"); + print("10) Peak Memory Usage (Real): " . $mp_1 . " bytes (" . sprintf('%.06g', $mp_1 / 1024 / 1024) . " megabytes).
"); + print("11) Peak Memory Usage (emalloc): " . $mp_2 . " bytes (" . sprintf('%.06g', $mp_2 / 1024 / 1024) . " megabytes).
"); } + + print(''); + print(''); } function session(&$stuff) { @@ -249,8 +356,8 @@ $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()); + set_log_activity($database); + get_database_data($database, $stuff); if ($session->get_id_user()->get_value_exact() > 0) { $log = get_log_activity($database); @@ -298,7 +405,7 @@ $session->set_password($_POST['login_password']); $user_data = array(); - $account_exists = check_login_access($database, $_POST['login_name'], $_POST['login_password'], $session); + $account_exists = check_login_access($stuff, $database, $_POST['login_name'], $_POST['login_password'], $session); if (!$account_exists) { $user_id = 1; $session->set_name('public_user'); @@ -314,14 +421,13 @@ $connected = connect_database($database); if ($connected) { - set_log_user($database, 'login_failure', $_POST['login_name'], 403); + set_log_user($database, 'login_failure', $_POST['login_name'], NULL, 401); + set_log_activity($database, 401); $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 { @@ -349,16 +455,17 @@ $failure = TRUE; } else { - set_log_user($database, 'login'); - $result = $session->do_connect(); $failure = c_base_return::s_has_error($result); } - if (!$failure) { + // added '$user_id > 999' to ensure that anonymous and other system users do not generate a session cookie. + if (!$failure && $user_id > 999) { $result = $session->do_push(600, 1800); // (10 minutes, 30 minutes) $session->do_disconnect(); + set_log_user($database, 'login', NULL, $session->get_timeout_expire()->get_value_exact()); + $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); @@ -368,7 +475,7 @@ 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. + 'expire' => gmdate("D, d-M-Y H:i:s T", $session_expire), // unnecessary, but provided for debug purposes. ); $cookie->set_value($data); $stuff['cookie_login']['cookie'] = $cookie; @@ -391,8 +498,8 @@ ldap($stuff, $session->get_name()->get_value_exact()); } - set_log_activity($database, $user_id); - get_database_data($database, $stuff, $user_id); + set_log_activity($database); + get_database_data($database, $stuff); if ($session->get_id_user()->get_value_exact() > 0) { $log = get_log_activity($database); @@ -412,7 +519,6 @@ unset($table); } - unset($user_id); unset($user_data); } else { @@ -426,6 +532,7 @@ } } + unset($user_id); unset($session); } } @@ -464,7 +571,7 @@ #$stuff['login'] .= '
' . "\n"; } - function get_database_data(&$database, &$stuff, $user_id) { + function get_database_data(&$database, &$stuff) { $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) { @@ -482,12 +589,20 @@ unset($row); unset($row_number); } - $stuff['login'] .= '
' . "\n"; + else { + if (!isset($stuff['errors'])) { + $stuff['errors'] = ''; + } + $stuff['errors'] .= '
  • ' . $database->get_last_error()->get_value_exact() . '
  • '; + } + unset($query_result); + + $stuff['login'] .= '
    ' . "\n"; $stuff['login'] .= '
    ' . "\n"; } - function check_login_access(&$database, $username, $password, $session) { + function check_login_access(&$stuff, &$database, $username, $password, $session) { if ($username == 'public_user') return FALSE; $database->set_session($session); @@ -500,6 +615,23 @@ // it is possible the user name might not exist, so try to create it. $ensure_result = ensure_user_account($_POST['login_name']); + if (c_base_return::s_has_error($ensure_result)) { + $errors = $ensure_result->get_error(); + if (is_array($errors)) { + if (!isset($stuff['errors'])) { + $stuff['errors'] = ''; + } + + foreach ($errors as $error) { + if ($error instanceof c_base_error) { + $stuff['errors'] .= '
  • ' . $stuff['error_messages']::s_render_error_message($error)->get_value_exact() . '
  • '; + } + } + unset($error); + } + unset($errors); + } + unset($ensure_result); // try again now that the system has attempted to ensure the user account exists. $connected = connect_database($database); @@ -538,40 +670,43 @@ return TRUE; } - function set_log_user(&$database, $type, $user_name = NULL, $response_code = 200) { + function set_log_user(&$database, $type, $user_name = NULL, $expires = NULL, $response_code = 200) { + $extra_parameters = ''; + $extra_values = ''; + $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_string .= 'insert into v_log_users_self_insert (id_user, name_machine_user, log_title, log_type, log_severity, request_client, response_code, log_details)'; + $query_string .= ' values (coalesce((select id from v_users_self), 1), coalesce((select name_machine from v_users_self), \'unknown\'), $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)); + $query_parameters[3] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0'; + $query_parameters[4] = isset($_SERVER['REMOTE_PORT']) ? $_SERVER['REMOTE_PORT'] : 0; + $query_parameters[5] = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '' ; + $query_parameters[6] = $response_code; + + if ($type == 'login') { + $query_parameters[0] = "Logging in to the system."; + $query_parameters[1] = 17; + $query_parameters[2] = 1; + $query_parameters[7] = json_encode(array('expires' => $expires)); + } + elseif ($type == 'logout') { + $query_parameters[0] = "Logging out of the system."; + $query_parameters[1] = 18; + $query_parameters[2] = 1; + $query_parameters[7] = NULL; + } + elseif ($type == 'create') { + $query_parameters[0] = "Created the user account."; + $query_parameters[1] = 27; + $query_parameters[2] = 1; + $query_parameters[7] = NULL; + } + elseif ($type == 'login_failure') { + $query_parameters[0] = "Failed to login as the user '" . $user_name . "'."; + $query_parameters[1] = 17; + $query_parameters[2] = 2; + $query_parameters[7] = json_encode(array('user_name' => $user_name)); } else { return FALSE; @@ -583,10 +718,19 @@ unset($query_string); unset($query_parameters); + if ($query_result instanceof c_base_return_false) { + if (!isset($stuff['errors'])) { + $stuff['errors'] = ''; + } + + $stuff['errors'] .= '
  • ' . $database->get_last_error()->get_value_exact() . '
  • '; + } + unset($query_result); + return TRUE; } - function set_log_activity(&$database, $user_id, $response_code = 200) { + function set_log_activity(&$database, $response_code = 200) { $connected = connect_database($database); if (!isset($stuff['login'])) { @@ -601,28 +745,15 @@ } 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_string .= 'insert into v_log_activity_self_insert (id_user, name_machine_user, request_path, request_arguments, request_client, response_code) values (coalesce((select id from v_users_self), 1), coalesce((select name_machine from v_users_self), \'unknown\'), $1, $2, ($3, $4, $5), $6); '; $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); @@ -636,6 +767,15 @@ $query_result = $database->do_query($query_string, $query_parameters); unset($query_string); unset($query_parameters); + + if ($query_result instanceof c_base_return_false) { + if (!isset($stuff['errors'])) { + $stuff['errors'] = ''; + } + + $stuff['errors'] .= '
  • ' . $database->get_last_error()->get_value_exact() . '
  • '; + } + unset($query_result); } else { return FALSE; @@ -672,10 +812,26 @@ } } } + else { + if (!isset($stuff['errors'])) { + $stuff['errors'] = ''; + } + + $stuff['errors'] .= '
  • ' . htmlspecialchars($database->get_last_error()->get_value_exact(), ENT_HTML5 | ENT_NOQUOTES | ENT_DISALLOWED | ENT_SUBSTITUTE, 'UTF-8') . '
  • '; + } + unset($query_result); 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)'); + if ($query_result instanceof c_base_return_false) { + if (!isset($stuff['errors'])) { + $stuff['errors'] = ''; + } + + $stuff['errors'] .= '
  • ' . htmlspecialchars($database->get_last_error()->get_value_exact(), ENT_HTML5 | ENT_NOQUOTES | ENT_DISALLOWED | ENT_SUBSTITUTE, 'UTF-8') . '
  • '; + } + unset($query_result); } else { $email = explode('@', $ldap_data['mail']); @@ -687,8 +843,16 @@ $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); + if ($query_result instanceof c_base_return_false) { + if (!isset($stuff['errors'])) { + $stuff['errors'] = ''; + } + + $stuff['errors'] .= '
  • ' . htmlspecialchars($database->get_last_error()->get_value_exact(), ENT_HTML5 | ENT_NOQUOTES | ENT_DISALLOWED | ENT_SUBSTITUTE, 'UTF-8') . '
  • '; + } + unset($query_result); } $user_data['id_user'] = 1; @@ -710,6 +874,14 @@ } } } + else { + if (!isset($stuff['errors'])) { + $stuff['errors'] = ''; + } + + $stuff['errors'] .= '
  • ' . htmlspecialchars($database->get_last_error()->get_value_exact(), ENT_HTML5 | ENT_NOQUOTES | ENT_DISALLOWED | ENT_SUBSTITUTE, 'UTF-8') . '
  • '; + } + unset($query_result); } return $user_data; @@ -732,6 +904,14 @@ } } } + else { + if (!isset($stuff['errors'])) { + $stuff['errors'] = ''; + } + + $stuff['errors'] .= '
  • ' . htmlspecialchars($database->get_last_error()->get_value_exact(), ENT_HTML5 | ENT_NOQUOTES | ENT_DISALLOWED | ENT_SUBSTITUTE, 'UTF-8') . '
  • '; + } + unset($query_result); return $values; } @@ -753,6 +933,14 @@ } } } + else { + if (!isset($stuff['errors'])) { + $stuff['errors'] = ''; + } + + $stuff['errors'] .= '
  • ' . htmlspecialchars($database->get_last_error()->get_value_exact(), ENT_HTML5 | ENT_NOQUOTES | ENT_DISALLOWED | ENT_SUBSTITUTE, 'UTF-8') . '
  • '; + } + unset($query_result); return $values; } @@ -846,17 +1034,34 @@ $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; + $socket = @socket_create($socket_family, $socket_type, $socket_protocol); + if (!is_resource($socket)) { + unset($socket); + + $socket_error = @socket_last_error(); + + @socket_clear_error(); + + $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_create', ':socket_error' => $socket_error, ':socket_error_message' => @socket_strerror($socket_error), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::SOCKET_FAILURE); + unset($socket_error); + + return c_base_return_error::s_false($error); } - unset($socket); - $connected = socket_connect($socket, $socket_path, $socket_port); + $connected = @socket_connect($socket, $socket_path, $socket_port); if ($connected === FALSE) { - socket_close($socket); - return FALSE; + unset($connected); + + $socket_error = @socket_last_error($socket); + @socket_clear_error($socket); + + @socket_close($socket); + unset($socket); + + $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_connect', ':socket_error' => $socket_error, ':socket_error_message' => @socket_strerror($socket_error), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::SOCKET_FAILURE); + unset($socket_error); + + return c_base_return_error::s_false($error); } unset($connected); @@ -871,16 +1076,43 @@ $packet = pack('a' . $name_length, $user_name); } - $written = socket_write($socket, $packet, $packet_size_target); + $written = @socket_write($socket, $packet, $packet_size_target); if ($written === FALSE) { - socket_close($socket); - return FALSE; + unset($written); + + $socket_error = @socket_last_error($socket); + @socket_clear_error($socket); + + @socket_close($socket); + unset($socket); + + $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_write', ':socket_error' => $socket_error, ':socket_error_message' => @socket_strerror($socket_error), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::SOCKET_FAILURE); + unset($socket_error); + + return c_base_return_error::s_false($error); } unset($written); - $response = socket_read($socket, $packet_size_client); - socket_close($socket); + $response = @socket_read($socket, $packet_size_client); + if ($response === FALSE) { + unset($response); + + $socket_error = @socket_last_error($socket); + @socket_clear_error($socket); + + @socket_close($socket); + unset($socket); + + $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_read', ':socket_error' => $socket_error, ':socket_error_message' => @socket_strerror($socket_error), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::SOCKET_FAILURE); + unset($socket_error); + + return c_base_return_error::s_false($error); + } + @socket_close($socket); + unset($socket); + if (!is_string($response) || strlen($response) == 0) { + unset($response); return FALSE; } unset($response); @@ -902,7 +1134,7 @@ // 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; + return c_base_return_int::s_new($response_value); } function ldap(&$stuff, $username) { @@ -1110,13 +1342,8 @@ unset($agent_string); } - $stuff = array( - 'resources' => array( - 'time' => microtime(TRUE), - ), - ); - + process_received_headers($stuff); existence_cookie($stuff); session($stuff); - headers($stuff); + send_prepared_headers($stuff); theme($stuff); diff --git a/program/reservation/reservation_paths.php b/program/reservation/reservation_paths.php index aa7ba2c..b75ca78 100644 --- a/program/reservation/reservation_paths.php +++ b/program/reservation/reservation_paths.php @@ -260,7 +260,15 @@ function reservation_attempt_login(&$database, &$settings, &$session) { 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.'); + + $socket_error = $session->get_socket_error()->get_value(); + if ($socket_error instanceof c_base_return_int) { + $problem->set_value('Failed to load session, due to socket error (' . $socket_error . '): ' . @socket_strerror($socket_error) . '.'); + } + else { + $problem->set_value('Failed to load session.'); + } + unset($socket_error); $problems[] = $problem; unset($problem); @@ -297,6 +305,22 @@ function reservation_attempt_login(&$database, &$settings, &$session) { $session_expire = $session->get_timeout_expire()->get_value_exact(); $cookie_login = $session->get_cookie(); + if (c_base_return::s_has_error($pushed)) { + $problem = new c_base_form_problem(); + + $socket_error = $session->get_socket_error()->get_value(); + if ($socket_error instanceof c_base_return_int) { + $problem->set_value('Failed to push session, due to socket error (' . $socket_error . '): ' . @socket_strerror($socket_error) . '.'); + } + else { + $problem->set_value('Failed to push session.'); + } + unset($socket_error); + + $problems[] = $problem; + unset($problem); + } + if ($cookie_login instanceof c_base_cookie) { $cookie_login->set_expires($session_expire); $cookie_login->set_max_age(NULL); @@ -304,7 +328,7 @@ function reservation_attempt_login(&$database, &$settings, &$session) { 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. + 'expire' => gmdate("D, d-M-Y H:i:s T", $session_expire), // unnecessary, but provided for debug purposes. ); $cookie_login->set_value($data); diff --git a/program/reservation/reservation_session.php b/program/reservation/reservation_session.php index 083d112..386f0cf 100644 --- a/program/reservation/reservation_session.php +++ b/program/reservation/reservation_session.php @@ -153,22 +153,30 @@ return c_base_return_error::s_false($error); } - $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); - if ($socket === FALSE) { - socket_close($socket); + $socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + if (!is_resource($socket)) { unset($socket); - $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_create', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::OPERATION_FAILURE); + $this->socket_error = @socket_last_error(); + @socket_clear_error(); + + $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_create', ':socket_error' => $this->socket_error, ':socket_error_message' => @socket_strerror($this->socket_error), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::SOCKET_FAILURE); return c_base_return_error::s_false($error); } $connected = @socket_connect($socket, $settings['database_create_account_host'], $settings['database_create_account_port']); if ($connected === FALSE) { - socket_close($socket); + $socket_error = @socket_last_error($socket); + + @socket_close($socket); + @socket_clear_error(); + unset($socket); unset($connected); - $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_connect', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::OPERATION_FAILURE); + $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_connect', ':socket_error' => $socket_error, ':socket_error_message' => @socket_strerror($this->socket_error), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::SOCKET_FAILURE); + unset($socket_error); + return c_base_return_error::s_false($error); } @@ -186,7 +194,7 @@ $packet = pack('a' . $name_length, $user_name); } - $written = socket_write($socket, $packet, $packet_size_target); + $written = @socket_write($socket, $packet, $packet_size_target); unset($packet); unset($packet_size_target); @@ -194,18 +202,44 @@ unset($difference); if ($written === FALSE) { - socket_close($socket); unset($written); - unset($socket); unset($packet_size_client); - $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_write', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::OPERATION_FAILURE); + $socket_error = @socket_last_error($socket); + + @socket_close($socket); + @socket_clear_error(); + + unset($socket); + unset($connected); + + $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_write', ':socket_error' => $socket_error, ':socket_error_message' => @socket_strerror($this->socket_error), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::SOCKET_FAILURE); + unset($socket_error); + return c_base_return_error::s_false($error); } unset($written); $response = @socket_read($socket, $packet_size_client); - socket_close($socket); + if ($response === FALSE) { + unset($response); + unset($packet_size_client); + + $socket_error = @socket_last_error($socket); + + @socket_close($socket); + @socket_clear_error(); + + unset($socket); + unset($connected); + + $error = c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'socket_read', ':socket_error' => $socket_error, ':socket_error_message' => @socket_strerror($this->socket_error), ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::SOCKET_FAILURE); + unset($socket_error); + + return c_base_return_error::s_false($error); + } + + @socket_close($socket); unset($socket); unset($packet_size_client); -- 1.8.3.1